rangnarang

좋은 코드를 작성하는 기술. 본문

좋은 코드를 작성하는 기술.

와이낫? 2018. 11. 19. 19:36

아가타 토시타카 지음/ 정인식 옮김/ Jpub 




목차


  1. 좋은 코드란 무엇인가
    1. 좋은 코드의 정의
    2. 좋은 코드이 가치
  2. 좋은 코드를 작성하기 위한 5가지 습관
    1. 읽기
    2. 쓰기
    3. 도구의 연마
    4. 알기
    5. 듣기
  3. 명명하기
    1. 좋은 코드는 좋은 이름에서 나온다.
    2. 좋은 이름의 조건
    3. 변수명
    4. 메소드명
    5. 클래스명
    6. 패키지/네임스페이스명
    7. 프로젝트명
  4. 스코프
    1. 스코프를 인식하는가
    2. 스코프란 무엇인가
    3. 스코프를 작게해서 기억하는 것을 줄이자.
    4. 변수의 스코프
    5. 메서드의 스코프
    6. 클래스의 스코프
    7. 캐스트를 사용한 가시성의 제어
    8. 보다 영역의 스코프
  5. 코드의 분할
    1. 코드를 분할하는가
    2. 두자가 방향으로의 분할 (하향/상향)
    3. 클라이언트에 xml 반환하는 API 처리의 분할
      1. 코드 작성
      2. 공통처리를 메소드로 추출하여 분할
      3. 처리단위로 분할
      4. 상태를 가진 처리를 클래스로 추출하여 분할
  6. 코드의 집약
    1. 코드 중복은 나쁘다
    2. 메소드로 추출하여 정리하기
    3. 계승으로 정리하기
    4. 유틸리티 클래스로 정리하기
    5. 서비츠 층에 정리하기
    6. 객체에 정리하기
    7. 정수에 정리하기
  7. 코드의 성능
    1. 성능은 계산량으로 결정된다.
      1. 알고리즘,클래스, 라이브러리 선택/사용법에 따라 바뀐다.
    2. 성능 개선의 순서
      1. 측정
      2. 원인 특정
      3. 튜닝
      4. 튜닝결과 측정
    3. 알고리즘 선택 이외의 성능개선
      1. SQL이나 테이블 설계 변경하기
      2. 캐시 사용하기
      3. 인프라 강화하기
    4. 성능 개선의 지침
      1. 어느 타이밍에 튜닝을 하는 것이 최선인가
      2. 적절한 양의 테스트 데이터를 준비하자
      3. 항상 성능을 의식하자
  8. 단위 테스트
    1. 단위테스트란
    2. 단위 테스트의 효능
      1. 다양한 테스트 자동화
      2. 회귀 테스트에 의해 코드가 망가지지 않은 것을 보증
      3. 설계의 개선
    3. 애플리케이션 보안 테스트
      1. DB 테스트 데이터 등록
      2. 화면 구현
      3. 화면의 단위 테스트(정상)
      4. 화면의 단위 테스트(이상)
      5. 단위 테스트 지침.
  9. 추상화
    1. 프로그래밍의 파워를 최대화하는 것이 추상화
    2. 배열/컬렉션, 이를 이용한 추상화
    3. 에제 : 이미지파일의 리스트를 표시하는 웹애플리케이션
      1. 코드를 대충 작성하기
      2. 가독성을 높이기 위한 메소드 추출
      3. 관련 데이터의 데이터 구조 정리
      4. 배열/컬렉션을 이용한 추상화
    4. 추상화의 지침
      1. 어떤 타이밍에 추상화하는 것이 베스트인가
      2. 코드중복을 정리하지 말라?
      3. 이건 단순 루프가 아닌가?
  10. 메타프로그래밍
    1. 프로그래밍을 프로그램하기
    2. 메타프로그래밍이란
      1. 코드의 자동생성
      2. DSL
      3. 예제 : Excel 사용한 외부 DSL
        1. 일단 코드 작성해보기
        2. 메타데이터를 Excel 이동하기
        3. 리플렉션 API 변환 규칙을 동적으로 적용하기
  11. 프레임워크를 만들자
    1. 프레임 워크의 동작 원리 이해하기
    2. 예제 : 애플리케이션의 프레임워크 만들기
      1. 기본이 되는 서블릿으로 작성해 보기
      2. 프런트 컨트롤러와 액션 클래스의 도입
      3. 라우팅 정보의 외부 파일화
      4. 자주 사용하는 처리를 간단하게 실행할 있도록 공통화하기
      5. 프레임워크를 패키지화한다


—————————————————————————



좋은 코드란 무엇인가

  1. 좋은 코드의 정의

유지보수성이 높고

신속하고 효율적으로 동작

정확하고

불필요한 부분이 없는

  1. 좋은 코드의 가치

프로젝트를 강력하게 추진

프로그래머로서 평가가 높아진다.

만족, 자존감 상승


좋은 코드를 작성하기 위한 5가지 습관

  1. 읽기
    오픈소스나 주변 사람들 코드 읽기.
    구글 코드 검색
  2. 쓰기
    일단 코드를 작성한다.
    주변에서 구한 코드를 작성하여 숨겨진 의도등에 대해 파악한다.
  3. 도구의 연마
    에디터 활용/ 빌드를 자동화/ DB 스키마 자동화/버전관리/유닉스 사용
  4. 알기
    서적, 레퍼런스/사양서등의 문서, 웹사이트를 통해 좋은 지식을 얻을
  5. 듣기
    코드리뷰, 블로그, 커뮤니티, 성과발표등을 통해 들어야 한다.


명명하기

  1. 좋은 코드는 좋은 이름에서 나온다

  2. 좋은 이름의 조건
    설명적이고 의미, 의도를 나타내야 한다.
    일관적이어야 한다.
    영어로 부여 되어야 한다.
    관용표현, 코딩표준을 따라야 한다.
    -
    자바는 메소드명이 소문자로 시작하고 C# 대문자로, C++에서는 프리픽스 ‘m_’ 붙이는 것이 일반적이다.

  3. 변수명
    글로벌 - 자바에서는 클래스 변수를 글로벌 변수의 대용으로 사용한다.
    클래스 - 자바에서는 클래스에 정의된 static 필드 변수를 클래스 변수로 여긴다.
    필드(인스턴스)변수 - 자바에서는 클래스 내에 정의된 static 아닌 변수가 필드변수다.
                                 -
    반대로 static으로 선언된 변수는 클래스변수가 된다.
    로컬변수 - 메소드나 for문등의 짧은 블록 안에서 사용되는 일시적인 변수를 말한다.
                    스코프 길이에 따라 사용을 구분할 것.(관용적인 표현도 좋지만 for 문 내에서 i,j,k등 표기하기 편한 상태로 사용하는것이 좋을 때도 있다.)
    메소드의 파라미터 - 알기 쉽게 간단히.

  4. 메소드명
    처리를 수행하는 단위이기 때문에 '동사 + 목적어'로 표기하는 것이 좋다.
    인스턴스 메소드 - 객체의 인스턴스와 결부되어 호출될수 있는 메소드를 말한다. 필드변수를 엑세스 할수 있으며 Java에서는 static을 붙이지 않은 메소드가 인스턴스 메소드다.
    클래스 메소드 - 클래스가 갖고 있는 메소드를 말한다. Java에서느 클래스 내 static으로 정의된 메소드를 말한다.

  5. 클래스명
    클래스명이 잘 떠오르지 않는다면 클래스의 역할이 확실하게 정의되지 않은것이 아닌지 생각해 볼 필요가 있다.
    한개의 클래스에 복수의 역할과 책임이 혼재되어있지 않은지, 아니면 역할이 애매하지는 않은지를 판단하여 재 설계하는 것이 좋다.
    '클래스의 이름 명명 = 설계' 인 셈

    업무 웹 애플이케이션 개발
    - *Action, *Controller, *Dto, *Logic, *Service, *Helper, *Util, *Support, *Dao, *Manager, *Bean, *Form, *Exception, *Validator, *Test, *Impl

    GUI/프레임워크 확장
    - *Listener, *Handler
    , *Runner, *Command, *Observer, *Node, *Adaptor, *Proxy, *Holder, *Context, *Monitor, *State, *Builder, *Factory, *Visitor, *Decorator, *Strategey

    프레임워크/라이브러리 개발
    -  *Scope, *Loader, *Engine, *Provider, *Conversion, *Behaviour, *Descriptor, *Cache, *Resolver, *Processor

  6. 패키지/네임스페이스명
    간결한 명사로 사용하는 것이 좋다.
    - util, name,service,plugin,crypt,rule

  7. 프로젝트명
    프로젝트명을 기초로 패키지명, 데이터베이스의 스키마명, Git/Subversion의 리포지터리 명 등이 정해진다.
    심플하게 프로젝트 이미지를 떠올릴수 있는 이름으로 사용하는 것이 좋다



4. 스코프

  1. 스코프를 의식하는가
    의식적으로 스코프를 컨트롤 할수 있다면 코드가 더욱 파악하기 좋다.

  2. 스코프란 무엇인가
    스코프는 사용 범위이며 의존성을 나타낸다. 스코프가 넓다면 의존성이 크다는 것을 의미한다,

  3. 스코프를 작게해서 기억하는 것을 줄이자.
    스코프를 작게 함으로서 코드가 심플해진다.

  4. 변수의 스코프
    1. 로컬변수의 스코프
        로컬변수는 일시적인 변수이며 블록 스코프이다.
        변수는 사용직전에 선언한다. (범위의 최소화)
        메소드로 추출한다.
        반복자(iterator) 내에서 사용하는 임시변수의 스코프를 루프내로 한정한다.
        대입되지 않는 변수에는 final을 붙인다.( = const )

    2. 필드변수
        필드변수는 인스턴스 별로 보관/유지되는 변수를 말한다.
        private이 기본이다.
        변수를 외부나 하위클래스로부터 엑세스 하고 싶은 경우 set/get등 엑세스용 메소드를 준비하여 공개해야 한다.    
        실제 효율이나 엑세스 메소드의 장황성을 배제하기 위해 package private, protected, public으로 변경하여 사용하는 경우도 있다.

    3. 클래스변수
        클래스가 보관/유지하는 변수로 대부분 필드변수와 동일한 가시성을 지정할 수 있다.
        private가 기본.
        
  5. 메서드의 스코프
    1. 인스턴스 메소드 
        - 인스턴스에 결부되어 호출할수 있는 메소드. 인스턴스를 통하지 않고서는 호출이 불가능하다.

    2. 클래스 메소드
        - static을 붙인 메소드. 이는 필드변수를 엑세스 할 수 없다.
        인스턴스 메소드를 클래스 메소드로 변경할 경우 자신이 영향을 주는 메소드가 줄어들게되어 결과적으로 스코프는 작아지게 된다.
        필드변수에 엑세스 할 필요가 없고 오버라이드 등이 필요가 없는 메소드는 클래스 메소드로 하는 편이 좋은경우가 많다.

    3. 메소드 파라미터의 정보량.
        - 파라미터가 전달하는 것이 객체일 경우와 단순 string일경우 정보 전달량이 다르다.
        비교를 하자면 객체보다 string으로 전달하는 경우가 의존성이 낮기 때문에 좋은 코드라 할수 있다.
        필요한 최소한의 정보만 갖는것이 좋지만
        만약 파라미터의 수가 5개 이상일 경우에는 파라미터를 객체로 변경하는 것이 좋다.

  6. 클래스의 스코프
    private, package private, protected, public  총 4가지다.
    클래스의 선언에서는 주로 public을 많이 사용한다.
    private은 인스턴스의 생성을 그 클래스에서만 실시 하고 싶은 경우(싱글톤 패턴)
    다만, 메인 클래스 선언은 private로선언할 수 없기 때문에 생성자를 private로선언하여 다른 클래스에서는 인스턴스의 생성을 할수 없게 한다.

    1. 내부 클래스
        클래스 내 정의된 클래스로 보통 private로 선언한다.
        GUI 애플리케이션의 이벤트핸들러 정의는 private한 내부 클래스로 주로 구현한다.
        내부 클래스 메소드가 static이 붙지 않았을 경우 외부 클래스의 필드에 접근이 가능하다.

    2. 무명 클래스
        익명 클래스.선언한 장소에서만 사용가능하다.

  7. 캐스트를 사용한 가시성의 제어
    형변환을 통해 불필요한 메소드를 사용하지 못하게 하는 방법도 있다.
    반대의 경우도 가능하지만 그리 했을 경우 스코프가 늘기 때문에 좋은 방법이라 할수 없다.

  8. 보다 영역의 스코프
    디자인 패턴등 컴포넌트 레벨의 스코프를 의미한다.
    하지만 이 역시도 작은 레벨의 스코프가 모여 발생하는 것으므로 작은것부터 튼튼히하는 것이 중요하다.


5.코드의 분할

  1. 코드를 분할하는가
    가독성이 향상, 유지보수가 편하고 재사용률이 높아진다.

  2. 두가지 방식으로 분할 (하향/상향)
    하향식 방식 - 우선 필요한 클래스나 메소드를 추출,분할하고 그 후에 구현. (UML, 화이트보드를 사용하여 클래스설계하고 구현진행.)
    상향식 방식 - 일단 개발부터 한 다음에 리펙토링 하면서 정리하는 방식. (요즘엔 이클립스 등으로 간단하게 리펙토링이 가능하다.)

    무엇이 옳다고는 할수 없지만 일반적으로 초보자들이 상향식 방식을 많이 사용.
    실제로는 두가지를 조합해 코드를 분할,정리한다.

  3. 클라이언트에 xml 반환하는 API 처리의 분할
    클라이언트에 XML을 반환하는 웹API 제작 예제를 만들어 본다.

    1. 코드 쭉 작성하고
    2. 공통처리 부분을 메소드로 추출. 이때, 메소드 내적인 요소말고 외적으로 영향을 주면 안된다.
    3. 처리단위로 분할. 데이터를 취득하고 XML을 작성하고 XML을 출력하는 3가지 단위로 추출한다.
      또한 제어구문(for, if, try등)에서 각각을 메서드로 대체해두면 흐름도 알고 쉽고 읽기도쉬워진다.
    4. 상태를 가진 처리를 내부 클래스로 추출하여 분할,정리한다.
      내부클래스로 만든 이유 - 바로 확인할수 있어 알기 쉬움. 외부에 따로 클래스파일을 만들지 않아 복잡도가 줄어든다. 
      클래스 추출 시 필드변수로 사용하기 좋은 정보는 플래그, 상태값, 복수의 인스턴스 메서드에서 사용하는 데이터 등이 있다.

정리 : 코드분할은 연습할수록 좋은 결과를 얻을 수 있다.




6. 코드의 집약

  1. 코드 중복은 나쁘다
    코드가 중복되면 수정도 어렵고 가독성도 떨어진다.
    중복없이 정리된 코드가 잘짜여진 코드.
    있어야 할곳에 있는 코드가 이상적.

    초보자는 메소드 추출하여 정리부터 하고 조금씩 난이도를 높여 정리하는 것이 좋다.
    (코드정리가 심해지면 스파게티코드가 되어 알아보기도 힘들어 진다.)

  2. 중복된 코드를 메소드로 추출하여 정리. 
  3. 상속으로 정리하기
    어떤 클래스를 상속받은 자식 클래스들 사이에서 코드중복이 발생될 경우, 중복코드를 부모 클래스로 이동하여 정리하는 것이 좋다.
    이 경우 단점이 발생할 수 있는데 부모클래스가 비대해 지거나 단일상속으로 사용이 불가능 할수도 있다는 점이다.(자바는 단일상속받음)
    이럴때는 유틸리티 클래스나 서비스 클래스를 사용하는 것이 좋음.

  4. 유틸리티 클래스로 정리하기
    특정한 처리에 편리한 메소드를 모아둔 클래스.
    위 3번처럼 부모클래스에 정리하지 않고 유틸클래스에 넣어두면 다른클래스 상속이 가능하기 때문에 여러모로 좋다.
    또한 유틸리티클래스는 기본적으로 상태를 갖지 않는 static 메소드로 정의. (static import 참고할 것)

  5. 서비츠 층에 정리하기
    웹 어플리케이션에서는   컨트롤러 - 서비스 - 데이터 엑세스   3층 레이어 구조의 아키텍처를 사용한다.
    컨트롤러 층에서는 애플리케이션의 중심기능을 작성하지 않고 서비스층을 호출하여 애플리케이션의 비지니스 로직을 처리하기 위한 서비스를 실행한다.

  6. 객체에 정리하기
    만약 별도의 객체를 참조하는 일이 많을 경우에는 해당객체에 메서드를 넣어두는 것이 더 효율적이다.
    폴더라는 객체를 호출하는데 폴더 객체가 공유폴더 여부확인 메서드가 필요하다고 가정할때,
    이를 폴더 객체에 생성해 두고 클래스에서는 호출하여 처리 여부만 결정하면 될것이다.
    이 방식은 설계가 중요하다. 연습 많이 해야함.

  7. 정수에 정리하기
    특정값의 중복도 유지보수성을 떨어뜨린다.
    중복되는 데이터는 상단에서 상수로 선언해두고 공통적으로 사용하는 편이 좋다.
    예를들어 중간중간 0 또는 1 의 값이 많이 체크되고 있다면 상단에 이를 상수로 선언하고 사용.

지나치게 코드를 정리하는 것도 좋지 않고
'같은 코드가 두번 나오면 정리'하는 정도가 좋다




7. 코드의 성능

    효율 좋게 동작하는 코드를 실현하기 위한 방법.
    측정에서 시작해서 측정으로 끝난다.

  1. 성능은 계산량으로 결정된다.
    코드는 한개 명령마다 비용이 발생하는데 그 비용을 수치화해서 합계를 낸 것이 계산량이다.
    계산량이 적으면 성능이 좋고, 많으면 성능이 나쁜데, 이 계산량은 알고리즘에 따라 변하게 된다.
    무분별한 중첩루프 사용은 지양 하고 사용시엔 break 사용해 계산량을 줄일 것.

    ArrayList, LinkedList는 성능이 다르다.
    ArrayList - 내부적으로 배열을 이용하여 리스트를 관리한다. 도중에 요소 삽입/삭제시 배열순서 변환이 발생해 느림 인덱스 지정 참조는 고속
    LinkedList - 참조리스트를 사용하여 리스트를 관리. 요소삽입/삭제처리가 빠른반면 인덱스 지정 참조는 느리다.

  2. 성능 개선의 순서
    1. 측정
      성능튜닝의 순서
      회귀테스트 - 측정 - 원인특정 - 튜닝 - 재측정(문제시 다시 측정단계로) - 회귀테스트
      로그와 프로파일러, 성능 측정 툴을 사용한다.

    2. 원인 특정
      성능이 낮은 위치와 이유의 범위를 좁혀나간다.

    3. 튜닝
    4. 튜닝결과 측정
      튜닝이 끝나면 다시한번 측정하여 기존과 비교하고 수치로 확인한다.
      개선되지 않았다면 다시 원인특정 단계로 돌아가 확인한다..
      이후 회귀테스트를 실시하여 프로그램이 망가지지 않았는지 확인한다.

  3. 알고리즘 선택 이외의 성능개선
    1. SQL이나 테이블 설계 변경하기
    2. 캐시 사용하기
    3. 인프라 강화하기

  4. 성능 개선의 지침
    1. 어느 타이밍에 튜닝을 하는 것이 최선인가
      개발 초기부터 성능을 염두에 둘 필요가 있다.
    2. 적절한 양의 테스트 데이터를 준비하자
    3. 항상 성능을 의식하자





8. 단위 테스트
    테스트는 중요하다.
    여기서는 주로 Tool을 사용하여 테스트 진행, (Java - JUnit 사용)

    자동화된 단위 테스트를 주로 사용한다.

  1. 단위테스트란
    유닛테스트라고도 불리우며 메소드,클래스 등의 구현코드에 대해 작성되는 테스트를 말한다.

  2. 단위 테스트의 효능
    1. 다양한 테스트를 자동화 할 수 있다.

    2. 회귀 테스트에 의해 코드가 망가지지 않은 것을 보증
      자동화된 단위 테스트는 배치처리나 Jenkins등의 인터그레이션툴을 사용함으로서 정기적으로 실행할 수 있다.
      계속적 인터그레이션툴을 사용하면 커밋과 동시에 모든 단위 테스트가 실행되어 커밋에 의해 코드가 손상되지 않았는가를 자동적으로 발견해준다.

    3. 설계의 개선으로 이어진다.
      단위 테스트를 작성할 경우 테스트코드가 실행될 수 있도록 설계가 되기 때문에 쓸데없는 부분이 없는 필요 최소한의 설계가 된다.

  3. 애플리케이션 보안 테스트
    todo 애플리케이션 구성 예제.

    1. DB 테스트 데이터 등록하고
    2. 간단하게 화면을 구현한다.
    3. 화면의 단위 테스트(정상)
    4. 화면의 단위 테스트(이상)
    5. 단위 테스트 지침.

테스트 정책을 정할것.
웹컨트롤러층에서 비지니스로직에 대한 대부분의 테스트를 작성하지만 서비스나 데이터엑세스 층에서 테스트를 작성하는 접근방식도 있다.
이런 부분들은 대부분 모의객체(Mock Object)로 에뮬레이션하거나 툴을 사용하는 방법을 사용한다.


많은 연습이 필요하다.
어떤 툴을 사용해야 하는지 맞는 것을 정하고 계속 연습하는 것이 중요.




9. 추상화

    추상화는 비슷한 것을 동일하게 취급함으로서 프로그래밍을 간단하게 하는 것으로 
    프로그래밍의 파워를 최대화하는 것이 추상화.

    예는 아래와 같다.
    
    1) 공통적인 처리를 정리하여 부모클래스로 작성.
    2) 데이터베이스 접속정보를 설정파일로 외부추출
    3) 비슷한 메서드를 인터페이스로 추출

    추상화는 파라미터레벨의 추상화, 데이터형의 추상화, 다형성등이 있음.
    여기서는 배열/컬렉션을 이용한 파라미터 레벨의 추상화를 다룬다.

  1. 배열/컬렉션, 이를 이용한 추상화
    배열과 컬렉션은 모두 객체의 리스트를 보관하고 관리할수 있는 용기(컨테이너).
    서로 다르며 배열은 나중에 변경불가능하고 컬렉션은 확장가능하다.


  2. 에제 : 이미지파일의 리스트를 표시하는 웹애플리케이션
    이미지폴더 내 폴더 목록을 보여준다.
    폴더명, 폴더내 이미지 용량, 폴더내 이미지 목록을 출력함.

    1. 코드를 대충 작성하기
      되는대로 작성.

    2. 가독성을 높이기 위한 메소드 추출
      추상화를 진행하기 전에 데이터 구조를 정리하는 것이 좋다.
      관련있는 것들의 묶음이라면 이를 한개의 오브젝트로 정리할수 있으니까.

    3. 관련 데이터의 데이터 구조 정리
      파일 목록, 사이즈등은 공통적인 부분이므로 이를 관리하는 유틸리티 클래스를 하나 만들어 정리한다.
      이런 데이터는 계층구조를 가진 클래스로 정리하는 것이 좋다. 이에대한 조작이 필요한 경우 인스턴스 메소드로 정의 할수도 있기 때문.

    4. 배열/컬렉션을 이용한 추상화
      입력 데이터를 배열을 이용하여 단순화 시키고 루프돌려 결과를 하나의 객체로 만들어 리턴한다.

  3. 추상화의 지침
        추상화는 몇수 앞을 바라보는가가 중점. 너무 이르거나 쓸데없는 추상화는 시스템을 복잡하게 만들어 버리기 때문에 좋은 코드라 할수 없다


데이터형의 추상화, 다형성에 대해서도 알아보자.
좀더 많은 예제와 연습이 필요하다.



10. 메타프로그래밍


추상화를 응용하는 예로 다룬다.
메타프로그래밍은 프로그래밍을 프로그래밍하는 것.
보통의 프로그래밍이 '산순히 처리를 순서대로 나열하여 코딩하는 것'이라고 한다면, 여기서는 프로그램을 자동생성하는 프로그래밍을 말한다.


최근의 웹 프레임워크는 뷰나 컨트롤러를 자동으로생성해 주는 기능이 있고 데이터 베이스의 스키마를 기초로 엔티티 클래스등 많은 원시 코드를 자동으로 생성해 주기도 한다.

이런것들이 메타프로그래밍의 일종이라고 할수 있다.

    1. DSL (Domain Specific Language : 도메인 특화 언어)
      일종의 메타프로그래밍으로 어떤 특정의 문제 영역을 해결하기 위한 작은 규모의 언어를 DSL이라 한다.
      예를들어 JAVA의 DSL은 JSP.
      JSP에서 서블릿엔진은 HTML을 출력하는Java코드로 변환(pre-compile)되고,
      이렇게 생성된 Java코드가 다시 컴파일 되고 실행되서 HTML을 출력한다.

      외부 DSL
      - 예를들어 XML파일에 프로그래밍 설정을 넣어두고 사용하는 방법도 이에 해당된다.
        이게 실제로 단순한 설정파일로도 해석될수 있지만, 프로그램 실행시에 해석되어 프로그램의 동작이 동적으로 변할수 있다는 점에서 다르다고 할수 있다.

      내부 DSL
      - 내부적으로 참조를 걸어 사용하는 방법을 예로 들수 있으며, 자유도가 높은 언어에서는 다양하게 구사할수 있음.
        JAVA처럼 구문의 자유도가 낮은 언어에서는 구현이 어렵다. 한정적 방법으로 Annotation, fluent interface를 사용한다.

    2. 예제 : Excel 사용한 외부 DSL

          엑셀 파일을 읽고 이를 출력하는 프로그램을 DSL로 응용하여 제작한다.
          이 엑셀파일에는 출력해야 하는 데이터가 "표"로 기재 되어있다.(컬럼별 길이,내용에 대한 사양서 제공)
          
      1. 일단 코드 작성해보기
        메인에서는 파일을 읽고 이를 바이트형식 메세지로 리턴 후 미리 제작한 파서 내부 클래스로 파서를 돌린다.
        파서 내부 클래스는 생성자에서 파라미터로 바이트 배열을 받고 이를 파서메서드에서 배열 길이만큼 루프를 돌린다.
        루프내에서 해쉬맵을 생성하고 각 컬럼의 데이터를 추출하여 해쉬맵에 입력 후 프린트 한다.
        인덱스와 바이트배열값은 상태를 저장해야 하기 때문에 클래스의 내부 변수로 생성하고 각 메서드에서 필요한 만큼 읽어들인다.
        각 데이터의 변환메서드도 모두 만들어 둔다(toDate, toInteger등)
        (이정도만 해도 좋은 코드라고 할수 있다.)

      2. 메타데이터를 Excel 이동하기
        앞서 코드에서는 사양서에 맞춰 파서를 하드코딩했지만 여기서는 config.xls 파일을 참조로 두고 개발한다.
        config.xls 파일내에는 컬럼 순서, 컬럼 내용, 길이값이 들어있다.

        이번에는 Main에서 1. 데이터 파일을 읽고 2. config.xls 파일을 데이터테이블로 읽은 후 3. 파서 생성자에 결과를 넣어 결과값을 출력한다.
        여기서 config.xls에 넣은 데이터가 메타 데이터(데이터베이스 정의정보, html meta 태그 등)가 된다.

      3. 리플렉션 API 변환 규칙을 동적으로 적용하기
        Java의 Class객체를 통해 필드, 메소드, 어노테이션등의 메타정보를 취득할수 있는 API를 말한다.
        우선 변환 규칙용 인터페이스(Convert, IntegerConverter ... 등)를 만들어 놓고
        앞서 데이터 구조를 넣어둔 config.xls 에 추가로 데이터의 변환규칙을 추가(예.  convert.DateConverter)하고 
        config.xls를 읽는 시점에 이를 불러 직접 호출하게 함으로서 메인 내의 파서 코드내에서 따로 데이터를 변환하기 위한 코드를 작성할 필요가 없다.

        이와같이 처리로직을 교환 가능하게 해 확장성이나 보수성을 높이는 수법을 스트래티지 패턴이라고 한다. 
        여기서는 특정로직을 외부에서 인도하여 실행하게 하는 리플렉션을 사용하여 동적으로 생성하는 일이 많다.
복잡도가 오히려 상승할것 같아서 ...이렇게 까지 해야 하나 싶다.


11. 프레임워크를 만들자
    

프레임워크는 애플리케이션 작성에 있어 필요로 하는 범용적인 기능을 정리하여 재이용 할수 있도록 한 라이브러리.
struts, ruby on rails등 이 이에 속한다.

  1. 예제 : 애플리케이션의 프레임워크 만들기 - Todo List Application. 로그인처리, 리스트 표기등을 구성한다.
    1. 기본이 되는 서블릿으로 작성해 보기
      - 로그인 화면 표시, 로그인 처리, 리스트 화면 표시 등을 기초 서블릿으로 만들고 web.xml페이지에 서블릿 설정을 한다.
      이 경우 web.xml에는 사용하는 모든 서블릿의 내용이 등록되어야 하기 때문에 간략화하는 것이 좋다.

    2. 프런트 컨트롤러와 액션 클래스의 도입
      - 모든 리퀘스트를 단일의 서블릿으로 받고, 리퀘스트 패스로 처리를 결정토록 한다.
         url-pattern요소에 *.action 지정하고 .action이 붙는 리퀘스트에서 DispatcherServlet이 불리도록 처리한다.
         이렇게 모든 처리를 받는 서블릿을 프런트 컨트롤러라고 부른다.
         모든 리퀘스트를 받고 이 정보로부터 개개의 처리를 결정해 호출처리함.

    3. 라우팅 정보의 외부 파일
      - 라우팅 정보를 route.properties라는 파일에 '패스=클래스명'으로 정리하여 등록.
         이를 읽어서 라우티 정보로로딩하고 액션은 패스값을 사용하여 라우트 정보에서 클래스명을 찾아 이를 동작토록 한다.

    4. 자주 사용하는 처리를 간단하게 실행할 있도록 공통화하기
      - forward, redirect를 간략화하여 액션클래스 내에 구성한다.

    5. 프레임워크를 패키지화한다
      - 프레임워크 코드와 애플리케이션 코드를 명확하게 나눈다.
      패키지 나누기의 포인트는 의존관계를 한방향으로 하는 것으로, 프레임워크 측에는 애플리케이션 고유의 코드를 갖게 해서는 안된다.
      이후 프로젝트를 나눠 여러 프로젝트에서도 이 프레임워크 패키지를 사용할수 있도록 한다.
      또한 버전관리를 함으로서 버그에 대한 관리를 강화한다.


—————————————————————————


참고 문헌


  • 원시 코드 리딩에서 배우는 JAVA 설계와 실장.
  • 리팩토링, 나쁜 디자인의 코드를 좋은 디자인으로 바꾸는 방법.
  • 코드 크래프트 : 뛰어난 코드 작성을 위한 실천 지침.
  • CODE COMPLETE
  • 원숭이라도 있는 역방향 디자인 패턴.
  • 자바스크립트 완벽 가이드
  • 엔터프라이즈 애플리케이션 아케텍처 패턴.
  • 테스트 주도 개발
  • 실용주의 프로그래머
  • 켄트 벡의 구현 패턴
  • JAVA언어로 배우는 디자인 패턴 입문.


'' 카테고리의 다른 글

읽기 좋은 코드가 좋은 코드다. (작성중)  (0) 2018.12.13
Comments