동시성이 필요한 이유 동시성은 결합을 없애는 전략. 즉, 무엇과 언제를 분리하는 전략이다. 스레드가 하나인 프로그램은 무엇과 언제가 서로 밀접하다. 구조적 관점에서 프로그램은 거대한 루프 하나가 아니라, 작은 협력 프로그램 여럿으로 구성되어 있어 무엇과 언제를 분리하면 애플리케이션 구조와 효율이 극적으로 나아진다. 따라서 시스템을 이해하기 쉽고 문제를 분리하기도 쉬워진다. 장점 구조적 개선 응답 시간과 작업 처리량 개선 동시성이 필요한 이유 동시성은 결합을 없애는 전략. 즉, 무엇과 언제를 분리하는 전략이다. 스레드가 하나인 프로그램은 무엇과 언제가 서로 밀접하다. 구조적 관점에서 프로그램은 거대한 루프 하나가 아니라, 작은 협력 프로그램 여럿으로 구성되어 있어 무엇과 언제를 분리하면 애플리케이션 구조와..
단순한 설계 규칙 1. 모든 테스트를 실행하라 설계는 의도한 대로 돌아가는 시스템을 내놓아야 한다. 문서로는 시스템을 완벽하게 설계했지만, 시스템이 의도한 대로 돌아가는지 검증할 간단한 방법이 없다면 문서 작성을 위해 투자한 노력에 대한 가치는 인정받기 힘들다. 테스트가 불가능한 시스템은 검증도 불가능하다. 이러한 검증 불가 시스템은 절대 출시하면 안된다. 테스트가 (쉽게) 가능한 시스템을 만들려고 애쓰면 설계 품질이 더불어 높아진다. 크기가 작고 하나의 목적만을 수행하는 클래스 SRP 를 준수하는 클래스 테스트가 많을수록 개발자는 테스트가 쉬워지게 하는 코드를 작성하는데, 이렇게 철저한 테스트가 가능한 시스템을 만들면 더 나은 설계가 얻어진다. 결합도가 높으면 테스트 케이스를 작성하기 어렵다. 그러므로..
시스템 제작과 시스템 사용을 분리 소프트웨어 시스템은 애플리케이션 객체를 제작하고 의존성을 서로 연결하는 준비 과정과, 이후에 이어지는 런타임 로직을 분리해야 한다. 이러한 관심사 분리는 우리 분야에서 가장 오래되고 가장 중요한 설계 기법 중 하나이다. 시작 단계는 모든 애플리케이션이 풀어야 할 관심사. 그러나 대다수 애플리케이션은 시작 단계라는 관심사를 분리하지 않는다. ex) 초기화 지연 fun getService(): Service { return service ?: MyServiceImpl() } 이러한 기법은 장.단점이 존재한다. 장점 실제로 필요할 때까지 객체를 생성하지 않아서 불필요한 부하를 줄여주고, 그로 인해 애플리케이션 시작 시간이 빨라진다. 단점 getService 메서드가 MySer..
클래스 체계 클래스를 정의하는 표준 자바 관례 변수 목록 정적 공개 변수(static public) 정적 비공개 변수(private) 비공개 인스턴스 변수 공개 변수(필요한 경우는 거의 없음) 공개 함수 변수 목록 다음에는 공개함수가 나온다. 비공개 함수는 자신을 호출하는 공개 함수 직후에 넣는다. -> 추상화 단계가 순차적으로 내려가서 프로그램은 신문 기사처럼 읽힌다. 캡슐화 변수와 유틸리티 함수는 가능한 공개하지 않는 편이 낫지만, 반드시 숨겨야 한다는 법칙도 없다. 그러나 비공개 상태를 유지할 온갖 방법을 강구한 후, 캡슐화를 풀어주는 결정은 언제나 최후의 수단이 되어야 한다. 클래스는 작아야 한다. 클래스를 만들 때 가장 중요한 규칙은 크기가 작아야 한다는 것 얼마나 작아야 하는가 에 대한 기준으..
TDD 법칙 세 가지 실패하는 단위 테스트를 작성할 때까지 실제 코드 작성하지 않기 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성 현재 실패하는 테스트를 통과할 정도로만 실제 코드 작성 이렇게 일하면 실제 코드를 사실상 전부 테스트하는 테스트 케이스가 나온다. 하지만 실제 코드와 맞먹을 정도로 방대한 테스트 코드는 심각한 관리 문제를 유발하기도 한다. 깨끗한 테스트 코드 유지하기 지저분한 테스트 코드를 내놓는 것은 테스트를 안하는 것과 같다. 오히려 더 못하다! 실제 코드가 진화하면 테스트 코드도 같이 변해야 하는데, 테스트 코드가 복잡할수록 실제 코드를 짜는 시간보다 테스트 케이스를 추가하는 시간이 더 걸리게 된다. 실제 코드를 변경해 기존 테스트 케이스가 실패하기 시작하면, ..
외부 코드 사용하기 패키지/프레임워크 제공자는 적용성을 최대한 넓히려고 하고, 사용자는 자신의 요구에 집중하는 인터페이스를 바란다. 이러한 긴장으로 인해 시스템 경계에서 문제가 생길 소지가 많다. 예를 들어 Map 인터페이스를 들 수 있다. Map 객체를 사용하는 사람은 누구나 내용을 지울 수도 있고, 새로운 값을 추가할 수 있다. 즉, Map 이 반환하는 Object 를 올바른 유형으로 변환할 책임은 Map 을 사용하는 클라이언트에 있다. 이러한 Map 인스턴스를 여기저기로 넘긴다면, Map 인터페이스가 변할 경우 수정할 코드가 상당히 많아지는 문제가 생긴다. (실제로 자바 5가 제네릭스 지원하면서 Map 인터페이스가 변했었다.) 따라서 Map 과 같은 경계 인터페이스를 이용할 때는 이를 이용하는 클래..