1. 책 내용 요약
15장 Junit 들여다보기
•
세상에 완벽한 코드는 없다
◦
의도를 명확하게 표현하기 위해 조건문을 메서드로 분리
◦
전후 단계가 있는 변수들 사이 시간적인 결합(hidden temporal coupling)을 해결하기 위해 리팩토링
◦
더 적절한 의미로 네이밍 변경
◦
불필요한 연산을 하는 코드 제거
16장 SerialDate 리팩토링
•
남의 코드를 비판하고, 내 코드의 비판을 듣는 건 편안하게 여겨야 할 활동이다.
2. 오픈 소스 접근법
MySQL, Apache, Tomcat 등과 같은 오픈 소스는 매뉴얼이나 문서, 책 등도 많이 나와 있으면 오픈 소스이지만 솔루션 자체도 안정적이라서 특별한 이유가 아니면 소스를 분석할 필요는 없습니다. 하지만 Hadoop이나 HBase 등과 같은 솔루션은 문서도 부족하지만 문서만으로 설명할 수 없는 복잡한 내용으로 구성되어 있는 솔루션이 많습니다. 따라서 제대로 솔루션을 사용하거나 운영하기 위해서는 소스 코드를 봐야 하는 경우가 많습니다. 최근에는 Presto, Zeppelin, Kafka 등을 사용하면서 필요한 기능을 추가하거나 설치, 운영 중 에러를 해결하기 위해 사용하는 오픈 소스의 코드를 분석하였습니다. 이때 사용되었던 제 나름대로 가지고 있는 오픈소스 코드 분석 방법에 대해 정리해 보았습니다.
해당 솔루션에 대한 기본 지식을 먼저 익혀라
하둡을 분석하려면 구글에서 발표한 논문을 읽어 봐야하고, HBase를 분석하기 위해서는 BigTable 논문을 읽어야 합니다. 분석하고자 하는 솔루션에 대한 이론적인 배경 지식이 없는 상태에서 소스 코드를 바로 보면 그냥 스파게티처럼 얽혀 있는 코드를 보고 있는 느낌이 듭니다.
복잡한 분산 컴퓨팅 환경에서 운영되는 솔루션인 경우 더욱 더 그 시스템의 기본 개념과 아키텍처를 이해하고 있어야 합니다.
본인 PC에 빌드 및 실행 환경을 구축하가
코드 분석을 빨리하기 위해서는 분석에 필요한 로그를 추가하여 재컴파일한 후 실행하면서 로그를 확인하는 것이 좋습니다. 단순 코드만 보면 특정 연산의 흐름이 어떻게 진행되고 있는지를 파악하기 어려운 경우가 많기 때문입니다. 실제로 필자가 가장 먼저 하는 부분이 바로 이 항목입니다.
최근의 오픈소스들은 분산 환경에서 운영되는 경우가 많은데 이 경우라 하더라도 개발자의 PC(가능하면 노트북)에 빌드와 실행 환경을 모두 구성하는 것이 좋습니다. “좋다” 라는 정도가 아니라 필수 사항이라 할 수 있습니다.
빌드 및 실행환경을 구성하는 것만으로도 코드 분석의 50%는 진행되었다고 할 수 있습니다.
수정, 실행, 확인 사이클을 짧게 만들어라
코드를 분석하기 위해서는 분석에 필요한 정보를 출력하는 코드나 확인을 위한 코드를 추가한 다음에 기능을 실행해서 확인해야 하는 경우가 많습니다. 이 경우 수정, 실행, 확인을 위한 시간이 길어지면 그만큼 효율이 떨어지게 되고 많은 시간이 소요됩니다.
몇 번 반복하다 보면 같은 작업 패턴을 찾게 되는데 이때에는 스크립트를 만들어서 반복 작업을 효율적으로 하는 것이 좋습니다.
자신에게 질문을 많이 하라
오픈 소스 개발자라고 해서 하늘에서 떨어진 개발자는 아닙니다. 대부분 비슷한 교육을 받고 비슷한 경험을 했습니다. 특정 기능에 대해서 “나라면 어떻게 개발했을까?” 라고 자신에게 질문을 던지고 머리속에 어떻게 구현할 것인지를 먼저 그려 봅니다.
처음에는 자신이 예측했던 부분이 많이 틀리겠지만 코드를 많이 보고 연습을 많이 하면 이것도 얼추 많이 맞추게 됩니다. 유사한 오픈 소스 그룹은 유사한 패턴으로 개발하기 때문입니다. 대표적인 오픈 소스 그룹이 Hadoop 및 그 패밀리(HBase, ZooKeeper, Hive 등)입니다.
분석하면서 문서로 정리하라
분석을 하면서 그림 또는 문서로 정리를하면 분석하는 그 시점에도 도움이 되지만 나중에도 도움이 됩니다. 문서는 굳이 UML이 아니더라도 ppt 같은 도구로 정리하면 됩니다(블로그도 좋음). 이렇게 중간 중간에 정리하면 머릿속에서만 빙빙 돌던 생각이 정리될 때가 많습니다. “분석이 다 된 다음에 깔끔하게 정리해야지”라는 생각이면 거의 정리는 못한다고 봐야 합니다. 나중에 정리하려면 정리도 어렵고 생각도 잘 나지 않습니다.
디버거 활용하기
•
Log Level을 DEBUG로 설정하라
배포되는 패키지는 대부분 Logger의 설정이 INFO 또는 WARN으로 설정된 경우가 많습니다. 더 많은 정보를 얻기 위해서는 logger의 레벨을 DEBUG로 설정합니다. DEBUG로 설정할 경우 너무 많은 로그 메시지가 나올 수 있는데 패키지 별로 서로 다른 수준의 LOG level을 설정하는 것이 좋습니다.
•
디버거의 breakpoint 기능을 활용하라
집중적으로 분석하고 싶은 구간은 디버거의 breakpoint 기능을 이용하여 step 단위로 실행하며 각 변수의 변화 상태를 확인하는 것이 좋습니다.
•
System.out.println() 보다는 Thread.dumpStack()을 활용하라
최근 오픈 소스는 리플렉션을 적극 활용하거나 DI 등을 이용하여 코드 그 자체만으로는 어떤 클래스가 실행중에 바인딩 되는지 찾기 어려운 경우가 많습니다. 그리고 해당 로직이 어떤 경로를 거쳐 호출되는지 찾기 어려운 경우가 많습니다. 이 경우 앞에서 설명한 디버거를 이용할 경우에도 어디에 breakpoint를 걸어야 할지 애매한 경우가 많은데 짐작 가는 부분에 Thread.dumpStack() 코드를 추가하면 전체 호출 흐름 및 실제 바인딩 되는 클래스를 확인할 수 있습니다.
코드의 일부를 통해 먼저 파악하기
•
당장 관심 있는 부분부터 집중적으로 파악하라
방대한 시스템의 경우 전체를 보다 보면 금방 지루하고 갈 곳을 잃어 버리는 경우가 많습니다. 당장 필요하거나 관심있는 부분부터 집중해서 보는 것이 좋습니다.
•
테스트 코드는 좋은 교본이 된다
좋은 오픈 소스는 좋은 테스트 코드를 가지고 있습니다. 테스트 코드는 실제 운영되는 기능이나 모듈의 동작을 테스트하기 위한 프로그램 코드이기 때문에 특정 기능을 수행하기 위해 어떤 클래스의 어떤 메소드가 호출되는지가 바로 나타나는 경우가 많습니다. 그리고 테스트 코드중 일부는 데몬을 실행하지 않고 바로 실행, 확인할 수 있는 코드가 많기 때문에 이런 테스트 코드와 breakpoint 등을 잘 조합하면 쉽고 빠르게 소스 코드를 분석할 수 있습니다.
•
그래도 어려우면 초기 버전을 다운로드 받아 분석하라
복잡해보이는 오픈 소스도 초창기 버전은 단순하게 기본 기능만 구현되어 있는 경우가 많습니다. 버전이 올라가면서 개발자들이 많이 참여하게 되고 코드는 점점 복잡해지고 기능도 많아지게 됩니다. 초창기 버전에서는 핵심 기능에만 집중하는 경우가 많기 때문에 핵심 기능을 분석하기에는 초창기 버전이 좋습니다.
3. Spring 프로젝트 접근법
Spring 프로젝트 접근법
1.
2.
패키지 구조를 살펴본다 - ex) 멀티 모듈 프로젝트?
3.
빌드 설정(build.gradle)을 보고, 어떤 dependency(모듈)을 사용하는지 살펴본다.
4.
config 패키지 하위에 어떤 설정들이 되어 있는지 확인한다.
a.
RedisConfig, KafkaProducerConfig, DataSourceConfig, CircuitBreakerConfig, CacheConfig
5.
controller 패키지 하위 코드를 보고 어떤 요청들을 처리하는지 감을 잡는다.
6.
service 패키지 하위를 보고 비즈니스 로직을 추측한다.
7.
데이터 구조를 알기 위해 resource 하위의 db 설정 파일을 보고 db에 접근해본다. schema.sql 파일이 있으면 DDL을 읽어본다.
8.
세부적인 비즈니스 로직을 확인할 때는 test 코드와 비교하며 이해한다.