•
작성자: @한재엽
•
Updated: 22.6.26
Table of Contents
총평
Part I. 전제
Chapter 1. 소프트웨어 엔지니어링이란?
•
소프트웨어 엔지니어는 시간의 흐름과 언젠가 변경될 가능성에 더 신경써야 한다.
•
소프트웨어 기대 생애 동안 요구되는 모든 가치 있는 변경에 대응할 수 있다면 그 프로젝트는 지속 가능하다. 라고 할 수 있다.
•
소프트웨어 엔지니어링이란 여러 버전의 프로그램을 여러 사람이 참여해 개발하는 것이다.
•
“기발한”이 칭찬으로 느껴지면 프로그래밍이라 하고, 질책으로 느껴진다면 소프트웨어 엔지니어링이라고 한다.
•
개발 프로세스, 업무 프로세스는 눈치채기 어렵게 천천히 나빠지는 경향이 있다. “끓는 물 속 개구리가 되지 않도록 주의하자”
•
비욘세 규칙 (The Beyonce Rule)
◦
인프라를 변경하여 서비스가 중단되는 등의 문제가 발생하더라도, 같은 문제가 지속적 통합 시스템의 자동 테스트에서 발견되지 않는다면 인프라 팀의 책임이 아니다.
⇒ 네가 좋아했다면 CI 테스트를 준비해뒀어야지.
•
원점 회귀?
◦
개발 과정에서 문제를 일찍 발견할수록 비용이 적게 든다.
◦
타임라인에서 문제 발견 시점을 왼쪽으로 이동시킬수록 수정 비용이 줄어든다.
▪
개념잡기 → 설계 → 구현 → 리뷰 → 테스트 → 커밋 → 카나리 → 배포
•
비용이란?
◦
경제적 비용 (돈)
◦
리소스 비용 (하드웨어)
◦
인적 비용 (엔지니어링)
◦
거래 비용 (실행에 옮기는 비용)
◦
기회 비용 (실행에 옮기지 않는 비용)
◦
사회적 비용 (선택이 사회 전체에 미치는 영향에 대한 비용)
•
좋은 엔지니어링 결정이란 가용한 모든 근거 자료에 적절한 가중치를 부여하고 이러한 지식을 바탕으로 균형점을 잡는 일.
◦
반드시 해야 하는 일 (법적 요구사항, 고객 요구사항)
◦
근거에 기반하여 내릴 수 있는 최선의 선택
Action Item
원점회귀 할 수 있는 시스템 만들기
•
Design review request (or Pre-commit review)
•
Pair programming time
•
Testing Study
테스트 환경 구축과 테스트 문화 만들기 (진정한 지속적 통합 환경 만들기)
•
테스트 scaffolding
•
learning share
•
best practice
Part II. 문화
Chapter 2. 팀 워크 이끌어내기
•
인간은 간헐적 버그들의 집합에 가깝다.
•
혼자 일하려 한다면 실패할 위험성을 불필요하게 키우고 자신의 성장 잠재력을 속이는 것이다.
•
조기 공유?
◦
이미 구현된 선례가 있는 것은 아닌지 파악할 수 있다.
◦
초기 설계에 숨겨져 있는 근본적인 실수를 방지할 수 있다.
◦
혼자하는 것보다 아무튼 더 빠르게 할 수 있다.
◦
프로젝트의 버스 지수(Bus factor)를 높일 수 있다.
•
사회적 상호작용의 세 기둥
◦
겸손(Humility)
▪
당신은 모든 것을 알지도 완벽하지도 않습니다. 겸손한 사람은 배움에 열려 있습니다.
◦
존중
▪
함께 일하는 동료를 진심으로 생각합니다. 친절하게 대하고 그들의 능력과 성취에 감사해합니다.
◦
신뢰
▪
동료들이 유능하고 올바른 일을 하리라 믿습니다. 필요하면 그들에게 스스로 방향을 정하게 해도 좋습니다.
•
우리 자존감을 우리가 작성한 코드와 동일시해서는 안 됩니다. 나는 내 코드가 아님을 명심하세요.
◦
자신과 만든 것을 구분짓고 자신을 믿고 동료를 믿으세요.
Action Item
•
코드 리뷰 가이드 만들어보기
Chapter 3. 지식 공유
•
다음 두 가지가 먼저 자리 잡아야 지식이 전파될 수 있다.
◦
모르는 것을 인정할 수 있도록 돕는 심리적 안전
◦
배우고자 하는 배움의 문화
•
안티패턴
◦
거짓된 놀람 금지: 뭐? useCallback이 뭔지 모른다고?
◦
세세하게 고쳐주기 금지: 자신을 뽐내려는 무의식에 기인하는 경향이 있다.
◦
뒷자석 운전 금지: 토론 중 적절한 발언권 없이 끼어들어 의견 제시하지 말기
•
지식 공유는 질문에서부터
•
쿠도스 제도 (공개칭찬)
◦
동료의 기여를 공개적으로 인정하는 제도
Action Item
•
심리적 안전을 위한 환경이 구축될 수 있도록 고민하기
•
Weekly I Learned 라는 코너?
Chapter 4. 공정 사회를 위한 엔지니어링
•
편견에서 벗어날 수 없다.
◦
이를 인정하고 의식적으로 개선하려 하자.
◦
다양한 사용자 층을 포용하기 위해선 조직 구성에 있어서도 다양성을 갖춰야 한다.
•
자신을 솔직하게 바라보고 성찰하자
•
모두를 위해 만들지 말자. 모두와 함께 만들자
•
제품을 이용하기 가장 어려운 이들을 위해 설계하자
•
가정하지 말고, 시스템 전반의 공정성을 측정하자
•
변할 수 있다
•
일부 사용자에게 해를 끼칠 수 있는 제품이라면 출시를 늦추는 것이 맞다
Action Item
인터뷰어 풀 신경쓰기
접근성 공부하고 라이트닝 톡 준비하기
Chapter 5. 팀 이끌기
•
Manager: 사람을 이끈다.
◦
엔지니어링 관리자 (EM)은 구성원의 성과, 생산성, 행복을 책임지면서 제품의 사업적 요구까지 충족시켜야 한다.
•
Tech Lead: 기술과 관련된 책임을 진다.
◦
직접 나서서 일을 빠르게 처리하기도 하고
◦
다른 팀원에게 위임할지 판단한다.
◦
규모와 역량이 커질수록 위임하는 편이 낫다.
•
테크 리드 매니저 = Manager + Tech Lead
•
바나나를 재배하면서 사과를 세는 함정에 빠지지 말 것
◦
관리 업무는 효과가 나타나기까지 보통 더 긴 시간을 인내해야 한다.
•
피터의 법칙
◦
자신의 무능력이 드러나는 직급까지 승진하는 경향
•
Servant Leadership
◦
마치 집사가 가정의 안녕과 건강을 챙기듯, 팀을 떠받드는 것
◦
관리하려는 충동을 이겨내는 것
•
무슨 일을 처리할지 고민하고(What) 어떻게 처리할지는 팀에게 믿고 맡긴다.
•
안티패턴
◦
안티패턴 1. 만만한 사람 고용하기
▪
좌지우지할 수 있는 사람을 고용해서 권위와 위치를 공고히 한다
◦
안티패턴 2. 저성과자 방치
▪
기대를 충족해주지 못하는 사람을 다루는 것이 가장 고난이도 문제
▪
팀은 누가 저성과자인지 정확하게 알고 있다
▪
저성과자를 방치하는 것은 고성과자가 팀에 합류하는 것을 막고 고성과자가 팀을 떠나게 하는 요소가 된다.
▪
기간을 정하고 구체적인 목표를 제시할 것.
▪
점진적이고 측정가능한 목표.
◦
안티패턴 3. 사람문제 무시하기
▪
사회적 문제 / 기술적 문제 둘 다 신경쓸 것
◦
안티패턴 4. 만인의 친구되기
◦
안티패턴 5. 채용 기준 타협하기
◦
안티패턴 6. 팀을 어린이처럼 대하기
•
올바른 패턴
◦
자존심 버리기
▪
대신 집단으로서의 자존심과 정체성 강화하기
◦
마음 다스리기
▪
평정심 유지하기
▪
사람들을 고무시키는 것
▪
스스로 문제를 해결하도록 질문하고 직접 해결하기는 가장 마지막에 택하기
◦
촉매재가 되기
▪
팀원간의 상호작용을 만들기
◦
장애물 치우기
▪
정확한 답을 알고 있기 보다 올바른 사람을 알고 연결해주기
▪
꼭 멈춰야 된다고 생각되는 열차만 선택해서 멈추기
◦
선생이자 멘토되기
▪
멘티에게 도움이 얼마나 필요한지 측정하고 적절하게 input 넣기
◦
명확한 목표 세우기
▪
사명감
◦
정직하기
▪
피드백을 칭찬 속에 숨기지 말기
◦
행복한지 확인하기
•
경력 관리 챙겨주기
◦
새로운 것 배우기
◦
의미있는 제품, 서비스 론칭
◦
똑똑한 사람들과 일하기
▪
등을 성취할 수 있도록 고민하기
•
위임하되 곤란한 일은 직접 처리하기
•
대신할 사람을 찾기
•
혼란으로부터 팀을 보호하되 정직하기
◦
가능한 한 많은 정보를 팀과 공유하되 업무에 방해받지 않도록 하기
Action Item
엔지니어 경력 프레임워크 만들어서 경력 개발 1on1 하기
프런트엔드 챕터의 목적 생각해보기
플랫폼 팀의 이니셔티브 정의하기
Chapter 6. 성장하는 조직 이끌기
•
Always Be Deciding (늘 결정하라)
◦
이 결정대로 시도해보고 어떻게 되는지 지켜보자. 상황을 보고 그 때 또 결정해보죠.
•
Always Be Leaving (늘 떠나기)
◦
스스로 single point of failure 되지 않도록 하기
◦
이 문제를 처리할 수 있는 사람이 정말 나뿐일까?
◦
업무 크리티컬 패스 상에서 내가 사라지도록 하기
◦
관찰과 경청 9%, 절묘하고 시의적절한 개입 5%
•
Always Be Scaling (늘 확장하라)
◦
상황을 주도하는 능동형 일보다 상황에 맞춰 대응하는 반응형 일의 비중이 커진다.
◦
급한 문제와 중요한 문제가 있는데, 급한 문제는 중요하지 않고 중요한 문제는 급하지 않다.
◦
나만이 할 수 있는 일을 처리해야 한다.
◦
따로 blocking 시간을 준비해둘 것.
◦
정말 중요한 20% 남기고 나머지 80%는 버릴 것.
Action Item
최대한 위임하기
blocking 시간 마련하기
Chapter 7. 엔지니어링 생산성 측정하기
•
조직이 2배 커지면 소통 비용은 제곱으로 늘어난다. - 맨먼스 미신
•
선별하라. - 측정할 가치가 있는가?
◦
어떤 결과를 기대하고, 왜 그런가?
◦
데이터가 기대한 결과를 뒷받침 한다면 어떤 조치를 취하겠는가?
▪
딱히 액션이 없다면 측정할 가치가 없다. (현상 유지 편향)
◦
부정적인 결과가 나온다면 적절한 조치를 취할 것인가?
▪
대부분의 경우 이미 정해진 진로를 잘 틀지 않는다.
▪
결과가 부정적이더라도 딱히 액션이 없다면 측정할 가치가 없다.
◦
결과에 따른 조치는 누가 결정하고, 언제 수행하는가?
▪
결과, 결정에 따라 수행할 여유가 있는가?
◦
결과가 상대적으로 긴 시간동안 유의미한가?
◦
측정 결과를 단순히 계획의 뒷받침 용도로 쓰려고 하는가?
◦
측정할 수 있는 지표들이 문제를 평가하기에 충분히 정확한가?
•
GSM 프레임워크 기반의 선별
◦
Goal (목표): 원하는 최종 결과를 고차원 어휘로 표현한다.
◦
Signal (신호): 최종 결과를 이뤘는지 판단하는 방법
◦
Metric (지표): 실제로 측정하는 대상
•
엔지니어링 생산성을 구성하는 다섯가지 요소, 퀀츠(QUANTS)
◦
코드 품질 (Quality of the code)
◦
엔지니어들의 몰입도 (Attention from engineers)
◦
지적 복잡성 (Intellectual complexity)
◦
박자와 속도 (Tempo and velocity)
◦
만족도 (Satisfaction)
Action Item
•
측정하고자 하는 대상이 있는지, 있다면 GSM 기반으로 분석해보고 측정 시작하기
•
생산성을 개선할 수 있는 요소가 있는지 살펴보기
Part III. 프로세스
Chapter 8. 스타일 가이드와 규칙
•
규칙은 좋은 행동을 장려하고 나쁜 행동을 억제하기 위해 필요하다.
•
이루고자 하는 목표를 명확히 했을 때, 규칙이 따라온다.
•
규칙을 만들 땐,
◦
규칙의 양을 최소화 해야 한다.
◦
코드를 읽는 사람에게 맞춰야 한다.
◦
일관되어야 한다.
◦
예상치 못한 동작을 유발하는 구조는 피해야 한다.
◦
실용성을 생각해 예외를 허용한다.
•
코드는 작성되는 횟수보다 읽히는 횟수가 더 많으며 시간이 지날수록 더 벌어진다.
◦
쓰기에 간편함보다 읽기에 간단한 쪽에 가치를 둔다.
•
주석?
◦
문서화 주석과 구현 주석으로 나뉜다.
◦
문서화 주석은 jsdoc을 생각하면 된다.
◦
구현 주석은 뻔하지 않은 선택을 한 이유를 명시하기 위해 사용된다.
•
일관성
◦
코드가 일관되면 의미 단위로 잘 구분되어 분석하기 쉬워진다.
◦
어떻게 구현할지 고민하는 대신 무엇을 수행하느냐에 집중할 수 있다.
◦
모듈화하기도 쉽다.
•
규모가 커지면서…
◦
완전히 일관되는 일은 없을 것이며 그것을 목표로 삼지 않게 되었다.
◦
완벽한 일관성을 추구하기에는 얻는 것보다 비용이 큰 단계에 도달한 것이다.
◦
jscodeshift 같은 도구로 일괄 변경해도 완벽하지는 않기 때문이다.
•
스타일 가이드의 목적
◦
위험을 피하기 위함인가?
◦
모범 사례를 적용하기 위함인가?
◦
일관성을 보장하기 위함인가?
•
규칙은 고정불변이 아니다.
◦
다른 결론에 도달할 수 있는지를 다시 평가할 수 있다.
•
투표가 아니라 합의로 이뤄진다.
◦
개인 취향은 무시한다.
◦
트레이드 오프 평가에 기초하여 의사결정한다.
◦
다수결이 아니다.
•
가능한 규칙들은 ‘자동으로' 적용되게끔 해야 한다.
Action Item
•
운영중인 ADR을 스타일 가이드로 수정하고 근거가 되는 스레드를 추가한다.
◦
UX Engineering 부분도 살펴보자.
•
규칙을 변경할 수 있는 프로세스를 고민해본다.
◦
GitHub Discussion?
•
자동화 영역이 남아있는지 확인해본다.
Chapter 9. 코드 리뷰
코드 리뷰는 작성자 이외의 사람이 코드를 비판적으로 검토하는 프로세스이다.
구글에서 코드 리뷰는 소프트웨어 엔지니어라면 모두가 반드시 따라야 하는 몇 안 되는 전사적인 프로세스이다.
•
코드는 부채다
◦
코드가 그 자체로 부채임을 인정해야 한다.
◦
존재만으로 어느 순간 누군가가 유지보수해야 할 대상이 된다.
◦
밑바닥부터 만들고 있다면 뭔가 잘못하고 있는 것이다.
▪
누군가 비슷한 코드를 이미 작성해놓았을 가능성이 크다.
◦
새로운 걸 설계할 때는 작성 전에 챕터에서 이야기하면 좋다.
•
무엇을 검토하는가?
◦
정확성
◦
이해 용이성
◦
가독성
•
고민
◦
이 코드는 유지보수하기 쉬운가?
◦
내게 기술 부채를 안겨주나?
◦
우리 팀원 중에 이 코드를 유지보수해줄 전문가가 있나?
•
뭐가 좋지?
◦
코드가 정확한지 확인한다.
▪
일반적으로 변경 작성자가 선택한 방식을 존중해준다.
▪
완벽하다고 합의될 때까지 기다리지 않고 코드베이스를 개선한다고 인정되면 변경을 승인한다.
▪
완벽할 필요가 없다.
◦
변경된 코드를 다른 엔지니어도 잘 이해한다.
▪
지속해서 유지 가능한 코드인지 검토한다.
◦
코드베이스가 일관되게 관리된다.
▪
일정한 표준을 따라야 조직 안에서 이해되고 유지보수될 수 있다.
◦
팀이 소유권을 더 강하게 느낀다.
▪
리뷰 프로세스로 모노레포는 조직의 공동 소유물임일 인식시킨다.
◦
지식이 공유된다.
◦
코드 리뷰 자체의 기록이 남는다.
•
모범 사례
◦
방식에 결함이 있을 때만 대안을 제시한다.
◦
방식이 잘못되었다고 가정하기 전에 그렇게 처리하게 된 이유가 무엇인지부터 물어본다
◦
신속하게 피드백한다.
◦
제안한 변경은 팀의 소유임을 잊지 말아야 한다.
◦
작성자 또한 왜 그렇게 처리했는지 설명할 준비를 해둬야 한다.
◦
리뷰어가 단 댓글은 모두 할일로 취급해야 한다.
◦
작성자와 리뷰어 모두에게 배움의 기회임을 기억해야 한다.
•
요청자 입장에서,
◦
작게 만들어야 한다.
▪
200줄 이하
◦
변경에 대한 설명을 잘 써야 한다.
▪
무엇을 왜 변경하는지,
◦
리뷰어는 최소한으로
◦
가능한 자동화 한다.
•
코드 리뷰의 종류는?
◦
그린필드 리뷰 (신규 프로젝트 또는 새로운 기능)
▪
초기에 내린 가정들이 변해도 여전히 유지보수하기 쉬워야 한다.
▪
설계 리뷰를 강도 높게 진행한다.
▪
소유자를 명확히 한다.
◦
동작 변경, 개선, 최적화
◦
버그 수정 (롤백)
▪
기능 추가가 포함되어선 안 된다.
▪
롤백을 유발할 수 있는 모든 변경은 가능한 작고 원자적이어야 한다.
◦
리팩터링과 대규모 변경
Action Item
•
코드 리뷰 가이드 만들어보기
코드 리뷰 관련해서 계속 개선해나갈 working group 만들기
Chapter 10. 문서
•
문서도 코드와 같다.
◦
문서에 정책과 규칙이 있어야 한다.
◦
버전 관리 시스템에 등록해 관리해야 한다
◦
관리 책임자를 명시해야 한다
◦
변경 시 리뷰를 거쳐야 한다
◦
주기적으로 평가해야 한다.
◦
최신 정보 반영 여부가 확인되어야 한다.
◦
하나의 문서는 하나의 목적에 집중해야 한다.
•
종류
◦
참조용 문서 자료
◦
설계 문서
◦
튜토리얼
◦
개념 설명 자료
◦
랜딩 페이지
•
문서화
◦
누가: 대상 독자가 누구인지 문서 안에서 명확히 밝혀줘야 할 때가 있다.
◦
무엇: 목적
◦
언제: 문서가 생성되고, 리뷰되고, 갱신된 날짜가 명시되어 있어야 한다.
◦
어디에: 장소
◦
왜: 목적, 문서에 대한 소개에 들어가곤 한다.
•
좋은 문서
◦
의도한 역할을 잘 수행하는 문서
•
폐기
◦
신선도 보증 기간
◦
마지막으로 리뷰한 날짜를 기준으로 3개월 동안 갱신되지 않을 시 알림 메일을 보낸다.
•
문서 자료를 테스트와 같은 수준으로 취급해야 할지는 모르겠다.
◦
하지만 문서는 조직의 규모가 커질수록 중요해진다.
Action Item
문서 쓸 때는 작성자와 날짜 남기는 습관 들이기
•
GitHub에서 문서를 관리해야 하나 싶기도…
Chapter 11. 테스트 개요
테스트는 엔지니어에게 신뢰를 줄 때만 가치가 있다.
•
작성한 테스트는 수시로 실행될 수 있어야 한다.
•
Why?
◦
디버깅 감소
▪
코드의 존속 기간 전체로 봤을 때, 결함이 줄어든다.
◦
자신있게 변경 할 수 있다.
▪
리팩터링을 통해 코드 품질을 끊임없이 개선할 수 있다.
◦
더 나은 문서자료
▪
애플리케이션의 행위를 기술함으로써 문서로써의 역할을 한다.
◦
더 단순한 리뷰
▪
리뷰할 때도 동작을 예측하기 쉽다
◦
설계
▪
테스트를 잘 작성하면 잘못된 설계를 바로잡을 수 있다.
•
불필요한 노출 등을 숨기면서 더 응집도 높은 설계가 만들어진다.
•
테스트를 작성하는 것과 ‘잘' 작성하는 것은 별개이다.
◦
테스트를 작성하고 맨날 깨진다고 하는 것은 테스트를 잘못 작성했기 때문이다.
◦
대개 테스트에 대한 공부없이 테스트를 작성하곤 한다.
◦
테스트의 장점을 크게 누리지 못한 사람들이 부정적인 견해를 드러내곤 한다.
•
테스트는 두 가지 기준으로 분류할 수 있다.
◦
크기: 테스트 케이스 하나를 실행하는데 필요한 자원 (메모리, 프로세스, 시간)
▪
(LOC가 아니라) 프로세스 하나, 기기 하나, 여러 기기에서 테스트가 돌아감을 기준으로 크기를 구분짓는다.
▪
전통적인 단위 테스트, 통합 테스트 대신 크기로 구분짓는다.
▪
큰 테스트는 가장 복잡하고 검증하기 어려운 시나리오에만 제한적으로 활용한다.
◦
범위: 검증하려는 코드 경로
•
크기에 따른 테스트
◦
작은 테스트
▪
하나의 프로세스에서 실행되어야 하는 테스트 ( → 스레드 )
▪
테스트도 테스트 대상 코드와 같은 프로세스에서 실행되어야 한다.
▪
네트워크와 디스크에 접근하는 블로킹 호출을 사용해선 안 된다.
•
필요한 경우 테스트 대역을 사용한다.
◦
강한 의존성을 가벼운 인프로세스 의존성으로 대체해주는 수단
•
Why?
◦
블로킹 호출이 작은 테스트에 포함되면 전체적인 테스트 수행 속도가 느려진다.
◦
외부와 의존하게 되면서 불규칙한 결과가 나오고 이로 인해 테스트 수행 결과가 비결정적이 된다.
▪
범위와 상관없이 언제나 작은 테스트를 작성하길 권장한다.
◦
중간 테스트
▪
블로킹 호출을 이용할 수 있으나(로컬호스트) 외부 시스템과의 통신은 불허한다.
▪
흔히 말하는 통합테스트: 웹 UI와 서버 코드의 조합도 테스트 할 수 있다.
▪
외부 요인이 개입되므로 성능과 결정성을 온전히 우리 스스로가 보장할 수 없다.
◦
큰 테스트
▪
여러 개의 기기를 활용할 수 있다.
▪
비결정성으 크게 높아지기 때문에 몇 가지 용도에 한정해서 활용한다.
•
end to end test는 설정을 검증하는게 주된 목적이다.
▪
빌드나 릴리스 때만 수행되도록 하여 개발 워크플로우에 영향을 주지 않도록 한다.
•
크기와 상관없이 테스트의 공통 특성
1.
하나의 테스트 suite는 밀폐되어 있어야 한다.
•
setup, execute, tear down 하는데 필요한 모든 정보를 담고 있어야 한다.
•
테스트 수행 순서 같은 외부 환경에 관해서는 가능한 한 아무것도 가정하지 않아야 한다.
2.
확인하려는 행위를 수행하는 데 필요한 정보’만’ 포함해야 한다.
3.
무엇을 검사하는지가 명확해야 한다.
a.
정확성 검사는 사람이 직접해야 하기 때문에 조건문이나 순환문 같은 제어문은 쓰지 않는게 좋다.
b.
복잡해질수록 버그가 발생할 수 있으며 실패 원인을 파악하기 힘들어진다.
4.
테스트는 오직 실패했을 때만 들여다봐야 한다.
•
범위에 따른 테스트
◦
좁은 범위 테스트: 보통 단위 테스트
◦
중간 범위 테스트: 보통 통합 테스트
◦
넓은 범위 테스트: 보통 기능, 종단간 테스트
◦
구글은 되도록 작은 테스트, 좁은 범위 테스트를 추구한다.
▪
크기, 범위 별로 80:15:5 비율을 유지한다.
•
커버리지는 테스트되지 않은 코드가 어디인지 알려줄 수 있지만 시스템이 얼마나 제대로 테스트되었느냐를 판가람하는 지표로는 적합하지 않다.
•
구글의 테스트 혁명
◦
오리엔테이션 수업
◦
테스트 인증 프로그램
◦
화장실에서도 테스트
Action Item
•
테스트 혁신 진짜 해야겠다
Chapter 12. 단위 테스트
•
단위테스트는
◦
빠르고 결정적이어서 개발자들이 수시로 수행하며 피드백을 즉각 얻을 수 있다.
◦
작성하기 쉽다.
◦
실패 시 원인을 파악하기 쉽다.
◦
자연스럽게 예제 코드가 되며 문서 역할을 하게 된다.
•
1원칙: 테스트는 유지보수하기 쉬워야 한다. (maintainability)
◦
무엇이 테스트를 신뢰하지 못하게 하는가?
▪
검증 대상과 관련 없는 변경 때문에 실패하는 ‘깨지기 쉬운 테스트’ 때문에 (brittle)
▪
깨지면 무엇을 고쳐야 하는지 파악하기 어려운 ‘불명확한 테스트' 때문에 (unclear)
•
깨지기 쉬운 테스트 예방하기
◦
실제로 버그가 없음에도 상관없는 변경 때문에 실패하는 테스트
◦
테스트가 변경에 영향을 덜 받도록 해주는 패턴을 찾자.
•
테스트는 시스템의 요구사항이 바뀌지 않는 한 수정할 일이 없어야 한다.
◦
행위를 의도적으로 변경하는 경우에는 테스트도 함께 갱신해줘야 한다.
▪
이 경우, 작성된 테스트를 먼저 수정해도 좋다.
•
리팩터링 시 테스트가 깨졌다면?
◦
리팩터링 중 기능이 변경되진 않았는지 살펴보자
◦
테스트의 추상화 수준이 적절하지 못하진 않았는지 살펴보자
▪
세부 구현에 의존하고 있진 않았는지?
•
공개 API를 이용해 테스트 한다.
◦
공개 API란 서드파티에 노출한 API를 말한다.
◦
테스트 코드도 다른 사용자가 시스템을 호출하는 방식과 똑같은 방식으로 시스템을 호출한다.
◦
“사용하듯이”
◦
private 접근자를 제거하고 노출시킨다음 테스트하고 싶은 유혹을 떨쳐낼 것.
◦
보조하는 용도가 다인 메서드나 클래스라면 독립된 단위로 생각하지 않는 것이 좋다.
▪
고민) 한 컴포넌트에서만 사용되는 hooks는 독립된 단위가 아니기 때문에 따로 테스트하지 않고 이를 사용하는 컴포넌트를 통해서 테스트되도록 테스트 케이스를 구성한다????????????
◦
다방면으로 유용한 기능을 제공하도록 설계된 패키지나 클래스는 직접 테스트해야 하는 단위이다.
▪
hooks라도 유틸성 hooks는 테스트 대상이다.
•
상호작용이 아니라 상태를 테스트하자.
◦
대부분의 상황에서, 상호작용 테스트는 상태 테스트보다 깨지기 쉽다.
▪
상태 테스트는 결과가 “무엇인지”에 집중하고 (What)
▪
상호작용 테스트는 시스템이 “어떻게 작동하냐”를 확인하려 하기 때문이다. (How)
◦
상태 테스트: 메서드 호출 후 시스템 자체를 관찰
◦
상호작용 테스트: 호출을 처리하는 과정에서 다른 시스템과 협력하여 기대한 일련의 동작을 수행하는지 확인할 때
◦
상호작용 테스트가 만들어지는 가장 큰 원인은 모의 객체 프레임워크에 지나치게 의존하기 때문
▪
가짜 객체는 변한값을 반영하지 않기 때문
•
명확한 테스트를 작성하자.
◦
명확한 테스트란 존재 이유와 실패 원인을 엔지니어가 곧바로 알아차릴 수 있는 테스트를 의미한다.
◦
완전하고 간결한 테스트를 작성하면 된다.
▪
테스트 코드를 읽는 사람 입장에서 이 테스트를 이해하는 데 필요한 모든 정보를, 테스트 케이스 본문에 담고 있는 테스트를 말한다.
▪
이와 동시에 관련없는 정보는 담지 않아야 한다.
•
관련없는 정보가 포함되어 있다가 상관없는 변경으로 인해 테스트 케이스가 깨지기 마련이다.
▪
공통 객체를 사용하는 대신에, 헬퍼 메소드를 사용하여 값 객체를 만들자.
◦
메서드가 아니라 행위를 테스트하자
▪
행위란 특정 상태에서 특정한 일련의 입력을 받았을 때, 시스템이 보장하는 ‘반응'을 뜻한다.
▪
메서드 당 테스트 케이스 1개일 필요가 없다. 1:N의 관계이다.
•
메서드가 여러개만 N:N의 관계인 것이다.
▪
테스트 케이스 하나에서 하나의 행위만 테스트하자.
•
코드가 많아지지만, 더 좁은 범위이기 때문에 실패했을 때 그 원인을 좀 더 빠르게 파악할 수 있다.
•
테스트 명세가 한 가지만 드러내므로 더 파악하기 쉽다
◦
테스트의 구조는 행위가 부각되어야 한다.
▪
given, when, then으로 구분지어서 표현하기도 한다.
•
given: 시스템 설정을 정의한다.
•
when: 시스템이 수행할 작업을 정의한다.
•
then: 결과를 검증한다.
▪
여러 단계로 진행되는 작업은 교대로 when, then을 정의해도 된다.
▪
긴 블록의 경우 and로 연결해줄 수도 있다.
◦
테스트 명세는 행위 중심이 되어야 한다.
▪
동작과 예상 결과를 모두 담아야 한다.
▪
테스트 이름에 “그리고”가 들어가면 테스트 케이스를 나눠야 하나? 하는 의심을 할 수 있다.
•
테스트에 논리를 넣지 말자
◦
약간의 중복을 허용하더라도 순회문이나 조건문은 배제하자
◦
직설적인 코드로 작성하자
◦
DRY대신 DAMP(Descriptive And Meaningful Phrase)
•
공유 도우미 메서드와 공유 검증 메서드
◦
테스트용 값을 생성하는 코드 부분을 공유 도우미 메서드를 사용할 수 있다.
◦
검증을 공유 검증 메서드로 처리한다면?
▪
버그 하나로 인해 여러 테스트가 동시다발로 실패할 수 있다.
◦
공유 검증 메서드는 단 하나의 개념적 사실만을 검증해야 한다.
Action Item
•
테스트 혁신 가즈아!
Chapter 13. 테스트 대역
•
테스트 대역을 사용하면 실제 구현을 테스트 대역으로 교체하여 테스트할 수 있게 됩니다.
•
하지만 잘못사용하면 깨지기도 쉽고 복잡하고 효율도 나쁜 테스트로 전락합니다.
•
그렇기 때문에 되도록 실제 구현을 이용하시길 권합니다.
Part IV. 도구
트렁크 기반 개발, 모노레포, 정적분석 등 대부분 이미 토스에서 하고 있는 것들이라 메모가 적음.
(테스트가 메모가 많은 것도 동일한 이유)
Chapter 16. 버전 관리와 브랜치 관리
•
트렁크 기반 개발 짱
◦
트렁크 기반 개발과 뛰어난 소프트웨어 조직 사이에는 양의 상관관계가 존재
•
운 없는 엔지니어는 빌드 마스터, 병합 관리자, 콘텐츠 관리 엔지니어 같은 타이틀을 달고 조직 내의 모든 이질적인 브랜치를 병합하는 책임을 떠맡는다.
•
완벽하지 않거나 테스트되지 않는 기능은 비활성화하는 방향
◦
Feature Flag를 적극 활용하고 모든 변경사항은 main branch로 집어넣는다.
▪
(완전 동의)
◦
개발 브랜치를 만들지 말고, 만들더라도 매우 짧게 쓰고 없애야 한다.
◦
진행 중인 작업을 줄일 것
•
원 버전 정책
◦
모든 코드는 모노레포에.
◦
모듈들은 하나의 버전
▪
개발자가 이 구성요소는 어떤 버전을 사용해야 하죠?라고 묻는 상황을 만들지 않아야 한다.
•
빌드 호라이즌 정책
◦
프로덕션 환경에서 구동 중인 모든 제품은 최대 6개월 안에 다시 빌드하여 재배포해야 한다.
•
모노리포
◦
일관성 덕분에 도구를 새로 도입하거나 코드를 최적화한 혜택이 조직 전체에 훨씬 빠르게 전파된다.
Action Item
•
Feature flag 활성화 방안 생각해보기
Chapter 17. Code Search
사내 모노리포 검색 툴, 좋다는 자랑!
•
왜?
◦
이 코드가 왜 추가되었는가? 왜 이런 식으로 동작하는가? 에 대한 답을 찾기 위해 검색 목적으로 사용
◦
특정 시점의 코드베이스 상태를 찾기 위해
▪
새로 추가한 코드가 실패할 경우, 몇 분 전 추가된 변경을 살펴볼 때 사용
Chapter 18. 빌드 시스템과 빌드 철학
•
빌드?
◦
의존 관계를 생각해서
◦
각 조각을 올바른 순서로
◦
그 조각에 적합한 도구를 이용하여
◦
해야 하는 것
•
Not 태스크 기반의 빌드 시스템, But 아티팩트 기반의 빌드 시스템
•
원격 캐싱
◦
공통의 원격 캐시 서비스를 참조 (레디스 or GCP)
•
때로는 엔지니어의 힘과 유연성을 제한해야 생산성을 높일 수 있다.
•
의존성의 버전 관리는 너무 어렵다
•
작은 모듈 방식이 굵직한 모듈 방식보다 잘 확장된다.
Chapter 19. 구글의 코드 리뷰 도구, Critique
토스에서 사용하고 있는 프론트엔드 종달새 bot이 더 잘해주고 있음.
Chapter 20. 정적 분석
skip. 우리 챕터는 이미 너무 잘하고 있음
Chapter 21. 의존성 관리
•
안하는 것이 최선이다.
◦
모노레포에서 라이브러리, 서비스를 한꺼번에 관리하고 있어서 아직 필요성을 크게 느끼지 못하고 있음.
◦
필요하다면 외부 서드파티 라이브러리에 대한 의존성 관리가 필요함
•
라이브러리 분리는 아직 고려하지 않고 있음.