AOP ( Aspect-Oriented Programming 관점 지향 프로그래밍) 는 IoC/DI, 서비스 추상화와 더불어 스프링의 3대 기반기술의 하나이다. 우리가 흔히 알고 있는 것중엔 @Transactional 이 대표적인 AOP의 예시이다. 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것이고, 이를 핵심적인 비즈니스 로직에서 분리하여 재사용하는 것이다. 

 

게시물을 등록하거나 댓글을 등록하는 기능이 있다고 생각해보자. 

 

그 등록 과정에서 항상 로깅을 하고, JPA에서의 트랜잭션기능을 이용한다면 같은 동작에 대한 반복되는 중복 코드가 들어가게 될 것이다. 이를 게시물 등록과, 댓글 등록이라는 핵심적인 관점에서 빼내와서, 부가적인 관점으로 모듈화해서 사용하면 중복 코드가 줄어들지 않을까? 

여기서 두 번 정도야 괜찮다고 생각할 수 있겠지만, 블로그를 만드는 데 DB에 CRUD 중 CUD에 대한 성공과 실패를 로깅을 하려한다면  그 중복 코드는 상당할 것이고 이를 모듈화해 분리하면 더 좋은 코드가 될 수 있지 않을까? 하는 것이다.

 

 

주요 개념들은 다음과 같다.

 

- Aspect여러 곳에서 쓰이는 코드를 모듈화한 것

- Target Aspect로 모듈화된 코드가 적용되는 곳

- Advice :  Aspect 에서 실질적인 기능에 대한 구현체 (로깅에 대한 apect면 어떻게 로그를 남길 것 인지에 대한 코드)

- Joint point :  Advice 가 Target 에 적용되는 시점. ( ex. 메서드 진입할 때, 생성자 호출할 때, 필드에서 값을 꺼낼 때 등)

- Point cut :  Joint point 의 상세 스펙을 정의한 것

- Weaving : 지정된 객체에 애스팩트를 적용해서 새로운 프록시 객체를 생성하는 과정

 

 

이를 구현하는 방법에는 세 가지가 있다고 볼 수 있고 그것들은 다음과 같다. 

 

  • AspectJ
  • CG Lib based proxy
  • JDK based Proxy 

가장 간단하게 적용가능한 것은 AspectJ를 이용하는 방법이고, 코드로 표현해보면 다음과 같다.

모듈화를 할 코드를 @Aspect라는 Annotation을 사용하는 방법(이를 사용하려면 커스텀 어노테이션을 생성이 필요하다.)이고, @Around 는 Joint Point와 연관 되어 있는 부분이다. 또한, Around 안에의 Annotation 은 point cut과 관련된 부분이다. 이는 아래서 더 다룰 것이다.

(또한 이를 사용하기 위해서는 @SpringBootApplcation 부분에 @EnableAspectJAutoProxy 를 추가해야한다. ) 

@Component
@Aspect
public class LoggingAdvice {

    @Around("@annotation(OperationLogging)")
    public Object logging(ProceedingJoinPoint pjp) throws Throwable {
     // pre proceed
     Object retVal = pjp.proceed();
     // After procced 
    }
}
@Override
@OperationLogging
public Order createOrder(Long memberId, String itemName, int itemPrice) {
  Member memeber = memberRepository.findById(memberId);
  int discountPrice = discountPolicy.discount(memeber,itemPrice);
  return new Order(memberId,itemPrice,itemPrice,discountPrice);
}

 

위에서 보았던 Around 말고는 또 다른 어떤 것들이 있을까?

 

 - Around  : 타겟의 메서드가 호출되기 이전(before) 시점과 이후 (after) 시점에 모두 처리해야 할 필요가 잇는

부가기능을 정의한다.

 

 - Before :  타겟의 메서드가 실행되기 이전(before) 시점에 처리해야 할 필요가 있는 부가기능을 정의한다.

 

 - After Returning :  타겟의 메서드가 정상적으로 실행된 이후(after) 시점에 처리해야 할 필요가 있는 부가기능을 정의한다.

 

 - After Throwing : 타겟의 메서드가 예외를 발생된 이후(after) 시점에 처리해야 할 필요가 있는 부가기능을 정의한다.

 

 또 Annotation 말고 또 어떤 것이 있을까?  execution, within, bean, args, this, target 등이 있지만,  주로 사용하는 execution만 보면 다음과 같다.

 

@execution  : execution([수식어] 리턴타입 [클래스이름].이름(파라미터)

 

    -  수식어 : public, private 등 수식어를 명시 (생략 가능)

    -  Return 타입 : Return 타입을 명시

    -  클래스 이름 및 매서드 이름 : 클래스이름과 메서드 이름을 명시.

    -  파라미터 : 메서드의 파라미터를 명시

 

최근에 관련 기술을 이용해서 코딩을 했을 때는 Annotation 을 이용했고, 이때의 장점은 특정 파라미터를 전달이 가능하다는 것이다. 

@Aspect
@Component
public class LoggingAdvice { 
  @Around("@annotation(OperationLogging) && @ annotation(target)")
  public Object customAnnoTest(ProceedingJoinPoint joinPoint, TargetAnno target) throws Throwable {
    System.out.println("command : " + target.command());
    Object proceed = joinPoint.proceed();
    return proceed;
  }
}
@Override
@OperationLogging (command = "create")
public Order createOrder(Long memberId, String itemName, int itemPrice) {
  Member memeber = memberRepository.findById(memberId);
  int discountPrice = discountPolicy.discount(memeber,itemPrice);
  return new Order(memberId,itemPrice,itemPrice,discountPrice);
}

 

이번 주에 사용하기 위해서 AOP에 대해서 꽤 많은 공부를 하였음에도 이를 알고 있는 것과, 잘 정리하는 것은 꽤 다른 일이라는 생각을 하였다. 더 잘 정리할 수 있게 공부하면서 조금씩 요약하여 기록해두는 습관을 들여야 할 것 같다. 

마이크로 서비스의 통합은 어떻게 말하면 느슨한 결합의 분리를 의미한다. 하나의 마이크로 서비스가 다른 마이크로 서비스와 통신하는 방법

에 대한 여러가지 방법에 대해서 공부하려 한다.

 

- 공유 데이터베이스 

 

가장 단순하지만 마이크로 서비스 아키텍쳐가 추구하는 방법이 아니다. 강한 응집력과 느슨한 결합력을 잃게 되는 것만으로 피해야하는 통합
(통신) 방법이다.

 

- 오케스트레이션과 코레오그래피

 

오케스트레이션 방식은 지휘자처럼 프로세스를 안내하고, 구동하는 하나의 Master에 의존한다. 반면 코레오 그래피 방식은 발레 무용수들이 자신의 역할을 알고 주변의 다른 무용수에 반응하는 것처럼 시스템 각 부분에 작업 내용을 알리고 세부 사항을 수행하게 한다.

 중앙 관리 권한에 많은 권한이 있는 것 오케스트레이션 방식에 대비해서 이벤트를 발산하고, 그것을 체크하여 수행하는 방식인 코레오 그래피 방식은 느슨한 결합을 이끌어낸다. (이때 일이 제대로 수행되는지 모니터하고 추적하기 위한 추가 작업이 필요하다.)

 

- 원격 프로시저 호출 (Repote Procedure Call) RPC

 

 마이크로 서비스의 경우 다양한 언어와 프레임워크로 개발 될 수 있기 때문에, 프로토콜을 맞춰서 통신해야 하는 비용이 발생한다. 이럴 때 RPC를 이용하여 언어에 구애받지 않고, 원격에 있는 프로시저를 호출하여 비즈니스 로직에 집중할 수 있게 된다.

 

- REST 

 

 클라이언트가 요청/응답 통신을 사용하는 경우 요청을 서비스에 보낸 다음, 서비스가 요청을 처리하고 다시 응답을 보낸다. 요청/응답 통신은 특히 클라이언트 앱에서 실시간 UI(라이브 사용자 인터페이스)에 대한 데이터를 쿼리하는 데 적합.

 

-  버전관리의 가장 좋은 방법은 애초에 결함을 만들어내지 않는 것 

 

 관심 없는 데이터의 변경들을 무시할 수 있도록 독자를 구현하는 것 (관대한 독자 패턴)

 '전송할 때는 보수적으로, 받아들일 때는 자유롭게' (포스텔 법치)

 

 버전관리시의 하위 호환성이 깨지는 경우와 아닌 경우를 알 수 없을까? -> 유의적 버전 관리 (Major.Minor.Patch) 

 

 

전체적으로 여러가지 통신 방법들이 있고, 이것들로 각 마이크로 서비스를 어떻게 통합할 것이고, 문제를 해결할 것인지에 대한 고민들이 있는 부분인 것 같다. 책의 내용을 요약하는 것보다 내 것으로 만들어서 그에 대한 생각을 정리하고 싶었지만 굉장히 많은 내용을 다루고 있어 그런 부분이 어려웠고 각 기술들에 대해서 깊게 공부하는 시간을 가져야겠다는 생각을 하게 했다.  (gRPC, 메시지 큐 등에 대한 정리도 추가로 할 시간을 만들어보아야 겠다. )

 

 

이는 마이크로서비스 아키텍처 구축을 공부하면서 생각을 정리한 것입니다.. 관련된 내용에 대해서 더 알고 싶은 경우에는 해당 책을 보는 것을 권유합니다.

 

마이크로서비스 아키텍처 구축

마이크로서비스, 웹 기반 분산 시스템의 디자인 패러다임을 바꾸다!

www.hanbit.co.kr

 

 

'개발자로 살아남기 > Micro Service Architecture' 카테고리의 다른 글

3. 서비스 모델링하기  (0) 2021.04.11
2.진화적 아키텍트  (0) 2021.04.11
1. 마이크로 서비스  (0) 2021.04.11

좋은 마이크로 서비스를 구성하기 위해서는 느슨한 결합과 강한 응집력에 대한 고민은 필수적이다.

 

느슨한 결합이 잘 되어 있으면 하나의 서비스를 변경했을 때 다른 서비스는 변경이 되지 않으며, 이를 통해서 다른 변경없이 특정 서비스를 변경하고 배포할 수 있다. 강한 응집력이 잘되어 있으면 특정 행위에 대한 변경이 한 곳에서 이루어지는 것이다. 이는 같은 행위가 여러 곳에 분산되면 한 행위의 수정을 위해 여러 서비스를 변경 배포해야하는 문제가 발생하게 된다. "느슨한 결합" 그리고 "강한 응집력" 이 두 가지를 지키지 않으면 마이크로 서비스의 큰 장점을 잃을 수 있기 때문에 이를 효과적으로 컨트롤할 수 잇는 방법을 찾아야 한다.

 

특정 모델에 대해 경계가 정해진 적용 가능성, 콘텍스트를 제한한느 것은 팀원들로 하여금 무엇에 대해 일관성을 유지하고, 무엇을 독립적으로 개발할 수 있는 지 명확하게 공유할 수 있게 하는 것을 "경계가 있는 콘텍스트" 라고 한다. 각 콘텍스트 내에는 외부와 통신할 필요가 없는 것과 다른 외부로 통신하는 것이 함께 존재하고, 명백한 인터페이스로 어떤 모델이 다른 콘테스트와 공유될지를 결정한다.

 

 어떤 모델을 공유하고, 어떤 모델을 공유하지 않는 지를 명확하게 고려하게 되면 우리가 피해야 할 강한 경합 (우리는 느슨한 결합을 하고 싶다.)을 피할 수 있게 된다. 또한, 서로 조화를 이루는 비지니스들이 존재하는 도메인 내부의 경계를 설정함으로 높은 응집력을 이룰 수 있다. 이렇게 관련된 기능을 모으고, 내외부의 공유를 설정하는 작업을 통해서 모듈화를 이루고, 이를 모델링하게 되면 이는 마이크로 서비스의 후보가 될 수 있다. ( 애플리케이션의 관점에서 각 기능에 대해서 관련된 것들을 구역화하고, 이들의 모델의 내부와 외부에 대한 인터페이스를 설정하게 되면 그 구역화를 기점으로 마이크로 서비스를 이룰 수 있는 것을 의미하는 것이다.)

 

이러한 마이크로 서비스를 이룰 때 고려해야할 점 중 하나는 조직 구조와의 관계성에 대한 고민이다. 각 작은 서비스에 대해서 한 팀에서 다루면 큰덩어리의 한 묶음으로 관리하여 테스팅 단순화를 도모할 수 있고, 각 작은 서비스가 다른 팀이 하게 되면 최상위 계층의 마이크로 서비스가 될 수 있다. 

 

모놀리식 시스템을 어떻게 하면 구역화하고 어떻게 마이크로 서비스들의 묶음으로 수정할 수 있을 지에 대한 고민을 하게 되는 것 같다. 무엇보다 중요한 쟁점은 마이크로 서비스의 장점을 살리고, 그것을 이용하는 방법에 달린 것 같다. 더 고민해봐야할 것들이다.  

 

이는 마이크로서비스 아키텍처 구축을 공부하면서 생각을 정리한 것입니다.. 관련된 내용에 대해서 더 알고 싶은 경우에는 해당 책을 보는 것을 권유합니다.

 

마이크로서비스 아키텍처 구축

마이크로서비스, 웹 기반 분산 시스템의 디자인 패러다임을 바꾸다!

www.hanbit.co.kr

 

'개발자로 살아남기 > Micro Service Architecture' 카테고리의 다른 글

4. 통합  (0) 2021.04.25
2.진화적 아키텍트  (0) 2021.04.11
1. 마이크로 서비스  (0) 2021.04.11

아키텍트는 건축가보다는 도시 설계자에 가까운 의미로 접근해야한다고 한다.

 

나무를 보지 말고, 숲을 보라는 의미인건가? 나는 개발자로서 마이크로 서비스 아키텍쳐를 이해하려고 이 책을 봐서 그런지 아직 아키텍트라가 어떤 일을 하는지에 대한 감이 오지 않았다.

 

아키텍트는 앞서 생각했던 각기 다른 기술로 서비스를 할 경우에 발생하는 조직 내부의 문제 등을 최소화하기 위해서 일련의 규칙을 정하고, 올바른 방향으로 나아가도록 방향을 제시하는 것으로 시작되는 것이라고 생각한다. 이를 기반으로 큰 틀을 정하고, 각 서비스에 자율성을 부여하며 그것들이 하나의 응집력 있는 애플리케이션을 이루도록 하는 것.

 

이러기 위해서는 시스템의 상태를 일관되게 살펴볼 수 있어야 하고, 인터페이스 기술의 표준을 최소화 해야하며, 오동작에 대해 방어할 수 있는 시스템을 만들어야한다. 

 

또한, 개발자들이 약간의 노력으로 이런 지침들을 따를 수 있게 하는 것 또한 아키텍트의 능력이다. 그 방법으로는 본보기나 서비스 템플릿을 제공하는 것이다. 서비스 템플릿을 제공하는 경우에 개발자들로 하여금 잘못된 코딩을 줄여 시간을 단축할 수 있지만, 자칫 잘못하면 프로그래밍 언어의 선택을 제한할 수 있다. 

 

추가로 아키텍트의 담당 업무 중 하나는 거버넌스 (Governance)이다. 이는 "기업의 목적이 이해관계자의 요구, 조건, 섡택을 평가함으로써 달성될 수 잇음을 보장한다. 우선순위 및 의사 결정을 통해 방향을 설정하고, 합의된 방향과 목표에 대한 성과, 규칙 준수, 과정을 모니터링한다. "

 

 이렇게 본 아키텍트는 기술 적용과 규칙을 정했을 때 발생하는 트레이드 오프를 올바르게 결정하기 위해 끊임없는 고민을 해야하는 것 같다. 그 고민들의 결과물이 더 나은 서비스, 그리고 개발자들이 물 만난 물고기처럼 헤엄 칠 수 있는 환경을 제공하는 것이 아닐까? 

 

 

 

이는 마이크로서비스 아키텍처 구축을 공부하면서 생각을 정리한 것입니다.. 관련된 내용에 대해서 더 알고 싶은 경우에는 해당 책을 보는 것을 권유합니다.

 

마이크로서비스 아키텍처 구축

마이크로서비스, 웹 기반 분산 시스템의 디자인 패러다임을 바꾸다!

www.hanbit.co.kr

 

 

 

'개발자로 살아남기 > Micro Service Architecture' 카테고리의 다른 글

4. 통합  (0) 2021.04.25
3. 서비스 모델링하기  (0) 2021.04.11
1. 마이크로 서비스  (0) 2021.04.11

마이크로 서비스는 Mirco Service, 초소형 서비스를 말한다. 한 가지 앱에서 지원해야 할 서비스가 많아지면 당연하게 그 크기느 커질 수 있겠지만 마이크로 서비스 아키텍쳐는 그것들을 많이 세분화하여 작은 서비스의 여러개의 묶음으로 표현하려는 것이다. 처음에는 이것에 대해서 그럴 수 있고, 간단하다는 생각을 하였는데, 이것이 생각보다 약속할 것도 많고 설계시에 까다로운 부분들이 존재하다는 것을 알 수 있었다.

 

 분리된 각 서비스는 자율성을 가질 수 있다. 그렇기에 각 서비스마다 다른 기술을 적응시킬 수 있다. 이는 서비스 끼리의 의사소통은 네트워크 호출로 이루어지기 때문에 가능하다. " 각 서비스는 독립적이고 자율성을 가지며 다른 서비스와는 네트워크로만 통신한다. "라고 보았을 때 중복 코드가 무수히 많아질 것이라는 생각도 따라온다. 또한, 네트워크 통신에 대한 규칙에 얽메일 수 있고 주고 받는 데이터가 바뀔 때 독립성이 모호해지는 것이 아닌가 하는 생각에도 빠진다. 이는 어쩌면 끊임 없이 '다른 변경 없이 특정 서비스만을 변경하고 배포하는가?' 에 대해서 고민해야하는 방법이다.

 

 그렇기에 마이크로 서비스는 초기 설계와 개발하면서 진행 될 수 많은 토론과 회의 그리고 고민이 필요하다는 생각으로 연결 되었다. 자연스럽게 이런 노력과 시간이 의미가 있는 방법론인가? 생각하였고, 내가 일하면서 불편했던 것들의 단점들을 보완한다는 결론에 이르렀다.

 

 첫 번째는 매우 작은 서비스들로 세분화 되었기 때문에 몇몇 부분에서는 새로운 기술을 도입하려고 해도 리스크가 적다는 것이다. 문제를 해결하려고 할 때 이를 해결 할 수 있는 기술이나 방법을 찾아본 적이 있을 것이다. 하지만 모놀리식 서비스로 구성되었을 경우에는 새로운 기술에 대한 리스크에 고민과 고민의 수 많은 연결고리에서 현재 적용된 시스템에 영향을 미치지 않는 방법을 찾기 위한 시간을 보내야 했다. 하지만 세분화된 마이크로 서비스에서는 이러한 리스크가 작아지는 것을 느낄 수 있을 것이다.

 

두 번째는 독립성을 가지고 세분화된 마이크로 서비스는 배포에서도 큰 장점을 가질 수 있다. 모놀리그식 서비스로 구성된 것의 경우 작은 수정에도 전체 애플리케이션을 배포해야하는 번거로움이 있다. 하지만 마이크로 서비스의 경우 해당 서비스에 대한 배포만 하면 된다. 신속하고 빠르게 배포하고 더 자주 배포할 수 있을 것이다.

 

다른 장점들이 있지만 기존의 모놀리그 식에서 느꼈던 단점을 보완하는 이 두가지의 장점이 내게 와닿았다. (이는 아직 마이크로 서비스에 대한 학습과 이해가 부족해서 일 수 있다.)

 

마이크로 서비스에 대해서 잠깐 보았을 때 느껴진 것은 장점이 많지만 이는 모든 것의 만능열쇠는 아니라는 것 그리고, 세분화를 할 때 생각해야하는 수 많은 고리들에 대한 깊은 고민을 해야하는 것이다. 

 

어떻게 하면 이런 장점을 극대화시키면서 서비스를 구축할 수 있을지 고민해봐야겠다.

 

 

 

이는 마이크로서비스 아키텍처 구축을 책을 통해 공부하면서 생각을 정리한 것입니다. 관련된 내용에 대해서 더 알고 싶은 경우에는 해당 책을 보는 것을 권유합니다.

 

마이크로서비스 아키텍처 구축

마이크로서비스, 웹 기반 분산 시스템의 디자인 패러다임을 바꾸다!

www.hanbit.co.kr

 

'개발자로 살아남기 > Micro Service Architecture' 카테고리의 다른 글

4. 통합  (0) 2021.04.25
3. 서비스 모델링하기  (0) 2021.04.11
2.진화적 아키텍트  (0) 2021.04.11

https://finance.naver.com/

네이버 증권 사이트에 들어가서 검색하는 곳의 소스를 잠깐 보면 다음과 같다.

 

이것을 이용할까? 고민해보았는데

 

웹 주소상의 종목코드를 이용한 접근이 더 편할것으로 보인다.  (https://finance.naver.com/item/main.nhn?code=011070)

 

이제 각 주식별로의 위치까지는 들어가는 것까진 할 수 있다.

 

더나아가면 https://m.stock.naver.com/item/main.nhn#/stocks/005930/notice

 

해당 것을 이용해서, 각 기업에 "공시" 탭까지 들어갈 수 있다.

 

그렇다면? 탭에 들어가서 "배당" 을 검색하여 나온 리스트를 가지고 "언제" 그리고 "얼마" 를 주는지 알아내고 싶어진다.

(가능할까?ㅠㅠ)

 

https://m.stock.naver.com/item/main.nhn#/stocks/005930/notice

의 소스를 검색해보니 이런식으로 구성되어 있는 것을 알 수 있다. 이중에서 일단 "배당"이라는 글자가 들어가는 것을 알아보자

 

 

사용하려고 하는 것은 Beautiful soup 과 request 라이브러리이다.

 

stock_result = requests.get("https://m.stock.naver.com/item/main.nhn#/stocks/005930/notice")

stok_list = BeautifulSoup(stock_result.text, "html.parser")

title_list = stok_list.find("div",{"class":"lst_wrp_contents"})

 

이렇게 해보면.. 

 

결과는?? "NONE"

 

막힌건가

 

그렇다면 다른 방법을 알아봐야지.. 

 

다트 전자공시의 API를 활용해볼까한다.. ㅠㅠ 

 

이거 안되면 "언제" 를 빼고 배당금만 가져오는 방법을 생각해봐야겠다. 

최소한 의 지렁이로, 최대한 많은 효율을 내고 싶은 문제이다.

지렁이들이 "연결"된 곳을 다닐 수 있다

나는 여기서 해당 문제는 DFS 와 BFS를 이용할 수 있을 거라고 생각 했다.

1 1 0 0 0 1 1
1 0 0 0 0 1 1
0 0 0 0 0 0 0
1 1 1 0 0 0 0

이렇게 색칠한 음영별로 깊이있게 탐색을 하든, 넓게 탐색을 하든 다 찾아내면되는 것이다.

 

DFS 코드로 나타내면 이렇다.

 

#include<iostream>
using namespace std;

int map[50][50];
int n, m,k;

int direct[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};

void dfs(int i, int j)
{
    map[i][j] = 0;
    for(int k=0;k<4;k++)
    {
        int x = i+direct[k][0];
        int y = j+direct[k][1];
        if(x>= 0 && x < m && y >=0 && y <n)
        {
            if(map[x][y] == 1)
            {
                dfs(x,y);
            }
        }
    }
}

int main() {
    int tnum;
    cin >> tnum;

    for(int tcase = 0; tcase<tnum;tcase++)
    {
	    int result=0;
        cin >> m >> n>>k;

        for (int i = 0; i < k; i++)
        {
            int t1, t2;
            cin >> t1 >> t2;
            map[t1][t2] = 1;
        }

        for (int i = 0; i <m; i++)
        {
            for(int j=0;j<n;j++)
            {
                if(map[i][j]==1)
                {
                    dfs(i,j);
                    result++;
                }
            }
        }
        cout << result << "\n";

    }
	

}

 

BFS 코드는 다음과 같다.

 

#include<iostream>
#include <queue>
using namespace std;

int map[50][50];
int n, m,k;

struct point
{
    int x;
    int y;
};
queue<point> q;

void bfs(int i, int j)
{
    if(map[i][j]==0) return;
    map[i][j] = 0;

    for(int k=0;k<4;k++)
    {
        int x = i+direct[k][0];
        int y = j+direct[k][1];
        if(x>= 0 && x < m && y >=0 && y <n)
        {
            if(map[x][y] == 1)
            {
                point p ;
                p.x = x;
                p.y = y;
                q.push(p);
            }
        }
    }
}
int main() {
    int tnum;
    cin >> tnum;

    for(int tcase = 0; tcase<tnum;tcase++)
    {
	    int result=0;
        cin >> m >> n>>k;

        for (int i = 0; i < k; i++)
        {
            int t1, t2;
            cin >> t1 >> t2;
            map[t1][t2] = 1;
        }

        for (int i = 0; i <m; i++)
        {
            for(int j=0;j<n;j++)
            {
                if(map[i][j]==1)
                {
                    point p;
                    p.x = i;
                    p.y = j;

                    q.push(p);
                    while(!q.empty())
                    {
                        int t1,t2;
                        p = q.front();
                        t1 = p.x;
                        t2 = p.y;
                        q.pop();

                        bfs(t1,t2);
                    }
                    result++;
                }
            }
        }
        cout << result << "\n";

    }
	

}

 

나는 이런 문제에 대해서는 DFS가 상대적으로 직관적이고 좋은 것 같다. 

 

https://www.acmicpc.net/problem/1012

 

1012번: 유기농 배추

차세대 영농인 한나는 강원도 고랭지에서 유기농 배추를 재배하기로 하였다. 농약을 쓰지 않고 배추를 재배하려면 배추를 해충으로부터 보호하는 것이 중요하기 때문에, 한나는 해충 방지에 효과적인 배추흰지렁이를 구입하기로 결심한다. 이 지렁이는 배추근처에 서식하며 해충을 잡아 먹음으로써 배추를 보호한다. 특히, 어떤 배추에 배추흰지렁이가 한 마리라도 살고 있으면 이 지렁이는 인접한 다른 배추로 이동할 수 있어, 그 배추들 역시 해충으로부터 보호받을 수 있다. (

www.acmicpc.net

 

 

Creon API를 이용하여 주식 종목 코드를 가져오려고 한다.

 

API는 예전에 블로그에 정리한 것을 참고해주세요.

https://songveloper.tistory.com/15?category=688936

 

[Creon API] 종목 코드를 이용하여 여러 정보 가져오기

Creon API 에서 MarketEye 를 이용해서 종목 코드만 있으면 다음과 같은 정보들을 가져올 수 있다. http://money2.creontrade.com/e5/mboard/ptype_basic/HTS_Plus_Helper/DW_Basic_Read_Page.aspx?boardseq=284&s..

songveloper.tistory.com

https://songveloper.tistory.com/12

 

Creon API로 connect

맨날 공부한다고 생각만하고 있어서 그런지 상당히 더디게 프로젝트가 진행되고 있다. 처음에는 python 공부를 목적으로 하였지만.. 그것보단 내가 어떤 주식을 사야할지, 데이터 접근하여 값을 가져오는 용도로..

songveloper.tistory.com

위의 공부한 것을 바탕으로 내가 쓰기 좋게 Creon AP를 구성하고 구현한 것은 다음과 같다.

연결을 확인하고, 내가 원하는 Stock 리스트를 가져오는 그런 코드입니다.

 

import time

import win32com.client

import pandas as pd

from pandas import DataFrame

import copy

 

class Creon:

def __init__(self):

self.obj_CpCodeMgr = win32com.client.Dispatch('CpUtil.CpCodeMgr')

self.obj_CpCybos = win32com.client.Dispatch('CpUtil.CpCybos')

self.obj_StockChart = win32com.client.Dispatch('CpSysDib.StockChart')

 

def creonConnectCheck(self):

b_connected = self.obj_CpCybos.IsConnect

if b_connected == 0:

print("connect fail")

return False

else :

return True

 

def setAllStockList(self):

# ## 대신 api 세팅

obj = win32com.client.Dispatch("CpUtil.CpStockCode")

numData = obj.GetCount()

data = []

self.numTotalCount = 0

for index in range(numData):

tempData = []

tempData.append(obj.GetData(0, index))

if self.obj_CpCodeMgr.GetStockMarketKind(tempData[0]) == 1 or self.obj_CpCodeMgr.GetStockMarketKind(tempData[0]) == 2:

data.append(tempData)

 

return data;

 

def dataSlice(self,stockList):

refinedStockList = []

stockCount = len(stockList);

listRowCount = int(stockCount/200) + 1 #we just we 200 stock.. , so we need to slice the data.

for i in range(listRowCount):

tempList = [] # 안쪽 리스트로 사용할 빈 리스트 생성

for j in range(200):

numOfList = i*200 + j

if stockCount <= numOfList :

break

tempList.append(stockList[numOfList]) # 안쪽 리스트에 0 추가

refinedStockList.append(tempList)

return refinedStockList

 

def subMarketSingArray(self, codeList, mInfoList):

numCodeRow =len(codeList)

print(numCodeRow)

obj = win32com.client.Dispatch("cpsysdib.MarketEye")

 

obj.SetInputValue(0, mInfoList)

obj.SetInputValue(1, codeList)

obj.BlockRequest()

numField = obj.GetHeaderValue(0)

numData = obj.GetHeaderValue(2)

data=[]

 

for idx_x in range(numData):

tempdata=[]

for idx_y in range(numField):

tempdata.append(obj.GetDataValue(idx_y, idx_x))

data.append(tempdata)

 

return data

 

def subMarketEye(self, codeList, mInfoList):

numCodeRow =len(codeList)

print(numCodeRow)

obj = win32com.client.Dispatch("cpsysdib.MarketEye")

 

data=[]

for index in range(numCodeRow):

obj.SetInputValue(0, mInfoList)

obj.SetInputValue(1, codeList[index])

obj.BlockRequest()

numField = obj.GetHeaderValue(0)

numData = obj.GetHeaderValue(2)

 

for idx_x in range(numData):

tempdata=[]

for idx_y in range(numField):

tempdata.append(obj.GetDataValue(idx_y, idx_x))

data.append(tempdata)

 

return data

 



 

 

그 다음에 오늘은 배당금을 가져오고 싶었으나 관련 API 를 찾지 못해서 해당 API를 이용하여

종목명, 그리고 종목 코드를 가져오는 것을 구현

import time

import pandas as pd

from pandas import DataFrame

import CreonApi

import copy



class DividStock(object) :

 

def __init__(self, stockCode, price, stockName,dividend):

print("divide")

self.stockCode = stockCode

self.price = price

self.stockName = stockName

self.dividend =dividend;

 

def printStock(self):

result = []

result.append(self.stockCode)

result.append(self.price)

result.append(self.stockName)

result.append(self.dividend)

return result

 

class DivideStrategy():

 

creon = CreonApi.Creon()

codeinformList = [0,17]

stockList = []

# 0 종목코드, 4 현재가, 17 종목명, 20 : 총 상장주식수, 74 배당률, 75 부채비율, 77 ROA, 80 순이익증가율

# 89 BPS, 91 영업이익 95 결산연월, 102 분기영업이익,107 분기 ROE, 111 결산연월 123 SPS 124 CFPS

 

def refinedStock(self, inputdata):

data = []

lenofdata = len(inputdata)

for index in range(lenofdata):

tempdata = copy.deepcopy(inputdata[index])

tempStock = DividStock(tempdata[0],tempdata[1],tempdata[2])

self.stockList.append(tempStock)

 

def saveDataStockList(self):

lenofdata = len(self.stockList)

result = []

for index in range(lenofdata):

result.append(self.stockList[index].printStock())

df = DataFrame(result,columns=['종목코드', '종목명'])

df.to_csv('StockList.csv')

 

def dividStrategy(self):

if self.creon.creonConnectCheck() == True:

print("start")

tempdata = self.creon.setAllStockList()

sliceData = self.creon.dataSlice(tempdata)

print("refinde")

self.refinedStock(self.creon.subMarketEye(sliceData, self.codeinformList))

print("saved")

self.saveDataStockList()

print("end")

else:

print("bye!")



def DivideStockList():

divideStcok = DivideStrategy()

divideStcok.dividStrategy()

 

DivideStockList()



 

이것으로 가져온 리스트를 활용해서 내가 가진 주식의 배당금을 직전 년도 배당을 통해 알아보고,

내년에 나는 얼마의 배당을 받을 수 있을지 예측하는 프로그램을 만들어볼까합니다.

 

 

 

+ Recent posts