프로그래밍 <12>
단일 스레드는 콜 스택을 살펴보면 프로그램 상태가 바로 드러난다. 반면 멀티 스레드는 구조적인 관점에서 보면 하나의 루프가 아니라 작은 프로그램 여러 개가 돌고 있는 것으로 보인다. 시스템을 이해하기가 쉽고 문제를 분리하기도 쉽다. - 동시성이 필요한 이유? : 처리 속도의 향상 - 난관 : 동시성은 복잡하다. : 동시성 버그는 재현하기 어렵다. - 동시성 방어 원칙 : 동시성 코드는 다른 코드와 분리해야 한다. : 자료를 캡슐화하고 공유 자료(critical section)를 최대한 줄여야 한다. : 공유 객체를 복사해 읽기 전용으로 사용. : 스레드는 가능한 독립적으로 구현. (각 스레드는 클라이언트 요청 하나를 처리한다. 데이터는 로컬 변수에 저장. 다른 스레드와 동기화할 필요 없으므로 하나의 프로..
창발성 (창발성이란 창발된 성질이나 실체와 같은 대상들이 더 근본적인 대상들로부터 발생하지만, 근본적인 대상으로 환원되지 않으며 그 자체로 특수한 지위를 차지하는 것을 의미한다.) - 모든 테스트를 실행한다. : 결합도가 높으면 테스트 케이스를 작성하기 어렵다. (즉, 테스트 케이스를 많이 작성할수록 결합도를 낮출 수 있다.) : 테스트 케이스를 많이 만들수록 낮은 결합도와 늪은 응집력을 달성할 수 있다. : 테스트 케이스 작성 -> 코드와 클래스 정리(리팩토링) -> 응집도 높이고 결합도 낮추고 책임 분리, 함수와 클래스 크기 줄이고 더 나은 이름 선택 등 - 중복을 없앤다. : 중복은 추가 작업, 추가 위험, 불필요한 복잡도를 뜻한다. - 프로그래머 의도를 표현한다. : 좋은 이름 : 함수와 클래스 ..
- 시스템 제작과 시스템 사용을 분리하라 public Service getService() { if (service == null) { service = new MyServiceImpl(...) } return service; } 위 코드는 초기화 지연(Lazy Initialization), 계산 지연(Lazy Evaluation)이라는 기법이다. 장 : 실제로 필요할 때까지 객체를 생성하지 않음 (부하 감소), 어떤 경우에도 null 포인터를 반환하지 않음 단 : getService 함수가 MyServiceImpl과 생성자 인수에 의존한다. 테스트시에 테스트 전용 객체가 필요하다. 런타임 로직에 객체 생성 로직이 있기 때문에 service가 null인 경우와 null이 아닌 경우를 모두 테스트해야 한다..
- 클래스 체계 : 변수 public static -> private static -> private : 함수 public -> private : 캡슐화 - 변수와 유틸리티 함수는 가능한 공개하지 않는 편이 좋다. - 클래스는 작아야 한다. : 클래스 이름에 Processor, Manager, Super 등과 같이 모호한 단어가 있다면 클래스에 여러 책임을 떠맡겼다. : 단일 책임 원칙(Single Responsibility Principle) - 변경할 이유가 하나여야 한다. - 응집도 : 응집도가 높다는 것은 클래스에 속한 함수와 변수가 서로 의존하며 논리적인 단위로 묶인다는 의미이다. : 응집도를 유지하면 작은 클래스 여럿이 나온다 - 클래스가 응집력을 잃는다면 쪼개라. - 변경하기 쉬운 클래스 :..
- TDD 법칙 세 가지 : 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다. : 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다. : 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다. - 깨끗한 테스트 코드 유지하기 : 가독성이 좋아야 한다. (명료, 단순) : 도메인에 특화된 테스트 언어를 사용 하자. (시스템 API를 사용하는 대신 유틸리티를 구현해서 사용) : 메모리, CPU 효율을 신경 쓰지 않아도 된다. - 테스트 당 assert 하나 : 테스트 함수 하나에서는 하나의 개념만 테스트하라 : 즉. 개념 당 assert 문 수를 최소로 줄여라. - F.I.R.S.T. : Fast - 테스트는 빨라야 한다. : Independent - 테스트..
시스템에 들어가는 모든 소프트웨어를 직접 개발하는 경우는 드물다. 외부 코드(패키지, 오픈 소스, 다른 팀의 컴포넌트)를 우리 코드에 깔끔하게 통합하기 - 외부 코드 사용하기 : 외부 코드를 이용하는 클래스나 클래스 계열 밖으로 외부 코드가 노출되지 않도록 주의한다. - 외부 코드 살피고 익히기 : 간단한 테스트 케이스를 작성해 외부 코드를 익힌다. - 아직 존재하지 않는 코드를 사용하기 : ADAPTER 패턴을 사용해 미래에 작성될 외부 코드에 따라 변경될 사항을 한 곳으로 모음. - 깨끗한 경계 : 외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자. : ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환