-
Notifications
You must be signed in to change notification settings - Fork 5
더 나은 프로그래머 되는법 2주차 - 김영명 #536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| # 더 나은 프로그래머 되는 법 | ||
| ## 9장 ~ 13장 | ||
| --- | ||
| 이번 스프린트에서는 11장까지는 테스트 코드에 대해서 집중하였고, 12장 ~ 13장은 코드 설계에 집중한 느낌이었습니다. | ||
|
|
||
| 특히 테스트 코드를 좋아하고 중요하게 여겼던 기존 생각으로 정말 재밌고 어렵지 않게 읽을 수 있었습니다. | ||
| “이진 탐색”은 보통 알고리즘에만 적용하는 것으로 생각하고 있었는데, 버그를 찾는 전략으로도 사용하고 이를 위한 Git 명령어를 알게된 것도 정말 좋은 기회였던 것 같습니다. | ||
|
|
||
| 저자의 두가지의 시스템에 대한 경험을 통해 설계가 얼마나 중요한지 다시 한번 생각하는 시간을 가질 수 있었습니다. | ||
|
|
||
| ## 9장 - 예상하지 못한 것을 예상하기 | ||
| 코드 작성 시 벌어질 것으로 예상되는 상황에 대한 대비만으로는 부족하기 때문에 모든 단계에서 조금이라도 발생할 가능성이 있는 특이 사항들은 모두 고려해야 한다. | ||
|
|
||
| **오류** | ||
| * 항상 오류를 고려한 코드를 작성하여 그로부터 복구할 수 있도록 해야 한다. | ||
| * 오류를 무시하지 말고 오류 상황에서도 최선을 다하도록 코드를 작성하자. | ||
|
|
||
| **스레딩** | ||
| * 멀티 스레딩으로 인해 예상하지 못하는 일이 발생하는 범위가 넓어졌지만 동시 실행의 원리와 스레드 간의 결합도를 낮추는 방법을 반드시 이해해야 한다. | ||
|
|
||
| **셧다운** | ||
| * 애플리케이션이 종료되면서 작업자 객체(worker object)를 파기하므로, 그 과정에서 이미 파기한 객체를 사용하면 안 된다. 목표 객체가 이미 다른 스레드에 의해 제거된 콜백을 작업 큐에 넣으면 안된다. | ||
|
|
||
| > 코드 작성 시 가능한 모든 코드 경로를 고려해야 한다. 나중에 비정상적인 경우에 대응하려 하지 말라. 그렇게 할 일을 미루다 보면, 이후 그와 같은 경로 자체가 있음을 잊어버리게 되고 코드는 버그로 가득 찰 것이다. | ||
|
|
||
|
|
||
| ## 10장 - 버그 사냥하기 | ||
| 소프트웨어는 처음부터 완벽할 수 없기 때문에, 초보나 전문가나 모두 똑같은 문제로 쉽게 무너질 수 있다. | ||
| 책에 쓰여있는 에르허르 데이크스트라는 *“디버깅이 소프트웨어 버그를 없애는 과정이라면, 프로그래밍은 분명 버그를 만드는 과정이다.”* 라고 한다. | ||
| 그러니 버그는 어쩔 수 없이 무조건 발생하고 일상이니 피하지 말고 계속 신경써서 부딪히자. | ||
|
|
||
| **경제적 우려** | ||
| * 프로그래머들이 소프트웨어를 디버깅하는 데는 연간 약 3,120억 달러에 달하는 엄청난 비용이 소요된다고 한다. | ||
| * 이것으로 볼 때 프로그래머들은 버그를 빠르고 정확하게 고쳐야한다는 사명감이 있다고 볼 수 있다. | ||
|
|
||
| **대비책** | ||
| * 버그가 생기고 나서 고치는 것보다는 예방하는 편이 훨씬 낫다. | ||
| * 예방하기 위해서는 코드 검토, 페어 프로그래밍, 테스트 전략 (TDD 등), 커버리지 도구 등이 있다. | ||
| * 버그를 피하기 위해서는 너무 영리한 코드를 만들지 말자. 즉 너무 복잡한 코드를 작성하는 것을 피하자. | ||
| * 마틴 파울러: *“미련한 프로그래머는 컴퓨터가 이해할 수 있는 코드를 만들고, 좋은 프로그래머는 사람이 이해할 수 있는 코드를 만든다.”* | ||
|
|
||
| **버그 잡기** | ||
| * 대부분의 버그는 금방 찾아내서 수정할 수 있지만, 어떤 것들은 정말 오랜 시간을 잡아먹기도 한다. | ||
| * 버그를 체계적으로 조사하고 특징을 잡아내야 한다. 버그 재현 과정을 가장 단순하게 하여 하나의 문제에 집중하도록 하고, 특정 환경에 영향이 있는지 등을 조사해야 한다. | ||
|
|
||
| **함정 파기** | ||
| * assert나 테스트 코드를 이용해서 많은 가정을 입증하자. | ||
| * 이와 함께 로그를 이용하면 문제를 발견하고 해결한 이후 코드를 남겨놓는 확실한 방법이다. 하지만 너무 쓸데 없는 로그는 오히려 방해가 될 수 있다. | ||
|
|
||
| **이진 탐색 배우기** | ||
| * 코드를 한 줄씩 단순히 따라가기보다는 일련의 사건의 시작과 끝을 확인하라. 그런 다음 문제 공간을 두 개로 나누고, 가운데 시점에서 코드가 괜찮은지 확인하라. | ||
|
|
||
| **소프트웨어 고고학을 채택하라** | ||
| * 소프트웨어 고고학(Software archaeology)은 과거 이력을 바탕으로 버전 관리 시스템을 뒤져보는 방법에 대해 설명한다. | ||
| * 버그가 생성되기 이전의 가장 최근의 코드베이스 하나 선정하고 재현할 수 있는 테스트 케이스를 갖춰 어떤 코드 변경 모음으로 인해 파손이 발생했는지 찾아보자. 이때 이진 탐색 전략을 사용하는 것이 최선의 방법이다. (git bisect) | ||
| * 이것이 한꺼번에 많은 범위를 커밋하기보다는, 작게 나눠야하는 이유다. | ||
|
|
||
| **테스트하고 테스트하고 테스트해라** | ||
| * 단위 테스트를 작성하는 데 시간을 투자해야 한다. 처음에 작성한 코드를 개선하고 검증해나가는 데 도움이 될 뿐만 아니라, 향후 변경에 대비한 훌륭한 조기 경보 장치의 역할을 해줄 것이다. | ||
| * 버그의 원인을 최종 결정했다면, 문제를 명백히 재현해내는 간단한 테스트 작성을 고려하고 실제로 코드를 수정하기 전에 테스트 모음에 추가하라. | ||
|
|
||
| **예리한 도구에 투자하라** | ||
| * 디버깅을 위한 도구는 다양하며 이를 사용할 줄 알면 아주 효과적이다. | ||
| * 디버거 사용법을 잘 익힌 다음 필요한 때에 사용하자. | ||
|
|
||
| **간접적 전략** | ||
| * *쉬어가기* - 휴식을 통해 새로운 관점을 얻을 수 있고, 더욱 신중하게 생각할 수 있기 때문에 작업을 멈추고 코드에서 떨어져 있어야 할 때를 배우는 것이 중요하다. | ||
| * *다른 사람에게 설명해보라* - 어떤 문제를 다른 사람에게 설명하다보면, 동시에 자신에게도 설명하게 되고 문제를 해결하게 된다. | ||
|
|
||
| **재현할 수 없는 버그** | ||
| * 실패를 유발하는 요소들을 기록하고 더 많은 정보를 수집하자. | ||
| * 매우 힘든 문제일 경우, 테스트 팜을 세팅하여 오랫동안 가동하는 스트레스 테스트를 실행하는 방법도 있다. | ||
| * *스레드를 이용하는 코드* - 스레드는 비결정적이고 재현하기 어려운 방법으로 이리저리 휘감기며 상호 작용을 하는 만큼, 간헐적인 실패를 종종 유발한다. | ||
| * *네트워크 상호 작용* - 대부분의 코드는 로컬 저장소에 항상 접속할 수 있다고 가정되나 이는 부주의한 가정이다. 접속 실패, 간헐적인 긴 로딩 타임이 네트워크에서는 일어날 수 있다. | ||
| * *저장 장치의 다양한 속도* | ||
| * *메모리 손상* | ||
| * *전역 변수 / 싱글톤* | ||
|
|
||
| ## 11장 - 테스트하기 | ||
| TDD는 누군가에게는 종교와 다름 없거나, 적절한 개발 방법이나, 괜찮은 방법이나 작업에는 적용하기 어려운 것일 수 있다. | ||
| 또한 그저 낭비라고 생각할 수도 있다. | ||
|
|
||
| **왜 테스트하는가** | ||
| 당연히 자신의 코드는 자신이 테스트해야 하지만, 그렇지 않고 출시는 경우가 있다. 문제는 QA 단계에서 발견되거나 사용자가 발견할 때까지 방치된다. | ||
|
|
||
| **피드백 과정 줄이기** | ||
| 소프트웨어를 제대로 만들기 위해서는 피드백은 필수며 좋은 테스트 전략은 피드백 절차를 간소화하는 것이다. | ||
| QA에게 후보 버전을 테스트하는 방법이 있으나, 새로운 하부 시스템을 만드는 방법도 있고, 이보다 더 나은 방법으로는 단위 부분(클래스, 함수 수준)으로 나누어 테스트하는 것이다. | ||
| 이때 자동화된 테스트로 효율적으로 테스트를 수행할 수 있다. | ||
|
|
||
| **테스트 코드 짜기** | ||
| 테스트 코드를 작성하는 것에는 시간이 소모된다. | ||
| 그러나 오히려 테스트 코드를 통해 코드 작성 시간을 줄일 수 있다. | ||
| 실제로 여러 연구에 따르면 적절한 테스트 전략이야말로 불량 발생률을 줄일 수 있는 것으로 증명되었다. | ||
| 물론 속도가 느려질 수 있으나 이는 테스트를 제대로 이해하지 못해 오류가 많이 발생하거나, 코드 구조가 경직되어 하나의 함수 일부를 고치는 데 수백만 개의 테스트를 재작성해야 하는 경우다. | ||
| 그러나 이는 잘못된 테스트 코드를 작성하면 안되는 이유이며, 테스트를 하지 말아야 하는 이유가 아니다. | ||
|
|
||
| **테스트 유형** | ||
| * *단위 테스트* - 가장 작은 단위의 기능에 대한 테스트를 단독으로 수행하는 것으로, 각각의 함수가 정확히 작동하는지 확인하는 것. 단독이란 그 어떤 외부에 대한 접속도 하지 않는다는 것이다. | ||
| * *통합 테스트* - 각각의 단위 모듈을 더 큰 결합체로 통합하여 작동시키는 복합 기능을 검증할 수 있다. | ||
| * *시스템 테스트* - “종단 간 테스트(end-to-end tests)”라고도 알려진 이 테스트를 통해 전체 시스템에 대한 요구 사항 명세를 확인할 수 있다. | ||
|
|
||
| TDD에 대해 간략하게 레드-그린-리팩토링 주기에 대해서도 설명을 한다. | ||
| TDD가 중요 포인트는 아니고, 결국 테스트는 피드백 절차를 줄이고, 이는 좋은 품질의 소프트웨어로 이끌어 준다. | ||
|
|
||
| > 코드를 작성하면서 테스트를 같이 작성하라. 테스트 작성을 미루면 그만큼 테스트 효과가 줄어들 것이다. | ||
|
|
||
| > 아무리 좋은 개발자 테스트라 해도 QA 테스트를 대치할 수는 없다. | ||
|
|
||
|
|
||
| ## 12장 - 복잡도 다루기 | ||
| 자신이 짠 코드가 위대하고, 다른 사람의 코드가 복잡하다는 것은 늘 그렇지 않다는 사실을 인정해야 한다. | ||
| 실제로 복잡한 어떤 일을 너무 쉽게보고 충분한 계획을 세우지 않으면 프로그래머의 발목을 잡게된다. | ||
|
|
||
| 책의 필자는 소프트웨어의 복잡도는 크게 세 가지 원인에서 기인하며 그중 두 가지는 블롭(blob)과 라인(line)이라고 본다. | ||
|
|
||
| 크기 자체는 문제가 되지 않는다. 코드를 얻허게 구성하고 배분할지가 문제다. | ||
| 겉보기에만 단순해 보이는 것이 아니라, 실제로 간결해지도록 설계하려면, 각 블롭이 정확한 역할과 책임을 확실히 갖도록 해야 한다. | ||
|
|
||
| 복잡도는 각 블롭 안에서 커간 것이 아닌, 우리가 블롭을 서로 연결하는 과정에서 커진 것이다. | ||
| 일반적으로 라인이 적을수록 소프트웨어 디자인은 간결해지고 많아질 수록 설계는 더 경직된다. | ||
|
|
||
| ## 13장 - 두 개의 시스템에 대한 이야기 | ||
| 소프트웨어의 시스템은 마치 도시와 같다. 소프트웨어 도시의 품질은 도시 계획을 얼마나 잘 짰는지에 달려 있다. | ||
|
|
||
| **지저분한 대도시** | ||
| 책은 두 개의 시스템을 보면서 어떤 경험을 했는지 설명주며, 첫 번째는 “지저분한 대도시”이다. | ||
| 해당 프로젝트는 이미 성숙기에 접어들었지만, 복잡한 코드베이스로 아무런 설계가 있지 않았다. | ||
|
|
||
| > 소프트웨어는 건강하지 못한 회사 구조와 개발 절차로 인해 잘못 설계될 수 있다. | ||
|
|
||
| 나쁜 설계로 인해 추가 부분은 더 나쁜 설계로 이루어질 수 밖에 없었고, 신규 인력들은 복잡함으로 인해 파악하기 힘들었다. | ||
| 응집도 또한 부족하였고 각 기능 단위와 데이터 처리 부분의 위치가 잘못되었다. | ||
| 모듈 간 의존성 측면에서 대부분의 결함은 단방향이 아닌 양방향으로 이루어져 있었다. | ||
| 이로 인해 하나의 컴포넌트를 조금이라도 변경하면 다른 수많은 연관 컴포넌트도 바꿔야 했다. 즉 모든 컴포넌트는 단독으로 작동하지 않았다. | ||
| 그 결과 low-level 테스트, 코드 수준에서의 단위 테스트, 컴포넌트 수준에서의 통합 테스트가 불가능했다. | ||
|
|
||
| > 나쁜 구조로 인한 문제는 코드 대부에 한정되지 않는다. 외부와도 연계되어 개개인과 팀, 업무 처리 과정, 일정 산정 모두에 악영향을 미친다. | ||
|
|
||
| **디자인 타운** | ||
| 지저분한 대도시와 동일한 기술을 기반으로 한 제품이며, 다른 방식으로 만들어졌고 내부 구조도 완전히 달랐다. | ||
| 가장 중요한 기능 영역에 대해서만 초기 설계 단계부터 집중하였다. | ||
| 기본적인 유지 보수를 위한 부분에 있어서도 코드를 작성하기 쉽고 응집되도록 하는 방향으로 빠르게 결정했다. | ||
| 설계와 코드 작성은 모두 페어 프로그래밍 방식으로 이루어졌고, 작업이 정확히 이루어졌는지 확정하기 위해 세밀한 코드리뷰가 진행되었다. | ||
|
|
||
| > 명확한 구조 설계를 통해 일관된 시스템을 구성할 수 있다. 모든 설계 결정은 전체 구조 설계의 관점에서 수행해야 한다. | ||
|
|
||
| > 소프트웨어 구조는 불변의 것이 아니다. 필요하다면 변경하라. 변경 가능하게 만들려면 구조를 간결하게 유지해야 한다. 간결성을 빼앗는 변화에 저항하라. | ||
|
|
||
| 디자인 타운의 품질을 향상시킬 수 있게 도와준 XP 원칙은 바로 YAGNI였다. | ||
| “Don’t do anything if You Aren’t Going to Need It”. | ||
| 결정을 적절히 미루는 것은 설계에 대한 대단히 강력한 접근이었으며 상당히 자유로운 것이었다. | ||
|
|
||
| > 필요해질 때까지 설계상의 결정을 미루라. 요구 사항을 파악하기 전까지 구조 설계를 하지 말라. 추측하지 말라. | ||
|
|
||
| ## [논의 내용] | ||
| * 이진 탐색 전략을 이용할 수 있는 Git 명령어(git bisect)를 이번에 처음 알게 되었습니다. 기능이 매우 흥미롭게 보이는데, 실제로 사용해본 경험이 있으신 분이 있는지 궁금합니다! | ||
| * 책에서는 테스트 이름을 어떻게 작성할지 어느정도 설명해주는데, 실제로 다른 분들께서는 어떤 식으로 이름을 작성하시는지 경험을 공유해보고 싶습니다. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 메서드 이름을 문장 형태로 만듭니다. 예를 들면
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제 개인적으로는 팀내 팀원들이 식별할 수 있다면, 어떤 방식을 써도 괜찮다는 입장입니다 딱히 어떤 방식을 썼을 때 더 좋다 나쁘다 에 대해서 못느끼다보니 요렇게 생각하게 된 것 같네요
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 성공 케이스는 ~~ 여야한다, ~~ 해야한다 등으로 끝맺고, 실패 케이스는 예외 종류까지 명시하고 있습니다. (e.g. ~~하면 XXException 예외가 발생한다. ) |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 처음 알게 되었습니다.
실제 쓰게 된다면 commit log가 많아야 할텐데
저의 경우는 commit 단위와 pull request 단위의 큰 차이가 없어서 쓸 일이 없을 것 같기도 하네요.
보통 one pull request에 one to four commits 로 합니다.
4 commits로 bisect 한다면 명령어 두 번이면 되겠군요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
존재는 알고 있었지만, 실무에서 직접 활용해본적은 없는데, 딱히 활용할만한 상황이 없어서 그런것 같네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 이번 기회에 처음 알게 되었고 간단히 검색해보았을 때는 스크립트를 통해 버그여부를 확인해 탐색을 한다고 하는데 언젠가 필요하다면 한 번 사용해보고 싶네요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전에 pro git 스터디할 때 그냥 훑고 넘어간 정도라서 사용해보지는 않았습니다.