본문 바로가기
better code

Clean Code (5/n)

by marble25 2022. 2. 21.

오늘 계속해서 Clean Code 책을 읽어서 마무리지어 보았다.

 

13. 동시성

동시성이라는 개념은 구현하기 어려운 개념인 것 같다. 

사실 간단한 멀티 쓰레드 프로그램은 hands-on으로 쉽게 구현할 수 있지만, 임계 영역을 설정하고 동시 접근에 대한 깊이있는 고려를 한다면 그 자체가 하나의 연구 주제가 될 정도로 어렵다.

이 챕터에서는 동시성을 어떻게 깔끔하고 올바르게 구현할 수 있을지에 대해 설명하고 있다.

 

동시성은 꼭 필요한 상황에서만 사용해야 한다

일반적으로 생각했을 때, 동시성을 사용한다면 당연히 성능이 높아진다고 생각할 수 있다.

대기시간이 길어서 여러 스레드 간에 스위칭이 발생해도 괜찮거나, 프로세서가 동시에 처리할 독립적인 계산이 있을 때는 성능이 높아지는 것이 맞다.

하지만, 이는 운영체제 입장에서는 옳지 않다.

스레드 컨텍스트 스위칭을 할 때 비용이 발생하기 때문에, 이 부분에서 부하가 걸리며, 코드 역시 더 길어지고 복잡해질 수밖에 없다.

또한, critical section에 진입하는 순서로 인한 데드락, 라이브락 등 동시성을 사용해서 생기는 다양한 버그를 해결하기는 쉽지 않다.

따라서 문제를 잘 정의해보고 동시성이 꼭 필요한 상황에만 적용해 보아야 한다.

 

공유되는 자료를 줄여라

공유된 자료가 많아진다면 공유 자료에 접근했을 때마다 critical section이 제대로 설정되었는지 확인해 보아야 한다.

하지만 작업하다 보면 critical section을 빼먹는 경우도 많고, 적절하게 보호했는지 확인하기 쉽지 않다.

무엇보다 동시성 관련해서 발생하는 버그는 찾기 쉽지 않기 때문에 공유되는 자료 자체를 줄이는 것이 좋다.

공유 자료를 줄이고 독립적인 단위로 분할할 수 있는지 확인해 보자.

 

Critical section과 공유되는 자료를 줄여라

critical section은 둘 이상의 스레드가 동시에 접근해서는 안되는 영역으로, 최대 하나의 스레드만 접근할 수 있는 영역이다.

일반적으로 공유된 자료를 read/write하는 경우에 사용한다.

이런 critical section이 많아질 수록 동시성 개념이 희미해지고, 동시성을 사용했을 때의 성능상 장점이 사라진다. 

 

테스트 코드를 잘 작성하자

테스트 코드의 중요성은 거듭 강조해도 모자람이 없다.

설사, TDD가 아닌 일반 애자일 방식의 개발이라도 말이다.

스레드 코드는 테스트 코드를 작성하기 쉽지 않은데, 일반적인 순차 코드와는 다르게 버그가 실행할 때마다 생겼다가 안 생겼다가 하는 경우가 있기 때문이다.

스레드 코드에 잠입한 버그는 수천 번에 한 번씩 드러나는 경우도 있고, 심지어는 수백만 번에 한 번씩 드러나는 경우도 있다.

이런 일회성 버그들을 단순 '일회성'으로 치부하지 않고 해결해 나가는 것이 중요하다.

또한, 다양한 상황에서, 부하를 다양하게 걸어 보면서 테스트해보는 것이 중요하다. 

멀티 플랫폼에서, 수많은 스레드를 돌려 보는 테스트 코드를 작성해 보자.

 

17. 냄새와 휴리스틱

앞서 나왔던 14, 15, 16장은 실제로 코드를 주고 리팩토링해보는 형식으로 되어 있어서 생략하고, 바로 17장으로 넘어갔다.

사실상 이 책을 요약해 보았을 때 핵심 내용이 이 파트에 다 있는 것 같았다.

그래서 이 책에서 가장 중요한 부분이 아니지 않을까 싶었다.

대부분의 내용은 앞에서 다 설명을 했기 때문에 간단하게 정리를 해 보자.

 

  • 주석에 쓸모 없거나 부적절한 정보를 넣지 말자 
  • 코드 주석은 never!
  • 빌드와 테스트는 간단히 할 수 있어야 한다
  • 함수의 인수는 적을 수록 좋다.
  • 출력 인수와 플래그 인수는 되도록 없애자.
  • 사용하지 않는 코드는 없애자.
  • 한 소스 파일에 되도록 여러 개의 언어를 사용하지 않는다.
  • 경계 조건(예외나 잘 일어나지 않는 case)도 잘 처리한다.
  • 중복 X
  • 상위 클래스가 하위 클래스에 의존해서는 안 된다. 
  • 변수와 함수는 실행되는 위치에 가깝게 정의한다.
  • 함수는 자신의 이름이 드러내는 하나의 역할만 잘 하자!
  • 복잡한 계산의 경우 계산을 몇 단계로 나누어 서술적인 변수를 붙여주자. 이해하기 한결 쉬워질 것이다.
  • 업계에서 사용하는 용어를 가급적 따르자.
  • 의미가 있는 숫자는 상수로!
  • 복잡한 if문 조건은 캡슐화해서 함수로 만들어 보자. 
  • 부정 조건은 피하자!
  • 설정값들은 최상위 클래스에 두자.
  • 다른 코드와의 일관성을 유지하자.
  • 경계 조건을 빼먹지 않도록 캡슐화하자. ex) int nextLevel = level + 1
  • 불필요한 정보를 변수에 인코딩하지 말자. ex) m_: 멤버 변수
  • 테스트 커버리지 도구를 사용해서 테스트가 충분한 케이스들을 커버할 수 있도록 한다.
  • 경계 조건을 철저히 테스트하자.
  • 테스트는 빨라야 한다!

위에 말한 것만 명심하더라도 한 단계 성장한 프로그래머가 될 수 있을 것 같다.

지금까지 Clean Code를 읽으면서 뒤죽박죽이었던 내용이 한 번에 정리된 느낌이었다.

Clean Code를 항상 의식하면서 코드를 작성하고, 돌아가는 코드더라도 한번 더 생각해서 수정해 본다면 '냄새나는 코드'가 되지 않을 수 있지 않을까?

그런 면에서 보았을 때, Clean Code는 나에게 유익한 책이었던 것 같다.

이렇게 5편에 달하는 클린 코드 책 리뷰를 마친다.

'better code' 카테고리의 다른 글

객체지향의 사실과 오해  (0) 2023.07.02
[TIL] copy-on-write 방법론 - js에서 퍼포먼스 테스트  (0) 2023.04.22
Clean Code (4/n)  (0) 2022.02.16
Clean Code (3/n)  (0) 2022.02.11
Clean Code (2/n)  (0) 2022.02.07