2024. 11. 13. 18:52ㆍKIM CHAN HEE/📚
[Clean Code] 독후감 및 정리 - 1
들어가기 앞서 (다시 읽기에 앞서)며칠 전 한 면접을 보게 되면서, "좋은 코드 가독성이라는 것을 어떻게 생각하세요 ?" 라는 질문을 받았습니다. 평소에 지키는 클린 코드라고 생각한 방법들(좋
chanhhh.tistory.com
지난 편 정리 및 결론 링크입니다.
들어가기 앞서 (다시 읽기에 앞서)
이전에 1-3 장에 대해서 클린 코드를 읽고 주변의 프로그래머 지망생 동료와 책에 대한 얘기를 해봤습니다. 호불호가 많이 갈리는 책이다라고 얘기를 해주더라고요. 무조건적인 맹신은 지양하는 게 좋겠다는 뻔한 그런 얘기를 나눈 것 같습니다. 그래도 한 번쯤은 읽어서 좋은 인사이트를 가져가는 게 좋을 거 같다는 뻔한 얘기로 마무리되었습니다. 😊
끊임없이 "왜"라는 질문을 문제상황에서 던지면서 왜 이런 문제에 이런 해결책을, 자신의 견해를 적은 것 인지를 생각하면서 남은 부분들을 읽어보려고 합니다. 독후감 및 정리 시작하겠습니다. ✍️
이 글은 4장 주석, 5장 형식 맞추기, 6장 객체와 자료구조의 내용을 포함하고 있습니다.
다음 장은 다음 글로 이어집니다.
4장 주석
나쁜 코드에 주석을 달지 마세요. 새로 짜십시오. 잘 달린 주석은 그 어떤 정보보다 유용하지만, 경솔하고 근거 없는 주석은 코드를 이해하기 어렵게 만듭니다. 우리는 코드로 의도를 표현하지 못해, 실패를 만회하기 위한 주석을 사용합니다. 주석은 반겨 맞을 손님이 아닙니다. 주석은 오래될수록 코드에서 멀어집니다. 이렇게 4장 주석에 들어가자마자 주석에게 안 좋은 말만 해대는 밥아저씨를 볼 수 있습니다.
한 문장으로 부정확한 주석은 아예 없는 것보다 더 해롭습니다. 주석은 가능한 한 줄이도록 꾸준히 노력해야 합니다.
주석은 나쁜 코드를 보완하지 못한다
주석이 필요한 이유는 대개 코드 품질이 좋지 않기 때문입니다. 주석을 통해 코드를 설명하기보다, 코드를 개선해 주석이 필요 없도록 만드는 것이 우선입니다.
코드로 의도를 표현하라
함수명과 변수명만으로도 주석이 필요 없는 코드를 작성하는 것을 목표로 합니다.
좋은 주석
몇 가지 주석은 필요하거나 유익할 수 있습니다. 그러나, 진정으로 좋은 주석은 주석 없이도 의도를 드러내는 코드입니다.
법적인 주석
저작권 정보나 소유권 정보와 같은 법적 요구 사항은 주석으로 남겨야 합니다. 이는 필요하고 타당한 주석입니다.
정보를 제공하는 주석
필요에 따라 정보를 제공하는 주석을 추가할 수 있지만, 함수나 변수 이름에 해당 정보를 담는 것이 더 바람직합니다.
의도를 설명하는 주석
때로는 코드의 구현 방식을 넘어, 결정에 깔린 의도를 설명하는 주석이 필요합니다. 이런 주석은 코드가 왜 그렇게 작성되었는지를 이해하는 데 도움이 됩니다.
의미를 명확히 하는 주석
모호한 인수나 반환값이 있을 경우, 주석을 통해 의미를 분명히 하면 코드 이해가 쉬워집니다.
결과를 경고하는 주석
특정 상황에서의 위험을 경고하는 주석이 필요할 수 있습니다. 예를 들어, // 여유 시간이 충분하지 않다면 실행하지 마십시오와 같은 경고성 주석입니다.
TODO 주석
추후 해야 할 일이나 개선 사항을 표시하기 위해 TODO 주석을 남겨두는 것은 유용합니다.
중요성을 강조하는 주석
특히 중요한 부분을 강조하는 주석이 필요할 수 있습니다.
나쁜 주석
대부분의 주석이 이 범주에 속합니다. 불필요한 코드 설명이나, 허술한 코드의 변명 또는 미숙한 결정을 합리화하는 등, 주석이 쓸데없는 독백으로 끝나버리는 경우입니다.
주절거리는 주석
특별한 이유 없이 의무감이나 프로세스에 의해 마지못해 달아 놓은 주석입니다.
반복적인 주석
코드 내용을 그대로 되풀이하는 주석으로, 코드를 읽으면 금새 읽을 수 있는데, 읽을 필요 없는 주석을 읽느라 시간을 낭비하게 만듭니다.
오해의 소지가 있는 주석
의도는 좋았으나, 주석이 엄밀하지 못해 오해를 일으킬 여지가 있습니다. 이는 오히려 다른 개발자에게 혼란을 줍니다.
의무적인 주석
모든 함수와 변수에 주석을 달아야 한다는 규칙은 불필요하고 오히려 코드를 불필요하게 어지럽힙니다.
이력 기록 주석
과거 버전 관리 시스템이 부족했던 시절의 잔재로, 여전히 코드에 남아 있는 경우가 많습니다.
있으나 마나 한 주석
당연한 사실을 주석으로 남기면서 새로운 정보를 제공하지 못하는 주석입니다.
함수나 변수로 표현할 수 있는 주석
주석 대신 함수명이나 변수명으로 표현할 수 있는 경우, 코드를 개선하여 주석을 없애는 것이 좋습니다.
위치 표시 주석
특정 위치를 표시하려는 주석이나 배너는 꼭 필요할 때만, 아주 드물게 사용하는 것이 좋습니다.
과도한 배너는 독자에게 흔한 잡음으로 느껴질 수 있습니다.
닫는 괄호 주석
중첩이 심하고 장황한 함수라면 의미가 있을지 모르지만, 작고 캡슐화된 함수에는 잡음일 뿐입니다.
그러므로 닫는 괄호에 주석을 달아야겠다는 생각이 든다면 함수를 줄이는 시도를 해봐야 합니다.
공로나 저자 표시 주석
이런 정보는 형상 관리 시스템이 알아서 해줘야 합니다.
주석으로 처리된 코드
주석으로 코드를 처리하면 다른 사람이 이를 지우기 꺼리게 됩니다.
이유가 있어서 남기는 것이라고, 중요하니까 지우면 안 된다고 생각하게 됩니다.
이는 질 나쁜 와인병 바닥에 앙금이 쌓이듯 쓸모없는 코드가 되어 점차 쌓여가게 됩니다.
형상 관리 시스템이 코드 이력을 기록해 주기 때문에 주석 처리된 코드는 과감히 삭제해도 됩니다.
HTML 주석
코드에 HTML 주석은 피하는 것이 좋습니다.
전역 정보 주석
주석은 가까이 있는 코드에 대해서만 설명하고, 시스템 전반의 정보를 포함하지 않는 것이 좋습니다.
시스템의 전반적 정보가 변할 경우 해당 주석이 업데이트되지 않을 위험이 있습니다.
과도한 정보
주석에 불필요한 역사나 관련 없는 정보를 장황하게 담지 말아야 합니다.
예를 들어 RFC 2045와 같은 기술 설명은 주석에 적합하지 않습니다.
모호한 관계
주석과 주석이 설명하는 코드 사이의 관계가 명확해야 합니다.
함수 헤더 주석
짧고 하나의 작업만 수행하며 이름을 잘 붙인 함수가 주석 헤더보다 훨씬 좋습니다. 짧은 함수는 긴 설명이 필요하지 않습니다.
4장을 읽고 나서
4장에는 밥아저씨의 결론이 없습니다. 4장을 읽어보면 여러 기교가 있지만 하나의 결론으로 귀결되는 것이 보입니다.
'주석은 최대한 안 쓰는 게 좋다'입니다. 깨끗한 코드에서는 주석이 불필요하며, 코드의 중요성과 의도에 맞춰 꼭 필요한 부분에만 주석을 다는 것이 이상적입니다. 그 외의 주석은 오히려 코드를 해치는 잡음이 될 수 있음을 경계해야 합니다. 저도 이번 4장의 결론에 많이 동의하는 편입니다.
주석의 목적이 코드를 보완하는 것이라기보다는 코드 자체가 충분히 명확하게 의도를 드러내고, 이에 대해서 어떤 의도로 이런 코드를 짰는지에 대해 설명하고 중요한 점을 언급해 주는 정도로 주석을 다는 게 좋겠습니다. 결국 코드의 중요성과 의도를 언급하는 데 있어서 주석을 다는 것은 한번 더 그 코드에 대해서 생각하게 되고, 코드의 의미와 이것을 설명하기 위해서 더 나은 코드로 발전시키는 데 있어서 많은 도움이 된다고 생각합니다.
이전 C++로 서버 개발에서 doxygen을 활용해 docs 작업을 했던 경험이 떠올랐습니다. 그때 주석을 많이 사용했는데, 이번 장을 읽으며 당시 작성한 주석들이 과연 필요했던 것인지 다시 생각해 보는 기회를 갖게 되었습니다. 코드 가독성을 높이기 위해 주석을 남겼지만, 사실은 불필요한 설명도 많았을 수 있다는 점에서 아쉬움이 남습니다. 이번 장을 통해, 조금 더 가독성 높은 주석 작성법과 주석 사용의 필요성에 대해서 생각하게 되었습니다. 🙂↕️
5장 형식 맞추기
프로그래머라면 코드 형식을 깔끔하게 맞춰 작성하는 것이 중요합니다. 간단한 규칙을 정하고 이를 일관되게 따르는 것이 좋습니다. 팀으로 일하는 경우에는 팀이 합의한 규칙을 모든 팀원이 따라야 하며, 필요할 경우 Prettier나, lint 같은 형식 자동화 도구를 활용하는 것도 좋습니다.
형식을 맞추는 목적
코드 형식은 프로그래밍의 중요한 요소이며, 간과할 수 없는 부분입니다. 형식은 단순한 꾸밈이 아니라, 코드 작성자의 의도를 명확하게 전달하는 의사소통의 수단입니다. 개발자라면 일차적으로 의사소통을 책임져야 하며, 형식 또한 그 역할을 담당합니다.
적절한 행 길이 유지
일반적으로 큰 파일보다 작은 파일이 이해하기 쉽습니다.
한 파일에 보통 500줄을 넘지 않도록 하며, 대부분 200줄 미만으로 유지하는 것이 좋습니다.
신문 기사처럼 작성하라
이름은 단순하면서도 기능을 설명할 수 있도록 신경 써서 작성합니다. 소스 파일의 첫 부분은 전체 개요와 주요 알고리즘을 설명하는 고차원 개념을 담아야 합니다.
개념을 빈 행으로 분리하라
각 행은 수식이나 절을 나타내고, 관련 있는 행들은 묶어 표현하고 각 묶음 사이에는 빈 행을 넣어 분리합니다.
빈 행은 새로운 개념을 시작한다는 시각적 표시가 됩니다.
세로 밀집도
줄 바꿈이 개념을 구분하는 것이라면, 세로 밀집도는 연관성을 나타냅니다. 관련된 코드는 가급적 세로로 가깝게 배치하는 것이 좋습니다.
수직 거리
함수나 변수가 정의된 코드를 찾으려 상속 관계를 찾으러 거슬러 올라간 경험은 달가운 경험이 아닙니다.
시스템이 무엇을 하는지 이해하고 싶은데, 이 조각 저 조각이 어디에 있는지 찾고 기억하느라 시간과 노력을 소모하게 만들지 말아야 합니다.
서로 밀접한 개념은 세로로 가까이 둬야 합니다.
두 개념이 서로 다른 파일에 속한다면 규칙이 통하지 않지만, 타당한 근거가 없다면 서로 밀접한 개념은 한 파일에 속해야 마땅합니다.
변수 선언 위치
변수는 사용 위치에 최대한 가까이 선언해야 합니다.
인스턴스 변수 위치
인스턴스 변수는 클래스 맨 앞에 선언하며, 변수 간에는 공백 없이 연속적으로 작성합니다.
이는 잘 설계된 클래스가 많은 메서드에서 인스턴스 변수를 활용하도록 돕습니다.
종속 함수 위치
한 함수가 다른 함수를 호출한다면 두 함수는 가까이 배치하고, 호출하는 함수를 호출되는 함수보다 위에 두는 것이 좋습니다.
이를 통해 코드를 읽는 사람이 호출 순서를 쉽게 예측할 수 있습니다.
개념적 유사성
기능이 유사하거나 기본적으로 비슷한 코드는 가까이 배치합니다.
명명법이 똑같고 기본 기능이 유사한 함수들이 모여있는 유틸리티 함수 등이 좋은 예입니다.
세로 순서
일반적으로 함수 호출은 아래로 내려가는 구조로 유지합니다. 이를 통해 모듈이 고차원에서 저차원으로 자연스럽게 흐르도록 합니다.
가로 형식 맞추기
행 길이는 100자에서 120자 정도로 제한하는 것이 좋습니다. (저는 개인적으로 99자로 제한하는 방식을 선호합니다.)
가로 정렬
변수명이나 타입을 정렬하는 것은 오히려 중대한 결함을 감추기 쉽습니다.
목록이 너무 길어지지 않도록 유지하는 것이 핵심입니다.
들여 쓰기
들여 쓰기는 코드 구조를 명확히 보여주는 중요한 요소입니다.
때로는 간단한 if 문, 짧은 while 문, 짧은 함수에서 들여쓰기 규칙을 무시하고픈 유혹이 생기게 됩니다.
가급적 원칙을 지키고, 한 행에 조건문이나 반복문 범위를 한꺼번에 쓰지 않습니다.
가짜 범위
의미 없는 빈 while, for 문 등은 피합니다.
팀 규칙
팀은 한 가지 규칙에 합의해야 합니다. 그리고 모든 팀원은 팀 전체가 합의한 규칙을 따르는 것이 중요합니다.
좋은 소프트웨어는 읽기 쉬운 문서처럼 일관된 형식을 유지해야 한다는 사실을 기억해야 합니다.
밥 아저씨의 형식 규칙
스타일은 일관되고 매끄러워야 합니다. 한 소스 파일에서 적용한 형식이 다른 파일에도 동일하게 적용된다는 신뢰감을 독자에게 주어야 합니다. 온갖 스타일을 혼합하여 소스 코드를 복잡하게 만드는 실수는 피해야 합니다.
5장을 읽고 나서
5장을 통해 형식의 일관성이 코드 가독성과 유지보수성을 높이는 핵심이라는 점을 다시금 깨달았습니다. 형식은 단순한 예의 차원이 아니라 코드 의사소통의 필수적인 요소이며, 프로그래밍 과정에서 필수적으로 고려해야 할 요소입니다.
특히 팀 내에서 공통된 규칙을 설정하고 모든 구성원이 따르는 것은 협업에 큰 도움이 됩니다. 혼자 개발할 때도 형식 규칙을 설정해 꾸준히 따름으로써 코드 품질을 높일 수 있습니다. 좋은 코드란 읽기 좋은 코드라는 결론을 다시 확인하게 된 장이었습니다. 😊
42서울에서 공부할 때 Norminette라는 형식 rule이 있었습니다. 이때 이것을 지키기 위해서 굉장히 많이 노력했던 기억이 나네요.
그래서 VScode에서 작업하는 모든 결과물은 Prettier와 formatter를 사용해서 자동적으로 정리될 수 있도록 초기 세팅할 때 무조건 해두는 편입니다.
Xcode에서 작업하는 작업물들은 control + i 로만 맞추고 있습니다. 형식의 일관성을 위해서 Xcode에서 SwiftLint를 사용해봐야 할 것 같습니다. SwiftLint를 사용해 보고, 사용기도 포스팅해 보도록 하겠습니다. 😉
6장 객체와 자료 구조
객체와 자료구조의 차이점을 이해하는 것은 클린 코드 작성의 핵심입니다. 이 장에서는 객체와 자료구조의 개념적 차이, 이를 설계할 때의 주의사항, 그리고 잘못된 설계로 인한 문제점을 다룹니다.
자료 추상화
변수를 private으로 설정하는 것은 외부에서 변수에 직접 접근하지 못하도록 하기 위함입니다. 하지만 get/set 함수를 통해 외부로 값을 노출하면, 자료 구조의 구현을 그대로 외부에 드러내는 셈이 되어 진정한 의미의 추상화를 방해합니다. 단순히 변수를 함수로 감싼다고 해서 구현이 감춰지는 것은 아닙니다. 추상화란 사용자가 내부 구현에 의존하지 않고도 핵심 기능을 사용할 수 있도록 하는 것입니다.
자료를 세세하게 공개하기보다는 추상적인 개념으로 표현하는 것이 더 적절합니다. 아무 생각 없이 get/set 함수를 추가하는 방식은 객체 지향적 설계가 아닙니다. 객체가 포함하는 자료를 어떻게 표현하는 것이 가장 좋을지 심각하게 고민해야 합니다.
자료/객체 비대칭
객체는 내부의 자료를 감추고 필요한 동작을 공개하며, 자료 구조는 자료를 공개하지만 특별한 동작을 갖지 않습니다. 이로 인해 두 가지 접근 방식은 각기 다른 장단점을 지닙니다. 객체 지향 코드는 새로운 자료 구조를 추가하기 어렵지만, 새로운 동작을 추가하기 쉽습니다. 반면 절차 지향 코드는 새로운 자료 구조를 추가하기는 쉽지만, 새로운 동작을 추가하기는 어렵습니다.
시스템 설계 시 이러한 차이점을 이해하면 객체 지향적 접근이 적합한 경우와 절차적 접근이 유리한 경우를 구분할 수 있습니다.
디미터 법칙
디미터 법칙은 모듈이 자신이 조작하는 객체의 내부 세부 사항을 알지 말아야 한다는 원칙입니다. 객체는 자료를 숨기고 필요한 함수만 공개해야 하며, 이를 통해 모듈 간의 결합도를 낮출 수 있습니다.
"클래스 C의 메서드 f는 다음과 같은 객체의 메서드만 호출해야 한다."
- 클래스 C
- f가 생성한 객체
- f 인수로 전달된 객체
- C의 인스턴스 변수에 저장된 객체
기차 충돌
아래와 같은 코드 예시는 "기차 충돌(train wreck)"이라 불립니다.
이런 형태의 코드보다는 아래와 같이 각 단계를 나누어 쓰는 것이 좋습니다.
디미터 법칙 위반 여부는 객체가 자료 구조인지에 따라 달라집니다. 객체라면 내부 구조를 감추어야 하므로 위의 예시는 법칙을 위반합니다. 하지만 자료 구조라면 내부 구조를 드러내는 것이 오히려 적절할 수 있습니다.
string outputDir = ctxt.options.scratchDir.absolutePath;
잡종 구조
때때로 절반은 객체이고 절반은 자료 구조인 잡종 구조가 생기기도 합니다. 잡종 구조는 중요한 기능을 수행하는 함수와 get/set 함수로 외부에 노출된 변수들을 함께 갖고 있는 구조로, 비공개 변수를 노출해 다른 모듈에서 절차적으로 접근하게 만듭니다.
잡종 구조는 새로운 함수나 자료 구조를 추가하기 어렵고, 절차적 프로그래밍과 객체 지향 프로그래밍의 단점을 모두 담고 있습니다. 이러한 구조는 혼란과 결합도를 증가시키기 때문에 되도록 피해야 합니다.
구조체 감추기
구조체는 내부 구조를 감추고 필요한 함수만을 공개하는 객체로 설계하는 것이 바람직합니다. 예를 들어 ctxt, options, scratchDir이 객체라면, 내부 구조를 드러내지 않도록 외부에서 함수를 통해 작업을 위임해야 합니다. 이렇게 하면 모듈이 불필요하게 여러 객체를 탐색하지 않도록 설계할 수 있습니다.
자료 전달 객체 (DTO)
자료 전달 객체(DTO)는 공개 변수만 있고 함수가 없는 클래스로, 주로 데이터베이스와의 통신이나 소켓에서 받은 메시지를 처리할 때 사용됩니다. DTO는 앱 코드에서 사용할 객체로 데이터를 가공하는 첫 단계에서 유용합니다.
일반적으로 DTO는 비즈니스 로직을 포함하지 않는 단순한 데이터 전송용 구조체입니다. get/set으로만 조작 가능한 형태를 Bean이라고 하며, DTO와 비슷한 개념이지만 데이터를 직접 조작하는 방식에 차이가 있습니다.
활성 레코드
DTO의 특수한 형태인 활성 레코드는 공개 변수나 get/set 함수를 가질 뿐 아니라, save나 find와 같은 탐색 함수도 포함합니다. 이때 비즈니스 로직을 추가하여 자료 구조를 객체처럼 다루는 경우가 많은데, 이는 잡종 구조를 만들 가능성이 있어 피해야 합니다. 활성 레코드는 자료 구조로서의 역할만 하도록 하고, 비즈니스 로직이 필요한 경우 별도의 객체로 분리하는 것이 좋습니다.
결론
객체는 동작을 공개하고 자료를 숨겨서, 새로운 객체 타입을 추가하기는 쉽지만 기존 객체에 새 동작을 추가하기는 어렵습니다. 반대로 자료 구조는 별다른 동작 없이 자료를 노출하기 때문에, 새 동작을 추가하기는 쉽지만 새로운 자료 구조를 추가하기는 어렵습니다.
설계 시 각 접근 방식의 장단점을 고려해 상황에 가장 적합한 방법을 선택하는 것이 중요합니다. 클린 코드를 작성하려면 자료와 동작을 명확히 구분하고, 편견 없이 문제를 해결할 수 있는 최적의 방법을 찾는 유연성이 필요합니다.
6장을 읽고 나서
우선 이 장을 읽으면서 객체와 자료구조를 바라보는 관점이 한층 넓어졌습니다.
iOS(UIKit)에서 프로젝트를 진행할 때, 보통 MVVM 모델을 굉장히 많이 쓰게 되는데, 여기에서 Model은 자료구조를 의미하고, 객체를 ViewModel로 대입하며 읽으니 확실히 선명하게 이해가 되었습니다. 객체 지향 코드와 절차적 코드가 상황에 따라 다른 장점을 제공한다는 사실도 굉장히 흥미로웠고, 어느 한쪽에만 의존해서는 최적의 설계를 이루기 어렵다는 점도 확실하게 이해된 것 같습니다. 특히 자료를 숨기고, 동작을 공개하는 객체와 자료를 공개하면서 기능을 최소화한 자료구조 간의 차이가 확실하게 이해되었고, 기존에 무의식적으로 작성한 get/set의 남용에 대해서도 다시금 생각해 보게 되었습니다. 물론 Swift에서는 get/set 함수를 쓴 적은 없지만 개념적으로의 남용에 대한 생각입니다. 😂
또한, 디미터 법칙이나 잡종 구조에 대한 경고는 실제로 제가 경험했던 코드 문제와 맞닿아 있었습니다. 복잡한 코드가 여러 객체의 내부 속성을 참조하거나, 절반은 객체, 절반은 자료 구조 같은 잡종 구조로 인해 유지보수가 어려웠던 상황이 떠올랐습니다. 앞으로는 이러한 점들을 개선해 디미터 법칙을 준수하고, 필요할 때 자료 구조와 절차적 접근을 활용하는 등 더 균형 잡힌 설계를 목표로 해야겠다고 다짐하게 되었습니다. 😔
결국 이 장이 강조하는 것은 ‘유연성’과 ‘추상화’였습니다. 상황에 맞는 최적의 구조를 설계하기 위해선 객체와 자료구조의 특성을 잘 이해하고 편견 없이 선택하는 것이 필요함을 느꼈습니다. 이를 통해 앞으로 더 유연하고 유지보수하기 쉬운 코드를 작성하는 데 도움이 될 것 같습니다.
6장까지의 생각
4장부터 6장까지 읽고 나서 가장 처음으로 든 생각은 '깨끗한 코드란 결국 깊은 고민을 담아내는 것'이었습니다. 4장에서 6장에 걸쳐 강조되는 것은 코드가 어떻게 읽혀야 하고, 어떻게 설계되어야 하며, 궁극적으로 개발자가 코드의 유지보수와 확장성을 위해 무엇을 고려해야 하는지에 관한 것이었습니다.
이 책을 통해 깨끗한 코드를 작성하는 것은 단순한 기술 이상의 의미를 가진다는 것을 느꼈습니다. 코드의 설계와 작성, 그리고 그 속에서 고민이 담긴 선택이 결국 코드의 가치를 결정한다는 사실을 배웠습니다. 앞으로도 코드를 통해 개발자의 의도가 명확하게 드러나고, 누구나 쉽게 이해할 수 있는 클린 코드를 작성하기 위해 노력해야겠다고 다짐하게 되었습니다. 💪
이 글은 여기까지 마치고, 다음 7장부터 찾아뵙겠습니다. 긴 글 읽어주셔서 감사합니다. 🙇♂️
'KIM CHAN HEE > 📚' 카테고리의 다른 글
[삼체] 1부: 삼체문제 독후감 (3) | 2025.01.18 |
---|---|
[Clean Code] 독후감 및 정리 - 1 (1) | 2024.11.02 |
[오래된 연장통] 진화심리학에 대한 가벼운 통찰 (3) | 2023.10.30 |
[UX 라이팅 시작하기] 독후감 및 정리 (1) | 2023.10.12 |
[Algorithmic Problem Solving Strategies] 코딩과 디버깅에 관하여 독후감 (0) | 2023.04.04 |