클린코드 - 13.동시성

2022-02-27

동시성

동시성과 깔끔한 코드는 양립하기 어렵다. 스레드를 하나만 실행하는 코드는 짜기가 쉽다. 겉으로 보기에는 멀쩡하나 깊숙한 곳에 문제가 있는 다중 스레드 코드도 짜기 쉽다. 이런 코드는 시스템이 부하를 받기 전까지 멀쩡하게 돌아간다.


Read More

클린코드 - 12.창발성

2022-02-27

창발성

  • 창발적 설계로 깔끔한 코드를 구현하자
    • 모든 테스트를 실행한다.
    • 중복을 없앤다.
    • 프로그래머 의도를 표현한다.
    • 클래스와 메서드 수를 최소로 줄인다.
  • 단순한 설계 규칙 1: 모든 테스트를 실행하라
    • 설계는 의도한 대로 돌아가는 시스템을 내놓아야 한다.
    • 테스트를 철저히 거쳐 모든 테스트 케이스를 항상 통과하는 시스템은 ‘테스트가 가능한 시스템’이다.
    • 테스트가 가능한 시스템을 만들려고 애쓰면 설계 품질이 더불어 높아진다.
    • 테스트 케이스가 많을수록 개발자는 테스트가 쉽게 코드를 작성한다.
    • 철저한 테스트가 가능한 시스템을 만들면 더 나은 설계가 얻어진다.
    • 결합도가 높으면 테스트 케이스를 작성하기 어렵다.
    • 테스트 케이스를 작성하면 설계 품질이 높아진다.
  • 단순한 설계 규칙 2~4: 리팩터링
    • 테스트 케이스를 모두 작성했다면 코드와 클래스를 정리해도 괜찮다. 구체적으로는 코드를 점진적으로 리팩터링 해나간다.
    • 코드를 정리하면서 시스템이 깨질까 걱정할 필요가 없다. 테스트 케이스가 있으니까!
    • 리팩터링 단계에서는 소프트웨어 설계 품질을 높이는 기법이라면 무엇이든 적용해도 괜찮다.
    • 응집도를 높이고, 결합도를 낮추고, 관심사를 분리하고, 시스템 관심사를 모듈로 나누고, 함수와 클래스 크기를 줄이고, 더 나은 이름을 선택하는 등 다양한 기법을 동원한다.
    • 또한 이 단계는 중복을 제거하고, 프로그래머 의도를 표현하고, 클래스와 메서드 수를 최소로 줄이는 단계이기도 하다.
  • 중복을 없애라
    • 중복은 추가 작업, 추가 위험, 불필요한 복잡도를 뜻한다.
    • 깔끔한 시스템을 만들려면 단 몇 줄이라도 중복을 제거하겠다는 의지가 필요하다.
    • 소규모 재사용은 시스템 복잡도를 극적으로 줄여준다. 소규모 재사용을 제대로 익혀야 대규모 재사용이 가능하다.
  • 표현하라
    • 소프트웨어 프로젝트 비용 중 대다수는 장기적인 유지보수에 들어간다.
    • 코드는 개발자의 의도를 분명히 표현해야 한다. 개발자가 코드를 명백하게 짤수록 다른 사람이 그 코드를 이해하기 쉬워진다. 그래야 결함이 줄어들고 유지 보수 비용이 적게 든다.
    • 좋은 이름을 선택한다.
    • 함수와 클래스 크기를 가능한 줄인다.
    • 표준 명칭을 사용한다.
    • 단위 테스트 케이스를 꼼꼼히 작성한다. 테스트 케이스는 소위 ‘예제로 보여주는 문서’다.
    • 표현력을 높이는 가장 중요한 방법은 노력이다. 나중에 읽을 사람을 고려해 조금이라도 읽기 쉽게 만들자.
  • 클래스와 메서드 수를 최소로 줄여라
    • 함수와 클래스 크기를 작게 유지하면서 동시에 시스템 크기도 작게 유지할 수 있다.

Read More

클린코드 - 11.시스템

2022-02-27

시스템

“복잡성은 죽음이다. 개발자에게서 생기를 앗아가며, 제품을 계획하고 제작하고 테스트하기 어렵게 만든다.”
-> 레이 오지(Ray Ozzie), 마이크로소프트 최고 기술 책임자(CTO)


Read More

클린코드 - 10.클래스

2022-02-27

클래스

  • 클래스 체계
    • 클래스를 정의하는 표준 자바 관례에 따르면, 가장 먼저 변수 목록이 나온다. 정적(static) 공개(public) 상수가 있다면 맨 처음에 나온다. 다음으로 정적 비공개(private) 변수가 나오며, 이어서 비공개 인스턴스 변수가 나온다. 공개 변수가 필요한 경우는 거의 없다.
    • 변수 목록 다음에는 공개 함수가 나온다. 비공개 함수는 자신을 호출하는 공개 함수 직후에 넣는다. 즉, 추상화 단계가 순차적으로 내려간다.
    • 변수와 유틸리티 함수는 가능한 공개하지 않는 편이 낫지만 반드시 숨겨야 한다는 법칙도 없다. 캡슐화를 풀어주는 결정은 언제나 최후의 수단이다.
  • 클래스는 작아야 한다!
    • 클래스를 설계할 때도, 함수와 마찬가지로, ‘작게’가 기본 규칙이다.
    • 클래스 이름은 해당 클래스 책임을 기술해야 한다.
    • 클래스는 책임, 즉 변경할 이유가 하나여야 한다.(단일 책임 원칙)
    • 응집도가 높은 클래스를 선호한다. 응집도가 높다는 말은 클래스에 속한 메서드와 변수가 서로 의존하며 논리적인 단위로 묶인다는 의미기 때문이다.
    • 응집도를 유지하면 작은 클래스 여럿이 나온다.
  • 변경하기 쉬운 클래스
    • 새 기능을 수정하거나 기존 기능을 변경할 때 건드릴 코드가 최소인 시스템 구조가 바람직하다.(개방 폐쇄 원칙)
    • 이상적인 시스템이라면 새 기능을 추가할 때 시스템을 확장할 뿐 기존 코드를 변경하지는 않는다.(개방 폐쇄 원칙)
    • 상세한 구현에 의존하는 코드는 테스트가 어렵다. 테스트가 가능할 정도로 시스템의 결합도를 낮추면 유연성과 재사용성도 더욱 높아진다. 결합도가 낮다는 소리는 각 시스템 요소가 다른 요소로부터 그리고 변경으로부터 잘 격리되어 있다는 의미다. 시스템 요소가 서로 잘 격리되어 있으면 각 요소를 이해하기도 더 쉬워진다.
    • 결합도를 최소로 줄이면 자연습럽게 의존 역전 원칙을 따르는 클래스가 나온다. 의존 역전 원칙은 클래스가 상세한 구현이 아니라 추상화에 의존해야 한다는 원칙이다.
Read More

클린코드 - 9.단위 테스트

2022-02-27

단위 테스트

  • TDD 법칙 세 가지
    • 첫째 법칙: 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
    • 둘째 법칙: 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
    • 셋째 법칙: 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
  • 깨끗한 테스트 코드 유지하기
    • 테스트 코드는 실제 코드 못지 않게 중요하다.
    • 테스트는 유연성, 유지보서성, 재사용성을 제공한다. 테스트 케이스가 있으면 변경이 두렵지 않기 때문이다.
    • 실제 코드를 점검하는 자동화된 단위 테스트 슈트는 설계와 아키텍처를 최대한 깨끗하게 보존하는 열쇠다.
  • 깨끗한 테스트 코드
    • 깨끗한 테스트 코드를 만들려면 세 가지가 필요하다. 가독성, 가독성, 가독성. 어쩌면 가독성은 실제 코드보다 테스트 코드에 더더욱 중요하다.
    • 테스트 코드에서 가독성을 높이려면 명료성, 단순성, 풍부한 표현력이 필요하다.
    • 각 테스트는 세 부분으로 나눠진다. 첫 부분은 테스트 자료를 만든다. 두 번째 부분은 테스트 자료를 조작하며, 세 번째 부분은 조작한 결과가 올바른지 확인한다.
  • 테스트 당 assert 하나
    • assert 문이 단 하나인 함수는 결론이 하나라서 코드를 이해하기 쉽고 빠르다.
    • 때로는 함수 하나에 여러 assert 문을 넣을 수도 있지만 최대한 줄여야 좋다.
    • 테스트 함수마다 한 개념만 테스트하라
  • F.I.R.S.T
    • 빠르게(Fast): 테스트는 빨라야 한다. 테스트는 빨리 돌아야 한다는 말이다. 테스트가 느리면 자주 돌릴 엄두를 못 낸다. 자주 돌리지 않으면 초반에 문제를 찾아내 고치지 못한다. 코드를 마음껏 정리하지도 못한다. 결국 코드 품질이 망가지기 시작한다.
    • 독립적으로(Independent): 각 테스트는 서로 의존하면 안 된다. 한 테스트가 다음 테스트가 실행될 환경을 준비해서는 안 된다. 각 테스트는 독립적으로 그리고 어떤 순서로 실행해도 괜찮아야 한다. 테스트가 서로에게 의존하면 하나가 실패할 때 나머지도 잇달아 실패하므로 원인을 진단하기 어려워지며 후반 테스트가 찾아내야 할 결함이 숨겨진다.
    • 반복가능하게(Repeatable): 테스트는 어떤 환경에서도 반복 가능해야 한다. 실제 환경, QA 환경, 버스를 타고 집으로 가는 길에 사용하는 (네트워크에 연결되지 않은) 노트북 환경에서도 실행할 수 있어야 한다. 테스트가 돌아가지 않는 환경이 하나라도 있다면 테스트가 실패한 이유를 둘러댈 변명이 생긴다. 게다가 환경이 지원되지 않기에 테스트를 수행하지 못하는 상황에 직면한다.
    • 자가검증하는(Self-Validating): 테스트는 부울(bool) 값으로 결과를 내야 한다. 성공 아니면 실패다. 통과 여부를 알려고 로그 파일을 읽게 만들어서는 안 된다. 통과 여부를 보려고 텍스트 파일 두 개를 수작업으로 비교하게 만들어서도 안 된다. 테스트가 스스로 성공과 실패를 가늠하지 않는다면 판단은 주관적이 되며 지루한 수작업 평가가 필요하게 된다.
    • 적시에(Timely): 테스트는 적시에 작성해야 한다. 단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다. 실제 코드를 구현한 다음에 테스트 코드를 만들면 실제 코드가 테스트하기 어렵다는 사실을 발견할지도 모른다. 어떤 실제 코드는 테스트하기 너무 어렵다고 판명날지 모른다. 테스트가 불가능하도록 실제 코드를 설계할지도 모른다.

Read More