PandaGrammer

프로젝트를 진행하면서 서버를 구축했을 때 생긴 에러들과 해결한 방법들을 적어놓았습니다.

필요 환경 구축하기

우선 필요 환경은 mariadb, java, node, nignx입니다.

Java 설치

우선 설치 되어 있는 지 확인을 위해

$ javac -version
The program 'javac' can be found in the following packages:

Java가 설치되어 있다면 아래와 같이 나타납니다.

$ javac -version
javac 11.0.7

설치를 위해 아래와 같이 입력하면 됩니다. 이후 맨 처음처럼 확인 하시면 됩니다.

$ sudo apt-get install openjdk-11-jdk

Node 설치

PPA(Personal Package Archive)를 이용해 설치합니다.

$ curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -

후에 우분투에 NodeJS를 설치해줍니다.

$ sudo apt-get install -y nodejs

NodeJs와 NPM이 잘 깔렸는지 확인합니다.

$ node -v
$ npm -v

NPM이 제 기능을 하게 하기 위해 다음 명령어를 실행합니다. (요거 없으면 npm install 시 에러 날 확률이 높습니다.)

$ sudo apt-get install build-essential

Mariadb 설치

아래와 같은 명령어를 사용해 설치합니다.

$ sudo apt-get install mariadb-server

정상적으로 설치 되었는지 확인을 위해서 아래와 같이 입력해, 정보가 뜨는지 확인합니다.

$ sudo mysql

Nginx 설치

아래와 같은 명령어를 사용해 설치합니다.

$ sudo apt-get install nginx

정상적으로 설치 되었는지 확인을 위해서 nginx를 실행하고 확인해봅니다.

$ sudo service nginx start
$ ps -ef | grep nginx

이 때 nginx가 잡힌다면 정상적으로 동작하는 것 임을 알 수 있습니다.

외부 접속 허용하기

해당 서비스를 위해 nginxreverse proxy를 설정해야 하고, 로컬에서 개발하면서 들어가는 데이터를 위해 mariadb도 외부 접속을 허용해야 합니다.

우선 db부터 세팅하겠습니다.

Mariadb 외부 접속 세팅하기

우선 현재 db의 상태를 확인해봅니다.

$ netstat -atnp | grep mysql
tcp    0    0   127.0.0.1:3306   0.0.0.0:*      LISTEN      22370/mysqld

정보를 보면 127.0.0.1:3306 로 내부에서만 접속이 허용 가능하게 되어있다.

이러한 정보를 저장하고 있는 IP 설정을 바꿔야 한다.

IP 설정을 확인해보겠습니다.

$ grep ^bind-address /etc/mysql/mariadb.conf.d/50-server.cnf
bind-address        = 127.0.0.1

이러한 설정을 없애거나 열어줘야 합니다.

vi 편집기를 열어 127.0.0.1에서 0.0.0.0으로 변경합니다

$ sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf
bind-address        = 0.0.0.0

이후 mariadb 를 재시작하고 정보를 확인해봅니다.

$ sudo service mysql restart
$ netstat -atnp | grep mysql
tcp    0    0   0.0.0.0:3306   0.0.0.0:*      LISTEN      22370/mysqld

이후 원격에서 접속해 확인해봅니다.

$ mysql -u root -p -h [ip주소]

db 정보가 뜨면 접속이 정상적으로 진행 된겁니다!

Nginx Reverse Proxy 설정

리버스 프록시

리버스 프록시란?

가짜 서버에 request가 들어왔을때, 프록시 서버가 배후 서버(reverse server)로 데이터를 요청해서 가져오는 것.

기본적으로 nginx는 비동기 처리방식을 채택하고 있다.

장점

Reverse 서버에 request에 대한 응답대기 프로세스를 생성하지 않아도 되는 장점이 생긴다.

보안상의 이점 : 또한 외부 사용자로부터 실제 내부망에 있는 서버의 존재와 정보를 숨길 수 있다.

로드밸런싱 : proxy서버가 내부 서버의 정보를 알고 관리하므로, 부하 여부에 따라 요청을 분배 할 수 있다.

Nginx 설정

$ sudo vi /etc/nginx/nginx.conf

nginx설정 파일에서 호스팅 설정을 해준다.

http { 
    ...

    server {
        listen 80;
        server_name      localhost;
        root /home/users/project  # document root 설정

        location / { # proxy_pass 설정. 특정 확장자 요청을 넘기는 설정
            proxy_pass http://localhost:8080;
            proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
        }
    }
    ...
}

Proxy_pass : 요청이 올 경우 http://localhost:8080로 요청을 전달합니다.

proxy_set_header XXX : 실제 요청 데이터를 header의 각 항목에 할당하는 역할

이상으로 전체 필요 세팅을 마쳤습니다!

Comment +0

Java Convention

Programming/JAVA2020. 7. 22. 22:31

다수의 팀프로젝트들을 진행하면서 Convention을 맞추는 경우가 종종 있어 정리한 내용입니다.
(참고) https://naver.github.io/hackday-conventions-java/

Java Convention

Naming

  1. 한국어 발음대로의 Naming 금지한다.
  2. 변수 및 이름에는 숫자, 영어만을 허용한다.
  3. 패키지는 소문자로 구성한다.
    • 단어별 구분을 위한 언더스코어(_), 대문자를 섞지 않는다.
  4. 클래스, 인터페이스에는 대문자 카멜케이스 적용
    • CamelCase
  5. 클래스 이름에는 명사 사용
  6. 인터페이스 이름에는 명사 형용사 사용
  7. 메서드, 변수 이름에는 소문자 카멜케이스 적용
    • camelCase
  8. 메서드 이름은 동사, 전치사
  9. 상수는 대문자와 언더스코어로 구성
    • MAX_VALUE

선언(Declarations)

  1. 제한자 선언의 순서

    • public protected private abstract static final transient volatile synchronized native strictfp 순으로 제한자를 선언한다.
  2. 애너테이션 후 새 줄 사용

    좋은 예

    @RequestMapping("/guests")
    public void findGuests() {}

    나쁜 예

    @Override public void destroy() {}
  3. 한 줄에 한 문장

    • 문장이 끝나는 ; 뒤에는 새줄을 삽입한다. 한 줄에 여러 문장을 쓰지 않는다.

    나쁜 예

    int base = 0; int weight = 2;

    좋은 예

    int base = 0;
    int weight = 2;
  4. 하나의 선언문에는 하나의 변수만

    • 변수 선언문은 한 문장에서 하나의 변수만을 다룬다.

    나쁜 예

    int base, weight;

    좋은 예

    int base;
    int weight;
  5. 배열의 대괄호는 타입 뒤에 선언
    나쁜 예

    String names[]

    좋은 예

    String[] names;
  6. Long 형 값 마지막엔L붙이기

중괄호

  1. K&R 스타일로 중괄호를 삽입한다.
    중괄호 선언은 K&R 스타일(Kernighan and Ritchie style)을 따른다.
    줄의 마지막에서 시작 중괄호{를 쓰고 열고 새줄을 삽입한다. 블럭을 마친후에는 새줄 삽입 후 중괄호를 닫는다.
    나쁜 예

    public class SearchConditionParser
    {
        public boolean isValidExpression(String exp)
        {
    
            if (exp == null)
            {
                return false;
            }
    ...

    좋은 예

    public class SearchConditionParser {
        public boolean isValidExpression(String exp) {
    
            if (exp == null) {
                return false;
            }
    ...
  2. 닫는 중괄호와 같은 줄에 else, catch, finally, while 선언

    • else
    • catch, finally
    • do-while의 while

    나쁜 예

    if (line.startWith(WARNING_PREFIX)) {
        return LogPattern.WARN;
    }
    else if (line.startWith(DANGER_PREFIX)) {
        return LogPattern.DANGER;
    }
    
    try {
        writeLog();
    }
    catch (IOException ioe) {
        reportFailure(ioe);
    }
    
    do {
        write(line);
        line = readLine();
    }
    while 

    좋은 예

    if (line.startWith(WARNING_PREFIX)) {
        return LogPattern.WARN;
    } else if (line.startWith(DANGER_PREFIX)) {
        return LogPattern.NORMAL;
    } 
    
    try {
        writeLog();
    } catch (IOException ioe) {
        reportFailure(ioe);
    } finally {
        writeFooter();
    }
    
    do {
        write(line);
        line = readLine();
    } while (line != null);
  3. 빈 블럭에는 새 줄 없이 중괄호 닫기 허용

    public void close() {}
  4. 조건/반복문에는 중괄호 필수

    • 한 줄로 끝나더라도 중괄호를 활용한다.

'Programming > JAVA' 카테고리의 다른 글

Java Convention  (0) 2020.07.22
VO, DTO, Entity  (0) 2020.06.21
객체지향 프로그래밍(OOP: Object Oriented Programming)이란?  (0) 2019.11.06

Comment +0

05. 책임 할당하기

  • 책임 할당 과정은 일종의 트레이드오프 활동
  • 다양한 책임 할당 방법이 있고, 상황과 문맥에 따라 다르다.

01. 책임 주도 설계를 향해

  • 책임 주도 설계를 위한 두 가지 원칙
    1. 데이터보다 행동을 먼저 결정하라
    2. 협력이라는 문맥 안에서 책임을 결정하라

데이터보다 행동을 먼저 결정하라

  • 객체에게 중요한 것은 외부에 제공하는 행동
    • 책임.
  • 데이터는 책임을 수행하는데 필요한 재료일 뿐
  • 책임 중심의 설계는 이 객체가 수행해야 하는 책임은 무엇인가? 에서 시작한다.
    • 이후 이 책임을 수행하는 데 필요한 정보는 무엇인가? 를 결정한다

협력이라는 문맥 안에서 책임을 결정하라

  • 할당된 책임의 품질은 협력에 적합한 정도로 결정된다.
    • 책임은 객체에 어울리는 게 아니라, 협력에 어울리도록
  • 즉, 메시지 전송자의 의도에 적합한 책임을 할당해야 한다.
    • 메시지를 결정하고 객체를 선택한다.
    • 이때 책임을 할당 받게 된다.
  • 메시지를 먼저 결정하면 수신자에 대해 모르기 때문에 완벽한 캡슐화를 제공
    • 캡슐화는 높은 응집도와 낮은 결합도를 제공한다.

책임 주도 설계

  • 책임을 결정한 후에 책임을 수행할 객체를 결정하는 것.
  • 협력에 참여하는 객체들의 책임이 정리될 때 까지 구현에는 관심을 때는 것.

02. 책임 할당을 위한 GRASP

  • GRASP(General Responsibility Assignment Software Pattern): 일반적인 책임 할당을 위한 패턴
    • 책임을 할당할 때의 지침 같은 원칙을 정리한 것
  • 도메인의 개념들을 정리하는 것으로 시작한다.

도메인 개념에서 출발하기

  • 도메인의 개념을 책임으로 할당하면, 코드에 도메인을 투영하기 쉽다.
  • 다만 설계를 시작하는 것이지, 완벽할 필요는 없다.
    • 많은 시간을 쓰기 보다, 빠르게 설계와 구현을 진행하자.

https://user-images.githubusercontent.com/13096845/87176867-abaa0f80-c315-11ea-86a2-c62faee273dc.png

정보 전문가에게 책임을 할당하라

  • 제공해야 하는 기능을 책임으로 생각하고, 책임을 전송된 메시지로 간주하고, 메시지를 책임질 첫 객체를 선택하는 것이 설계의 시작.
  • 영화를 예매하는 기능
    • 시스템은 영화를 예매할 책임이 있다.
    • 메시지를 전송할 객체는 무엇을 원하는가? 예매하라
    • 메시지를 수신할 적합한 객체는 무엇인가? Screening
    • 수행할 정보를 잘 알고 있는 객체: INFORMATION EXPERT(정보 전문가)
      • 다만 알고 있다고, 저장할 필요는 없다
    • 메시지를 받은 Screening은 메시지를 완료하기 위해 스스로 처리 못한다면, 외부에 도움을 요청한다.
      • 이를 통해 협력이 구성된다.
      • 하지만 Screening은 가격을 계산해야 하고, 정보를 모르기 때문에 외부에 요청한다.
      • 외부의 전문가에게 요청한다. 가격을 계산하라
      • 이를 잘 아는 전문가는 Movie
    • 이러한 형태로 계속해서 나아간다.
  • 정보 전문가 패턴은 가장 기본적인 책임 할당 원칙

높은 응집도와 낮은 결합도

  • 설계는 트레이드오프 활동이다.
  • 같은 기능을 구현할 수 있는 많은 설계가 존재한다.
  • 만약 Screening이 직접 DiscountCondition과협력한다면?
    • 제공하는 기능은 동일하다.
    • 하지만 응집도와 결합도의 차이가 발생한다.
  • 다수의 협력 패턴이 존재한다면 높은 응집도와 낮은 결합도를 얻을 수 있는 설계를 선택한다.

LOW COUPLING(낮은 결합도) 패턴
설계의 전체적인 결합도가 낮게 유지되도록 책임을 할당하는 것

  • 원래의 시스템에서 이미 MovieDiscountCondition은 결합돼있다.
    • 따라서 두 객체가 협력한다면, 결합도는 추가되지 않는다.
    • 하지만, Screening이 직접 DiscountCondition과 협력하면 새로운 결합도가 추가된다.

HIGH COHESION(높은 응집도) 패턴
높은 응집도를 유지할 수 있게 책임을 할당하는 것

  • 중요한 책임은 예매를 생성하는 것
    • 만약 Screening이 직접 DiscountCondition과 협력하면 Screening은 요금 계산의 책임 일부를 받는다.
      • 예매 요금 계산 방식이 바뀌면 Screening도 바뀐다.
    • 결과적으로, 서로 다른 이유로 변경되는 책임을 짊어져 응집도가 낮아진다.
  • 다양한 설계에서 높은 응집도, 낮은 결합도를 고려하면 유연한 설계를 얻을 수 있다.

창조자에게 객체 생성 책임을 할당하라

  • 영화 예매 시스템의 최종 결과물은 Reservation을 생성하는 것
  • 즉 누군가는 생성의 책임을 할당해야 한다.
  • GRASP의 CREATOR 패턴은 객체 생성 책임을 어떤 객체에 할당할지 안내한다.
    • 객체 A를 생성해야 하는 책임을 할당할 객체B를 선정하는 방법
      • B가 A를 포함하거나 참조한다.
      • B가 A를 기록한다.
      • B가 A를 긴밀하게 사용한다.
      • B가 A를 초기화하는 데 필요한 데이터를 가지고 있다.(B는 A의 정보전문가)
    • 이 중 많은 조건을 만족하는 객체 B를 선택한다.
  • Reservation의 경우 위 조건을 만족하는 객체는 Screening이다.
    • 생성하는데 있어서 필요한 정보에 대한 정보 전문가다.

03. 구현을 통한 검증

  • 구현에 숨은 몇가지 문제점

DiscountCondition 개선하기

  • 변경에 취약한 클래스를 포함하고 있다.
    • 코드를 수정하는 이유가 한 개 이상인 클래스
    • 응집도가 낮다.
  • DiscountCondition은 세 가지 이유로 변경될 수 있다.
    1. 새로운 할인 조건 추가
      • isSatisfiedBy안의 if - else를 변경해야 한다.
    2. 순번 조건을 판단하는 로직 변경
    3. 기간 조건을 판단하는 로직 변경
  • 따라서, 변경의 이유에 따라 클래스를 분리해야 한다.
  • 변경의 이유를 빠르게 파악하는 방법
    1. 인스턴스 변수가 초기화 되는 시점
      • 응집도가 높은 경우 생성에 모든 속성을 초기화
      • 낮은 경우에는 일부는 초기화 되지 않은 상태로 남겨진다.
      • 함께 초기화 되는 속성을 기준으로 코드를 분리한다.
    2. 메서드들이 인스턴스 변수를 사용하는 방식
      • 응집도가 높은 경우 모든 메서드가 객체의 모든 속성을 사용한다.
      • 낮은경우에는 속성에 따라 그룹이 나뉜다.
      • 속성 그룹과 해당 그룹에 접근하는 메서드 그룹을 기준으로 코드를 분리한다.

타입 분리하기

  • 가장 큰 문제는 조건들이 하나의 클래스 안에 공존하고 있다.
    • 따라서, 두 타입을 두 개의 클래스로 분리하는 것.
    • 분리를 통해 코드의 품질은 높였지만 다른 문제를 야기했다.
  • 수정 전에는 MoiveDiscountCondition하나랑 협력했다.
  • 수정 후에는 SequenceCondition, PeriodCondition 두 개와 모두와 협력해야 한다.
    • 이를 위해 Moive가 두 목록을 따로 유지할 수 있다.
      • 하지만, 클래스 양쪽 모두와 결합한다는 문제가 발생한다.
        • 결합도가 높아진 것
    • 또한, 새로운 조건을 추가하기 어려워졌다.
  • 응집도 측면에선 개선됐지만, 변경과 캡슐화에서 바라보면 설계의 품질이 하락햇다.

다형성을 통해 분리하게

  • Moive의 입장에선 두 조건이 큰 차이가 없다.
    • 그저 할인 여부를 판단하는 동일한 책임을 수행한다.
    • 방법이 다른 것은 크게 중요치 않다.
  • 이 시점에서 역할이 나타난다.
    • 두 조건은 동일한 책임, 동일한 역할을 수행한다.
  • 역할을 사용하면 객체의 구체적인 타입을 추상화 할 수 있다.
    • 자바에서는 추상 클래스와 인터페이스로 제공한다.
    • 구현을 공유한다면 추상 클래스를 책임만을 원한다면 인터페이스를
  • 이를 POLYMORPHISM(다형성) 패턴이라 한다.

POLYMORPHISM 패턴
타입을 명시적으로 정의하고, 각 타입에 다형적으로 행동하는 책임을 할당한다.

변경으로부터 보호하기

  • 만약 새로운 할인 조건이 추가 된다면?
    • 역할을 통해 Movie에서 DiscountCondition은 캡슐화된다.
    • 새로운 타입을 추가하더라도 Movie는 영향을 받지 않는다.
  • 변경을 캡슐화하도록 책임을 할당하는 것을 PROTECTED VARIATIONS(변경 보호) 패턴이라 한다.

PROTECTED VARIATIONS 패턴
변화가 예상되는 불안정한 지점들을 식별하고, 그 주위에 안정된 인터페이스를 형성하게 책임을 할당한다.

  • 하나의 클래스가 여러 타입의 행동을 구현한다면 클래스를 분리하고, POLYMORPHISM 패턴으로 책임을 분산시킨다.
  • 예측 가능한 변경으로 여러 클래스가 불안정해진다면, PROTECTED VARIATIONS 패턴으로 안정적인 인터페이스 뒤로 변경을 캡슐화한다.
  • 이를 통해 코드 수정의 파급효과를 제어할 수 있고, 유연한 설계를 얻을 수 있다.

변경과 유연성

  • 설계를 주도하는 것은 변경
  • 개발자로서 변경에 대비할 수 있는 방법
    1. 코드를 이해하고 수정하기 쉽도록 최대한 단순하게 설계하기
    2. 변경을 수용할 수 있도록 코드를 유연하게 만들기
  • 대다수의 경우 1번이 더 좋지만, 2번을 선택해야 하는 경우가 있다.
    • 만약 할인 정책을 변경해야 한다면?
      • 지금은 상속을 사용하고 있어, 새로운 기능을 추가되면 인스턴스를 생성하고, 복사하고 등등 비효율적인 일들을 한다.
      • 이때에는 합성을 사용해 유연하게 만든다.
  • 유연성에 대한 압박이 설계에 영향을 미치고, 유연성은 결국 의존성의 정도다.

04. 책임 주도 설계의 대안

  • 책임을 빨리 찾는 방법은 빠르게 목적하는 기능을 수행하는 코드를 작성하는 것.
    • 일단 코드를 얻고 책임을 올바른 위치로 할당하는 것이 중요하다.
    • 다만, 외부에 제공하는 동작이 바뀌는 것이 아니다.
      • 캡슐화를 시키고, 응집도를 높이고, 결합도를 낮추지만 동작은 유지
      • 리팩토링(Refactoring)이라 한다

메서드 응집도

  • 데이터 중심의 시스템에서의 객체들은 단지 데이터의 집합일 뿐
    • 책임을 분배하면 책임 주도 설계와 유사할 것이다.
  • 메서드의 길이가 길고 이해하기 어렵다면
    • 응집도가 낮기때문에 유지보수 및 변경이 어렵다.
    • 이를 몬스터 메서드(Monster Method)라고 한다.
  • 로직이 이해하기 어려워 주석이 필요하다면?
    • 응집도가 낮은 메서드임을 자명하는 것.
    • 메서드를 분리해 응집도 높이는 것이 필요하다.
  • 이를 통해 이해하기 쉬운 좋은 코드가 만들어진다.

객체를 자율적으로 만들자

  • 어떤 책임을 어떤 객체에 할당하는가?
    • 객체는 자율적인 존재여야 한다.
    • 자신의 데이터를 스스로 처리하도록 만드는 것
  • 책임 주도 설계가 어색하다면
    • 데이터 중심의 설계를 만들고 리팩터링을 거쳐 책임 주도 설계로 바꿔라.

'Programming > Book Summary' 카테고리의 다른 글

[오브젝트] 5장  (0) 2020.07.11
[오브젝트] 4장  (0) 2020.07.10
[오브젝트] 3장  (0) 2020.06.24
[오브젝트] 2장  (0) 2020.06.19
[오브젝트] 1장  (0) 2020.06.18
CLEANCODE_CHAPTER5.형식 맞추기  (0) 2020.01.03

Comment +0

04. 설계 품질과 트레이드 오프

  • 객체지향 설계: 올바른 객체에게 올바른 책임을 할당하며, 낮은 결합도와 높은 응집도를 가진 구조를 창조하는 활동
    • 객체지향 설계의 핵심은 올바른 책임, 책임은 결합도와 응집도에 연관있다.
    • 설계의 변경에는 비용이 수반되나, 훌륭한 설계는 합리적인 비용 안에서 변경을 할 수 있는 구조
      • 높은 응집도와 낮은 결합도
    • 객체에 행동을 중심으로 설계한다면, 구현이 노출되지 않아 설계의 변경에 유연하다.

01. 데이터 중심의 영화 예매 시스템

  • 객체지향 설계의 두 가지 방법
    1. 상태를 중심으로 한 분할(데이터 중심)
    2. 책임을 중심으로 한 분할(우리의 목표)
  • 데이터에 중심을 둔다면, 구현에 중심을 둔 불안전한 설계
    • 이러한 사항들이 노출되어 캡슐화를 저해하고, 변경에 취약하다.

데이터를 준비하자

public class Movie {

    private String title;
    private Duration runningTime;
    private Money fee;
    private List<DiscountCondition> discountConditions;

    private MovieType movieType;
    private Money discountAmount;
    private double discountPercent;
}
  • 책임 중심 설계와 다른 점은 할인 조건 목록, 정책 등이 Movie안에 정의되고 있다.
  • 데이터 중심 설계는 객체에게 필요한 데이터에 집중한다.
  • 캡슐화를 지키기 위해 접근자(accessor), 수정자(mutator)를 추가한다.
    • 쉽게 getter, setter
  • 이러한 형태로 설계한 데이터 중심의 시스템

https://user-images.githubusercontent.com/13096845/87161015-dfc60600-c2fe-11ea-817d-085de0a72d43.png

02. 설계 트레이드오프

  • 설계를 판단하는 세가지 기준
    1. 캡슐화
    2. 응집도
    3. 결합도

캡슐화

  • 객체의 내부 구현을 숨기기 위해, 상태와 행동을 한 객체 안에 모은다.
  • 이를 통해 객체의 변화가 시스템에 주는 파급효과를 조절한다.
  • 변경의 가능성이 높은 불안한 구현과 안정적인 부분인 인터페이스
    • 알아야 할 필요 없는 부분을 감춤으로써 단순화하는 추상화 전략인 캡슐화
    • 불안한 구현을 안전한 인터페이스에 숨기는 것

응집도와 결합도

  • 모듈의 내부 요소들의 연관 정도를 나타내는 응집도
    • 하나의 목표에 얼마나 긴밀하게 협력하는가?
  • 다른 모듈에 대해 얼마나 많은 것을 아는지 나타내는 결합도
    • 서로가 어느 수준의 지식을 공유하는가?
  • 좋은 설계란? 응집도가 높고 결합도가 낮은 설계 (너무 난해하다!)
    • 각 요소가 하나의 목표를 위해 작동하고, 느슨하게 결합돼야 한다(이것도 난해하다)
    • 좋은 설계는 오늘의 기능을 수행하면서, 내일 변경을 수용할 수 있어야 한다.
  • 변경의 관점에서의 응집도는 변경이 발생 할 때 내부 모듈에서 발생하는 변경의 정도
    • 하나의 변경을 위해 한 모듈만 변경된다면 높은 응집도(얼마나 바꾸기 편한가..)
    • 응집도가 높을 수록 변경 대상과 범위가 명확해 진다.
  • 변경의 관점에서의 결합도는 한 모듈이 변경되기 위해 필요한 다른 모듈의 변경 정도
    • 결합도가 높으면 높을 수록 한 모듈을 바꾸려 할 때 바꿔야 하는 다른 모듈이 많다(끔찍)
      • 내부 구현을 변경 했을 때 외부에 영향을 준다면 결합도가 높다.
      • 인터페이스만 변경 했을 때 영향을 준다면 결합도가 낮다.
    • 즉 인터페이스에 의존해서 설계를 한다면. 결합도가 낮다.
  • 다만 성숙한 라이브러리, 프레임 워크는 결합도에 고민할 필요는 없다.
  • 하지만, 개인의 코드는 불안정
  • 캡슐화를 지킨다면 응당 응집도는 높아지고, 결합도는 낮아진다.

03. 데이터 중심의 영화 예매 시스템의 문제점

  • 기능적 측면은 동일하지만, 설계는 아니다.
  • 데이터 중심의 설계는 내부 구현을 노출한다.
    • 즉, 캡슐화를 위반 한다.
    • 따라서 낮은 응집도와 높은 결합도를 가진다.

캡슐화 위반

class Movie {
    private Money fee;

    public Money getFee() {
            return fee;
    }

    public void setFee(Money fee) {
            this.fee = fee;
    }
}
  • 캡슐화를 지키는 것 처럼 보인다. private 접근 지정자 때문에
    • 하지만, 내부 구현이 노출되어 있다.
    • 노골적으로 Money 타입의 fee라는 객체가 있음을 나타냈다.
  • 데이터 중심의 설계를 하다보면, 접근자와 수정자를 찾게 된다.
    • 과도하게 의존하는 설계 방식을 추측에 의한 설계 전략(design-by-guessing strategy)
    • This sort of design-by-guessing strategy is inefficient at best because you end up wasting time writing methods that aren’t used by.Allen Holub
    • 추측에 의한 설계는 잘해도 비효율적이다. 사용하지 않는 방법을 작성하느라 시간을 낭비하기 때문에 by.Allen Holub

높은 결합도

  • 객체 내부 구현이 인터페이스에 노출 되면서 구현에 강하게 결합됐다.
  • 단순히 내부 구현을 변경해도, 인터페이스에 의존하는 객체 혹은 클라이언트도 변경해야 한다.
  • 만약 Money 타입에서 다른 타입으로 객체를 바꾼다면?
    • 반환도 바꾸고, 받는 쪽도 바꿔야 한다.
    • 사실상 캡슐화가 이뤄지지 않았다.
    • 접근자를 둠으로써 가시성을 private에서 public으로 바꿔 캡슐화를 약화시켰다.
  • 여러 데이터 객체들을 사용하는 제어 로직이 특정 객체에 집중된다.
    • 시스템에서의 ReservationAgency
    • 어떤 객체가 바뀌더라도 ReservationAgency는 바뀐다.
  • 전체 시스템을 하나의 의존 덩어리로 만들어, 변경이 발생할 때 전체 시스템이 요동친다.

낮은 응집도

  • 서로 다른 이유로 변경되는 코드가 한 모듈 안에 있는 경우
  • 변경과 응집도 사이의 관계
    • 할인 정책이 추가될 경우
    • 할인 정책 별로 요금 계산 방법이 변경될 경우
    • 할인 조건이 추가될 경우
    • 할인 조건 별로 할인 여부를 판단하는 방법이 변경될 경우
    • 예매 요금 계산 방법이 변경될 경우
    • 위의 모든 경우에 ReservationAgency는 변경된다.
  • 변경의 이유가 다른 코드가 한 모듈 안에 있어 변경과 상관 없는 코드들이 영향을 받는다.
  • 하나의 요구 사항을 변경하기 위해 다른 모듈을 수정해야 한다.
    • 책임의 일부가 엉뚱한데 위치하기 때문에

04. 자율적인 객체를 향해

캡슐화를 지켜라

  • 객체 지향 설계의 제 1원리: 캡슐화
  • 객체 외부에서는 인터페이스에 정의된 메서드를 통해서만 상태에 접근해야 한다.
    • 이때의 메서드는 접근자와 수정자를 의미하는 게 아니다.
    • 객체가 책임져야 하는 무언가를 수행하는 메서드
    • 가시성을 private으로 설정해서 캡슐화 한 것이 아님.

스스로 자신의 데이터를 책임지는 객체

  • 객체가 어떤 데이터를 포함해야 하는가?
  • 객체가 데이터에 대해 수행해야 할 연산은 무엇인가?
  • 위 두 가지를 염두하면, 객체의 내부 상태를 저장하는 방식과 연산 집합을 얻을 수 있다.
  • 이러한 방식으로 개선한 설계

https://user-images.githubusercontent.com/13096845/87166039-f0c64580-c305-11ea-9bd3-c7aa88864aae.png

05. 하지만 여전히 부족하다.

  • 개선했지만 문제는 여전하다.

캡슐화 위반

  • 여전히 상태를 인터페이스에 노출하는 DiscountCondition
  • 만약 수정해야 한다면?
    • 해당 메서드를 사용하는 클라이언트도 함께 수정해야 하는 파급효과가 발생한다.
    • 파급 효과는 캡슐화가 부족했다는 증거

높은 결합도

  • 캡슐화 위반으로 내부 구현이 외부로 노출됐기 때문에 결합도는 높을 수 밖에 없다.
    • 즉, 한 모듈의 구현이 변경될 때 다른 모듈의 변경의 영향이 전파될 확률이 높다.

낮은 응집도

  • 캡슐화 위반으로 높은 결합도가 생겼고, 할인 조건 변경이 Movie, Screening까지 영향을 미친다.
  • 모든 문제는 캡슐화 위반에서 시작된다.

06. 데이터 중심의 설계의 문제점

  • 데이터 중심의 설계는 변경에 취약하다.
    1. 본질적으로 너무 빠른 시기에 데이터에 관해 결정하도록 강요한다.
    2. 협력이라는 문맥이 없이 객체를 독립된 섬으로 만들고, 연산을 결정한다.

'Programming > Book Summary' 카테고리의 다른 글

[오브젝트] 5장  (0) 2020.07.11
[오브젝트] 4장  (0) 2020.07.10
[오브젝트] 3장  (0) 2020.06.24
[오브젝트] 2장  (0) 2020.06.19
[오브젝트] 1장  (0) 2020.06.18
CLEANCODE_CHAPTER5.형식 맞추기  (0) 2020.01.03

Comment +0

[Velog] (https://velog.io/@pandahun/Programmers-2020-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%9D%B8%ED%84%B4%EC%8B%AD-%EC%88%98%EC%8B%9D-%EC%B5%9C%EB%8C%80%ED%99%94)

 

[Programmers] 2020 카카오 인턴십 - 수식 최대화

카카오 인턴십 코딩테스트 - 수식 최대화

velog.io

 

Comment +0