Skip to content

Commit 345acc2

Browse files
authored
release: v1.0.9
## Description + 도서 디렉토리 구조 변경 + 도서 리뷰 추가 + 학습내용 추가 ## Related Issues partly resolved #54 resolved #60
2 parents d9c3186 + da1cbda commit 345acc2

File tree

40 files changed

+3682
-1185
lines changed

40 files changed

+3682
-1185
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
title: "클린 코드 스터디 (1): 깨끗한 코드"
3+
date: "2023-01-06T22:51:00.000Z"
4+
template: "post"
5+
draft: false
6+
slug: "/books/clean-code/2023-01-06-pt01"
7+
category: "devlog"
8+
tags:
9+
- "book_review"
10+
- "code_quality"
11+
description: "2023년 1월부터 시작한 클린 코드 독파 스터디 후, 매 모임 전 준비하는 게시글을 공유합니다. 이 글은 1장, 깨끗한 코드에 대해 알아봅니다."
12+
socialImage: { "publicURL": "./media/water.jpg" }
13+
---
14+
15+
# 1. 깨끗한 코드
16+
17+
ChatGPT로 기술 발전이 무섭게 발전하는 지금, 기계가 못하는 것을 할 수 있도록 하기 위해 이 책을 폈습니다. 우리는 기계보다 나은 코드를 짜도록 연마해야할 것입니다.
18+
19+
코드는 요구사항을 표현하기 위한 도구이며, 각 요구사항을 표현하기 위한 언어 또한 늘어나겠지요. 막연한 요구사항을 구체화하고, 이를 잘 풀어내는 것은 (아직은) 인간이 할 수 있는 것입니다. 그런고로, 잘 풀어내는 방법을 배워봅시다.
20+
21+
나쁜코드가 왜 좋지 않은지 이야기해봅시다. 이 글을 읽으시는 모든 분들은 '나쁜 코드를 어떻게 좋게 바꾸지?' 하고 고민하던 때가 있었을 것입니다.
22+
23+
1. 급하다고 막 짠 코드로, '이거 돈다!' 하는게 쌓이면 돌이킬 수 없습니다. 나중에 하자? **나중은 없습니다.** 실용주의 프로그래머에도 이런 말이 나옵니다: '깨진 유리창을 가만 두지 마라'.
24+
25+
2. 이런 나쁜 코드가 쌓이면 팀 생산성이 떨어집니다.
26+
27+
3. 설령 기회를 얻어, 나쁜 코드를 고칠 기회가 오더라도 모두 고치기는 쉽지 않을 것입니다.
28+
29+
4. 나쁜 코드를 유도하는 **나쁜 설계**를 유도하지 않도록 해야합니다. 좋은 설계에서 좋은 코드가 나올 수 있고, 좋은 코드를 유지하는 것 또한 좋은 설계의 일환입니다.
30+
31+
그런 의미로 코드를 잘 짜는 예술(Art)이 있다는 말에 어느정도 동의합니다. 아름다운 코드는 어떤 *감각*이라고 합니다. 아니 코드에 무슨 미학이 있는것도 아니고? 하는 생각이 들었는데, 수퍼스타들의 말을 읽어보니 납득이 됐습니다.
32+
33+
## 이 바닥 슈퍼스타들은...
34+
35+
1. Bjarne Stroustrup, (C++의 아버지)
36+
1. 우아하고 효율적인 코드
37+
2. 의존성을 줄이라
38+
3. 오류를 전략적으로 처리하라
39+
4. 성능은 최적으로. 그렇다고 원칙없이 잘 돌아가는 코드를 짜면 안됨
40+
5. 하나의 코드는 하나의 작동을 한다
41+
2. [Grady Booch](https://zetawiki.com/wiki/%EA%B7%B8%EB%9E%98%EB%94%94_%EB%B6%80%EC%B9%98) (Object Oriented Analysis and Design with Application](https://product.kyobobook.co.kr/detail/S000006439884)[1]의 저자)
42+
1. 단순하고 직접적이다.
43+
2. 잘 쓴 문장처럼 읽힌다.
44+
3. 설계자의 의도가 바로 드러난다.
45+
4. 명쾌한 추상화와 제어문으로 가득하다.
46+
3. Dave A. Thomas(aka. "Big" Dave Thomas) (OTI의 창립자이자 이클립스 전략의 Godfather)
47+
1. 안 짠 사람도 읽기 쉽고 고치기 쉽다.
48+
2. 유닛 테스트부터 인수 테스트까지 다 있다.
49+
3. 의미 있는 이름이 붙는다.
50+
4. 코드를 통해 목적을 달성하는 방법은 명확한 하나만 제공된다.
51+
5. API는 concise하다.
52+
6. 어떤 면에서는 문학적이다. 모든 정보를 코드로 풀 수 없기 때문이다. → 사람이 읽기 쉬운 코드라는 뜻
53+
4. Michale Feathers ([Working Effectively with Legacy Code](https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052)[2] 의 저자)
54+
1. 손댈 곳이 없어보이는 코드를 짜자
55+
2. 주의깊게 보이는 코드
56+
5. Ron Jeffries (Extreme Programming Installed, Extreme Progreaaming Adventure in C#의 저자)
57+
1. 모든 테스트를 통과한다
58+
2. 중복코드가 없다
59+
3. 시스템 내 모든 설계 아이디어를 표현한다
60+
4. 클래스, 메소드, 함수를 최소한으로 한다
61+
6. Ward Cunningham (위키의 창시자, 익스트림 프로그래밍의 공동 창시자, OO의 정신적 지주)
62+
1. 루틴대로 도는 코드 → 의도가 명확한 코드
63+
2. 문제를 풀기위해 보이는 코드
64+
7. Robert C. Martin (aka. 밥 아저씨) (이 책의 저자)
65+
1. 앞으로의 내용은 책을 보면 알 것
66+
1. 절대적인 것은 없으나, 상황에 맞는 기술과 기법을 익히길 바람
67+
68+
## 코드작성에 대한 태도
69+
70+
- Javadoc에는 `@author` 필드가 있습니다. 우리는 수차례 코드를 읽고 씁니다. 좋은 글을 쓰기 위한 작가로서의 책임감을 가질 필요가 있습니다.
71+
- 보이스카우트 규칙을 기억하세요.
72+
- _'캠프장은 처음 왔을 때보다 더 깨끗하게 하고 나갈 것.'_
73+
- 이는 '처음 왔을 때보다 *더 나은 세상*을 만들고 떠나려 노력하라. (후략)' 라는 말에서 나왔다네요. 낭만이 있습니다...
74+
75+
# 논외로
76+
77+
- [클린 코드 같은 건 없다!](https://www.steveonstuff.com/2022/01/27/no-such-thing-as-clean-code) 하는 당찬 제목이 있던데, 읽어보면 이 말입니다.
78+
79+
- 업계마다 원하는게 다르고, 그에 따라 간결한 코드를 짜는 방법은 _모두에게 다르게 적용됩니다_.
80+
- 때에 맞는 기술을 잘 선택해야 _깨끗하다_ 할 수 있습니다.
81+
82+
- 원작자의 마지막 멘트로 이 글을 마무리합니다.
83+
84+
> Hopefully I can convince you that you don’t really need clean code, you need `_____` code. It’s up to you to fill in that blank with words that describe what your project requires.
85+
86+
---
87+
88+
[1]: [이 링크](https://soniacomp.medium.com/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%A0%81-%EB%B6%84%EC%84%9D%EA%B3%BC-%EB%94%94%EC%9E%90%EC%9D%B8-object-oriented-analysis-and-design-%EC%86%8C%EA%B0%9C-part-1-%EB%B2%88%EC%97%AD-67ff58fd26c9)를 참고하십시오. UML을 만든 사람 중 하나이며, 객체간의 메시지 교환, 책임, 협업과 같은 요소가 있어서 객체지향의 사실과 오해, 오브젝트에서도 언급이 되었을 것입니다.
89+
90+
[2]: 이 링크를 참조하십시오.
53.1 KB
Loading
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
---
2+
title: "클린 코드 스터디 (2): 의미있는 코드"
3+
date: "2023-01-06T22:59:00.000Z"
4+
template: "post"
5+
draft: false
6+
slug: "/books/clean-code/2023-01-06-pt01"
7+
category: "devlog"
8+
tags:
9+
- "book_review"
10+
- "code_quality"
11+
description: "2023년 1월부터 시작한 클린 코드 독파 스터디 후, 매 모임 전 준비하는 게시글을 공유합니다. 이 글은 2장, 의미있는 코드에 대해 설명합니다."
12+
socialImage: { "publicURL": "./media/water.jpg" }
13+
---
14+
15+
# 2. 의미있는 코드
16+
17+
의미있는 코드 이름을 붙입시다. 소프트웨어 세상 만사에 다 쓰이는게 이름이잖아요. 그러면 잘 지어봅시다.
18+
19+
## 의도가 분명한 코드
20+
21+
변수, 메소드, 에서 의미가 드러나도록 생각해봅시다. 코드 맥락에 따라, 필요한 내용이 담겨있도록 하는 이름을 유도해봅시다.
22+
23+
### 저의 생각 (1)
24+
25+
인덱스용 `i`, `j` 도 가급적이면 `idx` 처럼 써서, `foreach` 형식의 구문에서도 이해할 수 있게 만들어야할 것입니다.
26+
27+
### 저의 생각 (2)
28+
29+
파이썬에선 매개변수 사용 시, 쓰도록 하고싶을 때, 아래와 같이 사용할 수 있습니다([PEP 3102](https://peps.python.org/pep-3102/)).
30+
31+
사용방법은 아래와 같습니다:
32+
33+
```python
34+
Python 3.7.12 | packaged by conda-forge | (default, Oct 26 2021, 06:08:21)
35+
Type 'copyright', 'credits' or 'license' for more information
36+
IPython 7.34.0 -- An enhanced Interactive Python. Type '?' for help.
37+
38+
In [1]: def test1(
39+
...: body: dict,
40+
...: *,
41+
...: testarg: bool # 쓸 거면 explicit 하게 호출하기 (PEP 3102)
42+
...: ):
43+
...: print(body)
44+
...: print(testarg)
45+
...:
46+
47+
In [2]: test1({"b": 1}, True)
48+
---------------------------------------------------------------------------
49+
TypeError Traceback (most recent call last)
50+
<ipython-input-2-b0d6e60260e3> in <module>
51+
----> 1 test1({"b": 1}, True)
52+
53+
TypeError: test1() takes 1 positional argument but 2 were given
54+
55+
In [3]: test1({"b": 1}, testarg=True)
56+
{'b': 1}
57+
True
58+
59+
In [4]: test1({"b": 1}, {"testarg": True})
60+
---------------------------------------------------------------------------
61+
TypeError Traceback (most recent call last)
62+
<ipython-input-4-3f3364c4dbeb> in <module>
63+
----> 1 test1({"b": 1}, {"testarg": True})
64+
65+
TypeError: test1() takes 1 positional argument but 2 were given
66+
67+
In [5]: test1({"b": 1}, **{"testarg": True})
68+
{'b': 1}
69+
True
70+
71+
In [6]: test1({"b": 1}, **{"sdafkjnerfg": True})
72+
---------------------------------------------------------------------------
73+
TypeError Traceback (most recent call last)
74+
<ipython-input-6-b65affa75eff> in <module>
75+
----> 1 test1({"b": 1}, **{"sdafkjnerfg": True})
76+
77+
TypeError: test1() got an unexpected keyword argument 'sdafkjnerfg'
78+
79+
```
80+
81+
## 그릇된 정보를 피하라
82+
83+
- 프로그래밍 업계 전반에서 널리 사용되는 용어, 개발중인 도메인에서 사용하고 있는 용어와 유사한 이름을 다른 뜻으로 사용하지 맙시다.
84+
- 유사한 개념은 유사한 표기법을 사용합시다.
85+
86+
## 의미 있게 구분하라
87+
88+
아래 코드를 살펴봅시다.
89+
90+
```python
91+
def swap_coord(
92+
self,
93+
q1: Coord,
94+
q2: Coord,
95+
) -> None:
96+
""" 좌표계 Coord을 swap하는 코드다
97+
"""
98+
q1, q2 = q2, q1
99+
```
100+
101+
뜻은 알겠습니다만, `src`, `dst` 라고 작성하는게 보다 "명확"합니다. 그래도 나은코드를 만들려면? 하는 고민이 필요한 시기라고 할 수 있겠지요.
102+
103+
예를들어 어떤 에러의 Traceback을 보는데, 이런식으로 나왔다고 가정해봅시다.
104+
105+
```python
106+
---------------------------------------------------------------------------
107+
Exception Traceback (most recent call last)
108+
<ipython-input-10-9732aa3334c7> in <module>
109+
----> 1 get_active_account()
110+
111+
<ipython-input-7-4703b8c01446> in get_active_account()
112+
1 def get_active_account():
113+
----> 2 get_active_accounts()
114+
3
115+
116+
<ipython-input-8-c779c718bd0e> in get_active_accounts()
117+
1 def get_active_accounts():
118+
----> 2 get_active_accounts_info()
119+
3
120+
121+
<ipython-input-9-154e7846498a> in get_active_accounts_info()
122+
1 def get_active_accounts_info():
123+
----> 2 raise Exception("!")
124+
```
125+
126+
기능을 쫓아갈 때도 보다 "명확한" 이름을 써야, 추후 디버깅하고 기능을 추가할 때도 보다 쫓아가기 쉽겠지요.
127+
128+
## 발음하기 쉬운 이름을 쓰라
129+
130+
한국에서 영어는 제2외국어니까 발음은 사실 그리 문제되지 않는다고 생각합니다. 다만 도메인을 풀 때 *공통적인 단어*에 대한 논의는 필요하다고 생각합니다. 예를 들어, "구분"이라는 단어를 `gubun` 으로 공통적으로 사용할 수도 있을 것입니다. 다같이 프로그래밍을 하는것이니까요.
131+
132+
## 검색하기 쉬운 이름을 사용하라
133+
134+
수업 당 학생 수를 표기하기 위해 `7` 을 상수로 바로 쓰기보단 `MAX_CLASSES_PER_STUDENT` 같은 이름을 붙여서 쓰는편이 좋을 것입니다.
135+
136+
## 인코딩을 피하라
137+
138+
Win32 API 프로그래밍에서 흔히 쓰이던 [헝가리식 표기법](https://en.wikipedia.org/wiki/Hungarian_notation)이 특히 그랬지요. 요즘 강타입 언어들은 더 많은 타입을 지원하고, 컴파일 레벨에서도 이런 문제들을 잡을 수 있고, 클래스와 함수가 점차 작아지는 추세입니다. 파이썬이라도 `mypy` 나 적극적인 타입힌팅을 두는 식으로도 어느정도 대응은 되지요. 그리고 IDE 단에서도 타입에러를 감지합니다. 때에따라 쓸 수 있겠지만, 불필요하겠지요.
139+
140+
### 인터페이스와 구현 클래스?
141+
142+
팩토리 클래스와 구현체 클래스의 이름을 정한다면, 팩토리쪽을 추상화한 이름을 짓는편은 어떨까요? 구현체의 이름에 `Impl` 이라거나 `I` 접두사를 붙이거나 하기보단 어차피 어느 부모를 상속한건지 IDE로도 쫓아갈 수 있으니까요.
143+
144+
## 자신의 기억력을 자랑하지 마라
145+
146+
나만 아는 이름을 하면 남과 함께 일하기 어려우니 자제해야 합니다. 남과 함께 일하기 좋은 변수명을 짓는 방안으로는 어떤게 있을까요?
147+
148+
### 클래스 이름
149+
150+
동사 쓰지말고 명사/명사구로 씁시다.
151+
152+
### 메소드 이름
153+
154+
동사/동사구로 씁시다. getter나 setter, 그외 요소들은 사용하는 언어의 특징을 따릅시다.
155+
156+
### 특이한 이름은 지양할 것
157+
158+
그 당시에만 웃겨서 다시보면 노잼일거에요...
159+
160+
### 한 개념에 한 단어만
161+
162+
추상적 개념 하나에 단어 하나를 선택하고,이를 고수합시다. 일관성있게 유지해서 충분히 유추할 수 있는 코드를 짭시다.
163+
164+
1. 동일한 결과를 기대하는 메소드라면 단일 이름을 씁시다. 클래스마다 `fetch`, `retreive`, `get` 과 같이 **각각 다르게**쓰면 다른 코드를 쫓아가기 어렵습니다.
165+
2. 동일 개념이라면 동일한 이름을 씁시다. 동일 코드 기반에 `controller`, `manager`, `driver` 등을 **섞어 사용하면** 다른 코드를 이해하기 어렵습니다.
166+
167+
## 말장난을 하지 마라
168+
169+
한 단어는 하나의 의미만을 가집시다. 더한다(add) 라는 개념을 확장하고 싶다면 insert나 append 같은 단어를 사용합시다. 코드를 훑어보더라도 이해하기 쉽도록 합시다.
170+
171+
## 해법 영역에서 가져온 이름을 사용하라
172+
173+
**모든** 이름을 도메인에서 따지는 말고, 기술이 주요한 개념이라면 기술이름을 응용하여 명명합시다. VISITOR 패턴을 썼다면 `AccountVisitor` 와 같은 이름을 쓰는것은 어떨까요?
174+
175+
## 문제 영역에서 가져온 이름을 사용하라
176+
177+
그게 아니라면 어지간한 이름은 도메인에서 따옵시다. 그러면 새로 오는 사람이더라도 관련 파트 사람에게 개념을 질문하여 빠른 해답을 끌어올 수 있을 것입니다.
178+
179+
## 의미 있는 맥락을 추가하라
180+
181+
클래스, 메소드, 변수를 통해 로직의 컨텍스트를 유지하다보니, 메소드 하나에 너무 많은 개념이 들어가있나요? 도메인을 풀기 위한 주요 개념이라면 이를 객체화 해봅시다.
182+
183+
객체끼리 메시지를 주고받을 수 있도록 하고 로직을 작게 분리하는 해결책은 어떨까요?
184+
185+
## 불필요한 맥락을 없애라
186+
187+
너무 짧은 이름보다는 긴 이름이 좋습니다만, 의미가 분명한 이름이라면 짧게 가져가서 불필요한 맥락을 빼버립시다.
188+
189+
## 마치면서
190+
191+
좋은 이름은 기억에 오래 남고, 비슷한 이름은 익숙해지기 쉽습니다. 이런 노력을 기울여서 이름에 대한 프로그래머의 생각비율을 최소화 합시다.
53.1 KB
Loading

0 commit comments

Comments
 (0)