Code Organization Guidelines for Large Code Bases – 유겐 휄러

왜 코드 조직화를 걱정하는가?
패키지 interdependencies
모듈 나누기와 레이어링
커다란 코드 기반 진화시키기
케이스: 스프링 진화
아키텍처 분석 도구

왜 코드 조직화를 걱정하는가?
– 전체 코드 이해를 돕고, 보다 편하게 네비게이션 하기 위해서.
– 자바에는 패키지와 서브 패키지 개념을 제공하긴 하지만, 어떻게 적용해야 할지에 대한 권고 같은건 없다.

신경써야 할 것들
– 코드는 원래 구조에서 계속 진화할 필요가 있다.
– 리팩터링과 애자일 개발은 좋다. 근데 그렇게 개발하면서도 이전에 배포한 코드와의 호환성은 어떻게 유지할 것인가..
– 원래 설계에서 의도하지 않았던 의존성들이 모듈을 나누다 보면 생길 수 있다.
– (점점 커지나까) API를 유지하면서 모듈을 좀 더 세밀한 모듈로 조갤 수 있을런지..

패키지 상호의존성
– 패키지 구조를 설계하는 건 놀랍도록 중요하다.

왜 단방향 의존성이 중요한가?
– 즉, 왜 순환 참조(CD)가 안 좋을까?
– 코드를 악화 시킨다,.
– 패키지 재사용에 제한이 생긴다.
– B를 사용하려면 A를 컴파일 해야 하는데 A는 다시 B를 컴파일 해야 하는 상황 발생한다.

그러니까
– CD를 없애라.
– 패키지들을 개념적인 모듈로 묶어라.
– 모듈을 만들어 낼 땐 개념적인 경계와 더불어 배포도 고려해야 한다.

모듈 decomposition과 레이어링
– 모듈의 특성(다른 모듈과 낮은 종속성, 모듈내에선 높은 결집도)
– 모듈은 소스 관리와 배포 단위 만듬이나 개념적인 단위다.
  – cognitive 오버로드를 피하라.
  – 개별적으로 사용 할 수 있어야 한다.(전체 시스템의 일부 기능)
– 모듈 간에 CD를 가지고 있으면 안 된다.
– 모듈 간에 의존성들은 그들이 가지고 있는 패키지에 의해 만들어진다.
– 레이어링은 패키지 구조에 있어서 중요한 논리 뷰다. 상위 계층에서 하위 계층을 참조하고 그 반대로는 안 되도록..
– 모듈 레이러링 보다는 개발 consideration에 의해 도출 된다.

그러니까
– 코드 베이스 내에서 자연스러운 개념적인 경계를 만들어라.
  – 자연스러운 패키지 네이밍
  – 편한 네비게이션
– 가장 힘든 도전은 코드를 진화시키는 거다.
  – code deteriorate를 놓치지 않고..
  – 아키텍처 질을 떨어뜨리지 않고..
– 하위 호환성과 아키텍처 품질 사이의 트레이드오프를 생각해야 한다.
  – 완전 100% 하위 호환성은 보장할 수가 없게 된다.
  – 물론 가끔 아키텍쳐 품질을 양보하지 않아도 되는 방법이 항상 있을 수 있음을 생각해야 한다.
– 물론 몇 가지는 쉽게 바꾸기가 힘들 것이다.
  – public API에 있는 패키지 이름
  – 그렇다고 정리하는걸 주저하면 안된다. 아키텍처 품질을 위해 deprecation 해버리자.

케이스 스터디: 스프링
– 스프링 코드 복잡한 SPI, 다양한 곳에서 사용하는 많은 API, 다양한 요구사항 속에서 3.5년을 어떻게 버텨왔을까?
– 매우 엄격한 아키텍쳐 관리
  – loosely counpled package with welldefined interdependencies
  – 패키지 단에서 CD가 없다. 만약에 CD가 생기면 다시 살펴보고 심각하게 고민하다.
– 스프링이 가지고 있던 CD (수정 후 dependency)
  – core <-> util (core <- util)
  – beans <-> aop (beans <- aop)
  – beans <-> context (beans <- context)
  – transaction <-> dao (transaction -> dao)
  – transaction <-> jdbc (transaction -> jdbc)
(소스 코드로 좀 보여주지 말로만 설명하네. 힘들게 시리 ㅠ.ㅠ)

CD 확인하는 도구
– JDepend
– SonarJ
– 공식 배포 하기 전에 JDepend를 한 번 돌려보는 건 어떨까!!

TSE 2006(Meeting Requirements through Acceptance and Stress Testing)

Acceptance Tests

비즈니스 요구사항/유즈케이스에 대한 구현에서 에러를 찾는다.
Formalized 요구사항
시스템 테스트(완성한 시스템에 대한 테스트)를 할 때 보통 한다.
보통 수동으로 한다.(반복하기 힘들기 때문에)

Fit/FitNesse

목적 : 고객이 인수 테스트를 작성하도록 만든다. <= XP의 목표가 되었다. 근데 이걸 어떻게 할 건가?
HTML을 input으로 사용한다.
    간단한 형식
    여러 도구로 사용가능(Ms Office)
    테스트와 문서(요구사항에 대한..)를 섞어 둘 수 있다.
테스트 만드는 방법
    public 필드 사용
    errors() 메소드 구현
    @Configurable 사용

스프링 아키텍처가 Fit 테스트를 간단하게 해준다.

    서비스들이 유즈케이스나 비즈니스 로직을 나타낸다.
    따라서 요구사항 테스트로 사용할 수 이쓴ㄴ 부분이 정의되어 있는 것이다.
    도메인 객체는 파라미터로 사용할 수 있다.
    시스템 테스트와 관계없이 비즈니스 요구사항에 대한 구현에서 에러를 찾아 볼 수 있다.
    쉽게 자동화 할 수 있다.
    사용자는 GUI가 보이지 않더라도 테스트가 수행됐다는 것을 믿을 수 있다.

사용 방법
   
    서비스 클래스 마다 Fit 테스트를 작성하라.
    public 속성을 도메인 객체로 변환해주는 어댑터를 만들어라.
    서비스를 호출하라

그냥 서비스를 Fit으로 Export 할 순 없을까?

    비즈니스 계층은 별다른 노력 없이 FIt으로 테스트 가능하다.
    할 수 있다. Generic Fit Exporter를 만들어야 한다. 이게 바로 Spring-FitNesse 프로젝트 목표다.
       스프링 Bean에 접근할 수 있어야한다.

이 후는 FitNesse 구현에 대한 여러 고민이 이어집니다. 이럴까 저럴까..이렇게 했다.
    PropertyEditor와 BeanWrapperImpl 사용해서 구현함.
    그 결과..
        도메인 객체를 자동으로 만들고 제공합니다.
        도메인 객체를 파라미터로 서비스들을 호출합니다.
        그 결과를 확인합니다.

주요 클래스
    SpringColumnFixture
    SpringActionFixture

결론

Fit을 쉽게 사용할 수 있으며
Generic 어댑터를 사용할 수 있다.
완성된 시스템이 없더라도 요구사항을 테스트 할 수 있다.
https://spring-fitnesse.dev.java.net

Stress Tests

Non functional Requirement
성능을 측정하는 방법
    JMeter

원하는 것

    계층 마다 측정하기
    JAMon
       모니터링 프레임워크
       결과를 웹 페이지에 보여준다.
       스프링은 JAMon 인터셉터를 제공해 준다.

JAMon
   
    웹 계층
       JAMonFilter
          HTTP Request/Response
          뷰와 컨트롤러까지 처리에 걸리는 시간을 계산해서 전체 시간에서 뺀준다.
    다른 계층
       포인트컷을 조정하면 된다.
    SQL 까지 프로파일 할 수 있다.
   
왜 JAMon을 사용해야 하나?

    기존의 포인트컷과 Spring AOP 프록시들을 재사용할 수 있다.
    오버헤드가 적다.
    모든 계층을 조사할 수 있다.
    스프링이 묶어 줄 것이다.

결론

    테스트와 관련된 스프링의 다양한 기능
       DI
       환경에 독립적
       통합 테스트용 클레스
    스프링 아키텍처가 Fit에 가져다 주는 장점
       도메인 객체를 데이터 컨터이너로 사용할 수 있다.
       JMeter, JAMon 그리고 Spring AOP는 성능 측정을 쉽게 해준다.

TSE 2006(Applying Domain Design in the Enterprise with AspectJ)

AspectJ In Action의 저자답게 AspectJ로 DDD를 돕는 여러가지 방법을 설명해줬습니다.

• Overview of Domain-driven design
• Aspects for crosscutting infrastructure
• Aspects for fine-grained DI
• Aspects for domain logic
• Aspects for enforcing DDD best
practices
• Proceeding towards DDD

이런 순서대로 발표가 진행됐는데, 토비님께서 마소에 기고하셨던 내용과 비슷한 내용들이 초반에 언급되었고 그 뒤로는 AspectJ를 사용하여 DDD 구현에 도움이 되는 방법들을 소개해 줬습니다.

  1. Service Layer에서 Aspect성 기능들을 Aspect로 구현하기.
  2. Aspect 사용해서 Repository나 Facade나 Service 객체들을 도메인에 DI 하기.
  3. 도메인 로직 중에 Aspect성 기능들을 Aspect로 구현하기.
  4. 아키텍처 정책을 수행하도록 강제하는 기능들을 Aspect로 구현하기.(web에서 Repository 호출하면 Eclipse에서 error로 표시하도록, DI사용해서 주입해야 할 것들을 명시적으로 new 하지 못하도록, …)

마지막으로 다음과 같은 ‘사고의 흐름’을 권장해줬습니다.

• 도메인 엔티티와 도메인 로직부터 시작하기
– Basic domain-driven and object-oriented principle
• 시작할 때 기본적으로 service 계층은 없다고 생각하기
– See how far you can get
– Add service level as required
• 구현과 관련된 규칙들을 강제하기
• DDD로 리팩터링하기.

TSE 2006(The Art of Domain Modeling)

Keith Donald가 발표를 했는데, 전반후와 후반부로 나눠서 전반부는 Domain Modeling에대한 이론을 설명하고, 후반부는 특정 사례를 들어 모델링을 수행하고 모델을 코드로 구현하는 과정을 보여주었습니다.

이론 부분에서 인상 깊었던 부분.

  • 도메인 모델링은 실제 세상 전부를 다루는 것이 아니라 영화처럼 특정 시점에서의 세상을 표현하는 것이라는 것.
  • 효율적인 모델링 요소
    • 모델을 코드로 바인딩 – 모델의 가용성을 테스트에 일찍 그리고 자주 반영하기 위해
    • Knowledge-rich model 정제하기 – 풀어야할 문제의 핵심 복잡성을 잡아내가 위해
    • 공유 언어에 익숙해지기 – 모델에 기반한 의사소통을 위해
    • 브레인스토밍과 실험

이밖에도 좋은 말을 많이 한 것 같은데 좀 어렵네요.

실습 부분에서 인상 깊었던 부분

  • 오.. 얼핏 TDD
  • 맥 사용이 불편하신 듯.. 하지만 맥을 좋아하시는 듯
  • 라이브 코딩이 약간 어색..

코딩을 빠르게 멋지게 하는 모습이 중요한 것이 아니기 때문에 별로 상관없었습니다. 모델을 바로 코드로 검증하려는 모습이 중요했습니다. 테스트 코드는 거의 하나의 시나리오를 보여주고 있었고, 해당 테스트를 실행하기 위해 여러 도메인 모델을 만들고 메소드를 구현했습니다.

Spring is XML Hell

이라는 주제로 TSE 2006에서 발표가 있었습니다. 작년 자료인데, 찬욱군토비님한테 받아온 것을 제가 다시 찬욱군으로부터 받았습니다.ㅋㅋ

사실 저 것은 부제고 원제는 Myth Buster 입니다. ‘미신 깨기’ 정도가 되겠네요. 따라서 Spring은 XML 지옥이 아니다는 주제가 되겠죠.

Spring이 XML을 많이 사용하는 것은 사실입니다. 2.5부터는 애노테이션을 대폭 활용하게 되겠지만 Java5를 도입하기 어려운 환경에 있으신 분들은 XML로 많은 bean들을 설정하게 될 것입니다. 이 때 다음과 같은 몇 가지 지침많 따르신다면, XML 지옥에서 벗어날 수 있을 것 같습니다.

  • bean 설정을 여러 파일로 나누기
  • import 엘리먼트 사용하기
  • 설정 파일을 코드 근처에 두기
  • bean의 id는 인터페이스 이름으로 한다는 Naming Convention 사용하기.
  • Factory나 FactoryBean을 사용합니다.(고정적인 부분을 설정으로 외부화 하지 않고 감출 수 있습니다.)
  • 또는 5번과 같이 Factory가 없어도 간단하게 static 블럭을 사용하여, 내부적으로 초기화 할 수 도 있습니다.
  • Spring이 제공하는 Parent/Child bean 설정 기능 사용하기.
  • Spring 2.0 부터 제공하는 다양한 네임스페이스 사용하기.(aop, jee, lang, tx, util, …)
  • 원하는 네임스페이스 만들어 사용하기.(KSUG 1회때 토비님께서 발표 했었습니다.)
  • Spring IDE 사용하기
  • 작년 TSE에서 Interface21의 수석 컨설컨트 Ben Hale이 발표한 내용을 참조했습니다.