memo
메모
저자는 다양한 개발자를 만나면서, 최고의 개발자들이 가진 공통된 특성에 대해 고민하게 됨
이 글은 초보 개발자나 성장하고 싶은 사람들에게 영감을 주기 위해 작성된 관찰 기록임
레퍼런스 문서를 먼저 읽을 것
Stack Overflow나 LLM을 먼저 찾기보다는 공식 문서를 먼저 읽는 습관을 들이는 것이 중요함
Apache, Python, TOML 등의 공식 문서는 실제로 꽤 잘 작성되어 있음
소스에서 직접 배우는 습관은 장기적으로 큰 도움이 됨
도구를 깊이 이해할 것
도구를 ‘사용’할 줄 아는 것과, 그것을 ‘이해’하는 것은 다른 수준임
도구를 잘 아는 사람은 설정 하나하나를 설명할 수 있음
잘 이해하려면 도구의:
- 역사 (왜 만들어졌는가)
- 현재 (누가 관리하는가)
- 한계 (언제 안 맞는가)
- 생태계 (주변 도구, 라이브러리 등)
- 를 모두 파악하고 있어야 함
Kafka 등을 주력으로 쓴다면, Reddit에서 본 수준 이상으로 알고 있어야 함
에러 메시지를 꼼꼼히 읽을 것
에러 메시지를 곰곰이 들여다보면 힌트가 담겨 있음
최고의 개발자는 적은 정보만 보고도 문제를 추론함
문제의 80%는 에러 메시지만 잘 봐도 해결 가능함
문제를 잘게 나눌 줄 알 것
막히는 건 누구나 겪는 일이고, 잘게 나눌 수 있어야 풀 수 있음
경험이 많거나, 문제 해결 능력이 뛰어난 사람은 쉽게 나눔
개발자의 핵심 업무는 결국 큰 문제를 작은 문제로 나누는 작업임
단순한 문제들을 차근차근 풀면 전체 문제도 해결됨
두려움 없이 코드를 다룰 것
최고의 개발자들은 코드 읽기를 두려워하지 않음
“그건 내 영역이 아니야” 같은 말 없이 그냥 시도하고 배움
처음 다룬 코드도 금세 팀 내 전문가가 되는 경우가 많음
항상 다른 사람을 도울 것
바쁜 와중에도 도와주는 개발자는 좋은 팀원이자 훌륭한 전문가임
호기심과 협력적인 태도는 좋은 개발자의 필수 자질임
글을 쓸 것
뛰어난 개발자는 말도 잘하고, 생각을 글로 풀 줄 앎
블로그, 발표, 오픈소스 활동 등으로 생각을 나눔
글쓰기 능력은 사고의 구조와 직접적으로 연결되어 있음
잘 쓰는 사람의 코드는 구조적이고, 명확하고, 때론 재치있음
배움을 멈추지 말 것
나이와 상관없이 계속 배우는 사람이 진짜 뛰어난 개발자임
새로운 도구나 언어를 시도하는 것에 거리낌이 없음
최신 기술을 맹목적으로 따르지 않고, 장단점을 스스로 분석할 줄 앎
젊은 나이에도 고정관념에 빠지면 성장이 멈춤
지위에 연연하지 말 것
좋은 개발자는 직책과 상관없이 누구에게나 배움을 구함
신입에게도 배울 게 있다는 태도를 가짐
새로운 시각을 가진 사람들과의 대화에서 영감을 받음
명성을 쌓을 것
실력도 중요하지만, 실력을 알려지는 것도 중요함
명성은 영향력을 넓히는 수단임
다음과 같은 방법으로 명성을 쌓을 수 있음:
중요한 서비스를 직접 만들거나 배포함
잘 알려진 도구를 개발함
유명한 오픈소스에 기여함
자주 인용되는 책을 씀
명성은 하루아침에 쌓이지 않으며, 꾸준한 노력과 시간이 필요함
인내심을 가질 것
사람과 컴퓨터 모두에게 인내심이 필요함
주변 사람은 바보가 아니라 정보가 부족한 것일 뿐임
인내심 없으면 쉽게 불만이 쌓이고 협업이 어려워짐
어려운 문제를 해결하려면 집중력과 끈기가 필요함
컴퓨터를 탓하지 말 것
최고의 개발자는 절대 시스템이나 외부 요인을 탓하지 않음
겉보기엔 무작위로 보이는 문제도 논리적인 이유가 있음
원인을 찾기 위해 끝까지 파고드는 태도가 중요함
“모르겠습니다”를 말할 줄 알 것
인터뷰에서 일부러 “모르겠습니다”를 말하는 순간을 기다린 적 있음
중요한 건 답이 아니라 태도임
최고의 후보는 모른다고 인정하고, 추론을 시작함
모른다고 인정하는 태도는 학습 가능성을 보여줌
거짓말하거나 아는 척하는 사람은 팀에 부정적임
추측하지 말 것
PEP 20의 철학처럼, 모호할 땐 절대 추측하지 말 것
추측의 위험:
- 틀리면 버그
- 맞아도 잘못된 전제를 믿게 되어 나중에 문제 유발
확신이 없으면:
- 질문하고
- 문서 읽고
- 디버깅 도구를 쓰고
- 근거를 찾아야 함
단순하게 유지할 것
똑똑한 사람은 똑똑한 코드를, 훌륭한 사람은 단순한 코드를 씀
단순한 코드가 유지보수에 훨씬 유리함
복잡함이 필요한 상황과 아닌 상황을 구별할 줄 알아야 진짜 실력임
마무리 생각
이 글은 체크리스트가 아니며, 훌륭한 엔지니어링은 경쟁이 아님
단, 어려운 작업을 건너뛸 수 있다고 스스로를 속이지 말 것
훌륭한 개발자가 되는 길에 지름길은 없음
개발 관련2
- 작은 프로젝트라도 각 프로젝트는 자신의 도구 상자에 새로운 기술과 도구를 추가할 수 있는 기회
- 한 프로젝트에서 배운 기술을 다른 프로젝트에서 배운 도구와 결합하여 문제를 해결할 수 있을 때 더 큰 가치를 창출할 수 있음. 모든 것이 합산됨
- 처음엔 언어/라이브러리를 배우지만, 경력이 발전하면서 관심범위가 넓어져야 함
- 기술 측면뿐만 아니라 접근 방식, 방법론 및 패러다임 측면에서도 마찬가지
- 엔지니어로서 발전하는 데 있어 진정한 가치는 단지 고립된 기술을 쌓는 데 있는 것이 아니라, 이를 각 부분의 합보다 더 큰 능력의 복잡한 그물로 엮는 것
- 도구 상자
- 엔지니어링 기술을 도구 상자로 상상해 보면, 새 알고리듬/언어/프레임워크 등 새로운 것을 배울 때마다 기본적으로 이 상자에 도구가 하나씩 추가되는 것
- 하지만 도구가 있다는 것과 도구를 효과적으로 사용하는 시기와 방법을 아는 것은 완전히 다른 문제
- 바로 여기에 경험의 가치가 있음
- 각 프로젝트는 규모에 관계없이 특정 도구를 사용해야 하는 상황을 이해하는 데 도움이 되는 고유한 과제를 제공함
- 하지만 도구 상자는 고정된 개체가 아니라 사용자와 함께 진화함
- 시간이 지남에 따라 더 많은 도구를 추가할 뿐만 아니라 점점 더 복잡한 문제를 해결하기 위해 새로운 방식으로 도구를 결합하기 시작할 것
- 한 프로젝트에서 RESTful API를 사용한 경험이 다른 프로젝트에서 타사 서비스를 능숙하게 통합하는 데 도움이 될 수 있음
- 멀티스레딩에 대한 이해는 데이터가 많은 애플리케이션의 성능을 극적으로 최적화할 수 있음
- 핵심은 각 프로젝트마다 별도의 도구 상자가 필요하지 않다는 것
- 하나의 도구 상자로 각 프로젝트의 고유한 요구 사항과 제약 조건의 이점을 활용할 수 있음
- 기술과 도구의 페어링
- 훌륭한 엔지니어와 그렇지 않은 엔지니어를 구분하는 것은 한 프로젝트에서 배운 기술을 다른 프로젝트에서 습득한 도구와 결합하는 능력
- 이러한 교차 수분(Pollination, 꽃받침에 꽃가루를 공급하는 것)은 보다 효율적인 문제 해결을 가능하게 하고 종종 더 훌륭한 솔루션으로 이어짐
- 도구 상자의 품질은 "도구의 수"가 아니라 "도구가 해결할 수 있는 문제의 풍부함"에 따라 결정됨
- 실제 사례
- 재고 수를 정확하게 유지하기 위해 데이터베이스 트랜잭션에 대한 깊은 이해를 바탕으로 이커머스 웹사이트에서 작업했다고 가정
- 별도의 프로젝트에서 실시간 채팅 애플리케이션을 위한 웹소켓 프로그래밍에 대해 깊이 파고들었음
- 이제 재고 관리를 위한 실시간 대시보드를 개발하는 임무를 맡게 됨
- 이처럼 서로 다른 프로젝트에서 배운 기술을 통합하여 강력한 솔루션을 만들 수 있음
- 데이터베이스 트랜잭션에 대한 깊은 이해를 활용하여 재고 데이터의 안정성과 일관성을 보장하는 동시에 WebSockets를 사용하여 대시보드에 실시간 업데이트를 푸시할 수 있음
- 이러한 기술을 결합하면 문제를 해결할 수 있을 뿐만 아니라 효율적이고 우아한 방식으로 문제를 해결할 수 있다는 뚜렷한 이점이 있음
- 안전지대를 넘어서 뻗어나가기 : 자신의 안전지대를 넘어서는 스트레칭이 중요한 점
- 익숙하고 덜 부담스러운 기존 스킬 세트와 일치하는 프로젝트에 끌리기 쉬움
- 하지만 다양한 경험을 쌓을수록 도구의 폭이 넓어지고, 이러한 결실을 맺을 수 있는 능력이 향상됨
- 새로운 것을 배우거나 이전에 해보지 않은 방식으로 생각하도록 만드는 프로젝트를 적극적으로 찾아볼 것
- 겉으로 보기에는 전혀 관련이 없어 보이는 프로젝트에서도 많은 이점이 있다는 것을 알게 될 것
- 민첩성과 적응력 유지
- 기술은 항상 발전하고 있으며, 오늘 익힌 도구가 내일은 그다지 유용하지 않을 수도 있음
- 하지만 그렇다고 해서 도구가 쓸모없어지는 것은 아님. 오히려 변화에 적응하고 혁신하는 능력을 키울 수 있음
- 예를 들어, 클라우드 네이티브 아키텍처가 등장했다고 해서 기존의 관계형 데이터베이스에 대한 지식이 무의미해지지는 않았음
- SQL과 데이터베이스 설계의 기본을 이해하면 최신 데이터 스토리지 솔루션으로 작업하는 능력을 크게 향상시킬 수 있음
- 가치 있는 경험을 쌓기 위한 실용적인 팁
- 도구를 마스터하는 것은 언제 어떻게 사용해야 하는지 알아가는 여정에 대한 하나의 이정표
- 경험을 쌓기 위한 다양한 옵션이 있음
- 다양한 프로젝트를 큐레이션 하기: 다양한 규모, 다양한 기술, 다양한 문제 영역의 다양한 프로젝트에서 작업해 볼 것. 각 프로젝트마다 도구 상자에 고유한 무언가를 추가할 수 있음
- 반영하고 문서화하기: 프로젝트를 완료한 후에는 배운 내용을 되돌아보는 시간을 가질 것. 더 좋은 방법은 문서화하는 것. '배운 교훈'이 담긴 비공개 저장소나 공개 블로그 게시물을 통해 이해를 공고히 하고 지식을 공유할 수 있음
- 커뮤니티에 참여하기: 오픈소스 기여 또는 개발자를 위한 맞춤형 소셜 플랫폼을 통해 커뮤니티에 참여하면 다른 방법으로는 접할 수 없는 문제를 접할 수 있음
- 멘토와 멘토링 받기: 배운 것을 통합하는 가장 효과적인 방법 중 하나는 다른 사람에게 가르치는 것. 마찬가지로, 자신이 잘 모르는 분야를 전문으로 하는 엔지니어에게 조언을 구하거나 배우는 것을 주저하지 말 것
- 배움을 멈추지 말기: 온라인 강좌, 웨비나, 주말에 새로운 언어를 익히는 등 지속적인 학습은 끊임없이 진화하는 커리어를 위한 윤활유
- 결론
- 기술 교차 수분(Pollination)은 단순한 우연이 아니라 엔지니어링의 우아함
- 최고의 솔루션은 종종 예상치 못한 기술의 조합에서 나옴
- 따라서 다음에 새로운 문제와 씨름하게 될 때, 경험의 도구 상자를 자세히 살펴볼 것
- 새로운 도구를 마스터하는 것이 아니라 수년간 쌓아온 도구를 현명하게 사용하는 데서 해결책을 찾을 수 있을 것
- 문제 해결에 대한 이러한 다층적이고 미묘한 접근 방식이야말로 진정으로 커리어를 발전시키고 엔지니어로서 여러분을 차별화하는 요소임
- "엘리트 코더가 다른 코더보다 뛰어난 능력을 발휘하는 방법"
- 코더가 아닌 엔지니어가 될 것 (Be an engineer, not a coder)
- 엔지니어링은 문제를 해결하는 것
- 최고의 엔지니어는 코드를 목적 달성을 위한 수단으로 생각함
- 코드를 작성하는 즐거움은 있지만 목적이 없는 코드를 작성하는 것은 의미가 없음. 대신 코드는 사용자를 위한 솔루션을 설계하는 데 사용됨
- 코딩은 창의성을 추구함! 창의력은 제약 조건 하에서 많이 발생함. 해결해야 할 명확한 문제라는 '제약'을 추가하면 엔지니어는 자신이 적합하다고 생각하는 방식으로 솔루션을 탐색하고 만들 수 있는 자유를 누릴 수 있음
- 최고의 엔지니어들은 제품 중심적이며, 무엇보다도 사람을 위한 문제 해결을 최우선으로 생각하며, 이는 다음 단계로 이어짐
- 컴퓨터가 아닌 인간을 위한 코드 (Code for the human, not the computer)
- 코드는 컴퓨터뿐만 아니라 인간을 위한 것
- 코드는 그 코드를 읽고, 유지 관리하고, 당신의 코드 위에 빌드하는 같은 팀 엔지니어를 위한 것
- 코드는 휴대전화를 사용하는 어린아이, API를 호출하는 개발자, 본인 등 사용자를 위한 것
- 최고의 엔지니어들은 항상 모든 사용자를 위해 코드의 가치를 평가했음
- 만약 그들이 고객 중 한 명이라도 만족시키지 못하면 그 코드는 프로덕션에 적용되지 못했음
- 코드 자체에서 벗어나기 (Detach from the code itself)
- 뛰어난 엔지니어는 코드 자체에 집착하지 않음
- 그들은 최종 결과물이 전반적으로 더 좋아질 수 있다면 90% 정도 완성된 코드라도 삭제하고 다시 시작하는 것을 두려워하지 않음
- 코드는 개인적인 것이 아니기 때문에 피드백을 적극적으로 받아들임
- 코드는 완벽하지 않음. 아무도 완벽한 코드에 관심을 두지 않음. 변화를 가져오는 코드에 관심이 있을 뿐
- 코드에 집착하지 않도록 스스로를 가르치는 가장 좋은 방법은 "20년 후에는 당신 코드의 대부분이 기술 부채가 되거나 더 이상 사용되지 않거나 다시 작성될 가능성이 높다는 것을 깨닫는 것"
- 일관된 표준 사용 (Use consistent standards)
- 코드를 작성할 때 일관된 표준과 코딩 스타일을 고수할 것
- 일관성(Consistency)을 유지하면 미래의 당신과 팀원 모두가 코드를 더 쉽게 읽고 이해할 수 있게 해줌
- 일관된 스타일 가이드를 사용하면 팀과 코드베이스 모두 더 쉽게 확장할 수 있음
- 이게 Meta/Google 같은 회사가 시간이 지나도 코드베이스를 읽을 수 없거나 유지 관리할 수 없게 되는 일 없이 많은 코드를 신속하게 배포하는 방법
- 모든 뛰어난 성과를 내는 기업은 스타일 가이드를 내재화하고 그 이점을 알고 최대한 이를 따랐음
- 구글은 일부 스타일 가이드를 오픈소스로 공개했음
- 메타는 그들의 일부 오픈소스에 C++ 스타일 가이드가 있음
- 팁: 당신의 팀을 위해서 Linter를 포맷팅하는 것은 확실히 시간을 들여 설정할 가치가 있음
- 간단한 코드를 작성 (Write simple code)
- 내가 아는 모든 엘리트 엔지니어는 생성하기엔 복잡했을 수도 있지만, 결국엔 읽고 이해하기 쉬운 코드를 생성했음
- 이에 대해 내가 한 가장 좋은 말은 그들의 코드가 "미학적으로 만족스럽다는 것"
- 그들의 코드는 깔끔하고, 체계적이며, 논리적(clean, organized, and logical)
- 코드에서 내린 각 결정은 의미가 있었고, 그렇지 않은 경우엔 코드내에 잘 문서화 되어 있었음
- 깔끔한 코드를 작성하는 좋은 방법은 SOLID 원칙과 같은 원칙을 따르는 것. 처음에는 OOP(객체 지향 프로그래밍)를 염두에 두고 설계되었지만 일반 프로그래밍에도 확장할 수 있음
- Single Responsibility: 한 클래스는 하나의 책임만 가져야 함
- Open-Closed: 소프트웨어 객체(클래스, 모듈 등)는 확장에는 개방적이지만 수정에는 폐쇄적이어야 예측 가능하고 유지 관리 가능한 코드를 만들 수 있음
- Liskov Substitution: 하위 유형은 프로그램의 정확성에 영향을 주지 않으면서 기본 유형으로 대체할 수 있어야 함
- Interface Segregation: 코드가 모든 것을 사용하지 않는 거대한 인터페이스에 종속되어서는 안 됨. 대신 패키지는 더 작은 특정 인터페이스를 포함하고 임포트할 수 있도록 허용해야 함
- Dependency Inversion: 상위 레벨 모듈이 하위 레벨 모듈에 종속되어서는 안 되며, 둘 다 추상화에 종속되어 보다 유연하고 분리된 시스템 설계를 촉진해야 함
- 그 예로 이름 짓기(Naming)를 들 수 있음: 좋은 이름에는 마법의 값이 없고, 구분이 명확하며, 설명적인 함수 이름과 이해하기 쉬운 변수를 표현함
- 의외성을 허용하지 않음 (Don’t allow surprises)
- 코드는 예상치 못한 결과를 만들어서는 안 됨. 이는 코드 원칙을 따르고 적절한 테스트를 작성함으로써 가능
- 좋은 코드는 예측 가능함
- 테스트는 코드의 명확성과 예측 가능성을 강화하고, 자신감을 줌. 우수한 자동화된 테스트를 통해 팀은 보이지 않는 부분을 깨뜨릴 염려 없이 코드를 변경할 수 있음
- 몇가지 테스트 유형
- 개별 컴포넌트 및 격리된 함수에 대한 단위 테스트
- 여러 컴포넌트 간의 상호 작용을 위한 통합 테스트
- 사용자 관점에서 전체 시스템의 기능을 평가하는 엔드투엔드 테스트
- 테스트는 간단해야 함. 실패한 테스트를 읽었을 때 무엇이 잘못되었는지 쉽게 파악할 수 있어야 됨
- 테스트하지 말아야 할 항목을 아는 것도 중요
- 예를 들어, 엔드투엔드 테스트의 수고가 프로그램의 실제 이점보다 크다면 테스트는 신중한 문서화, 모니터링 및 적절한 사람(예: 코드 소유자)에게 알림을 보내는 것으로 대체
- 또한 테스트는 프론트엔드 코드에서 특정 CSS 선택기를 테스트하는 것과 데이터 속성 또는 스크린샷 테스트만을 사용하는 것과 같이 코드 내의 구현 세부 사항을 테스트해서는 안 됨
- 자주 소통하기 (Communicate often)
- 훌륭한 시스템은 혼자서 만들어지지 않음. 훌륭한 엔지니어들은 설계 검토를 거치고, 피드백을 요청하고, 코드에 대한 초기 설계를 계속 반복했음
- 누구나 자신의 지식에는 다른 사람이 채워줄 수 있는 빈틈이 있음. 새로운 관점은 종종 코드를 더 명확하게 만들거나 이전에는 생각하지 못했던 새로운 접근 방식을 제공하는 데 도움이 될 수 있음
- 최고의 엔지니어들은 더 나은 최종 결과물을 얻기 위해 시간을 들여 함께 작업하는 것을 두려워하지 않고 소통과 협업을 중시
- 문서에 대한 빠른 검토를 위해 팀원에게 핑을 보내거나 중요한 풀 리퀘스트에 코드 검토자를 추가하는 것처럼 간단하게 할 수 있음
- 빠르게... 그리고 느리게 코딩하기 (Code fast… and slow)
- 내가 아는 최고의 엔지니어들은 프로젝트를 빠르게 완료하지만 코딩은 느리게 함
- 이상하게 들리죠?
- 위의 모든 원칙과 습관은 코딩의 첫 번째 단계에 더 많은 시간을 추가함. 하지만 이러한 원칙과 습관을 통해 엔지니어는 프로젝트의 진행 상황을 한 단계씩 발전시킬 수 있음
- 표준을 사용하고, 제대로 테스트하고, 원칙을 사용하고, 자주 소통하는 데 시간을 할애함으로써 장기적으로 더 많은 시간을 절약할 수 있음
- 인턴과 주니어 엔지니어 시절에 제가 직접 경험했고, 다른 많은 엔지니어들도 마찬가지겠지만, 3보 전진을 서두르다 장애물에 부딪혀 5보 후퇴하게 될 수 있음
- 맹목적으로 규칙을 따르지 말 것 (Don’t follow rules blindly)
- 위의 '규칙'과 '원칙'은 단순한 가이드라인일 뿐. 모든 것이 가이드라인에 깔끔하게 잘 들어맞는 것은 아님
- 때로는 작성 중인 코드가 원 안에 들어가지 않는 정사각형일 수도 있지만 괜찮음
- 이 경우 코드가 특정 방식으로 작성된 이유를 문서화할 것
- 그렇지 않으면 미래의 여러분과 같은 누군가가 나중에 코드를 보고 "와, 그때는 내가 멍청했었지. 왜 이게 우리 표준을 따르지 않는 거지?"라고 생각할 수 있음
- 그러면 그들은 이전과 같은 결론에 도달하기 위해 20시간 동안 표준에 맞게 다시 코딩하는 데 시간을 소비할 것
- 소프트웨어 개발의 현실은 모든 코드가 깔끔하거나 규칙을 완벽하게 따를 수 없다는 것
- 하지만 일관성 있고, 깔끔하고, 이해하기 쉽고, 테스트할 수 있고, 가치 있는 코드는 존재할 수 있음
- 최고의 엔지니어에게서 발견한 또 다른 패턴들
- 적어도 한 가지 분야에 대한 깊은 도메인 지식을 가짐. 제가 기록했던 모든 엔지니어는 프론트엔드 인프라, 분산 시스템, 깔끔한 UI 등 특정 분야에 집중하여 전문가가 되었기 때문에 현재 해당 분야에서 최고의 자리에 올랐음
- 자신을 자주 그리고 적절하게 마케팅함. 이 엔지니어들은 눈에 잘 띄지 않는 곳에 숨어 있지 않았음. 팀원들과 함께 일하는 모든 사람들이 자신의 가치와 전문성을 알고 있었고, 이는 적절한 마케팅과 영향력 있는 프로젝트를 수행한 결과
최고의 PR
- 지금은 엔지니어링 매니저가 되었지만 내가 소프트웨어 엔지니어로 일하던 시절, 복잡한 기능을 며칠간 작업해 PR를 올렸음
- 피드백은 단호하고 냉정했음 “오버 엔지니어링임. 복잡함. 리팩토링하시오”는 간단한 문장이 전부였음
- 칭찬 한마디 없이 비판만 받은 경험에 분노했으나, 그 매니저와의 일화는 단지 시작에 불과했음
- 감정을 배려하지 않는 리더 스타일
- 이 매니저는 기존에 알고 있던 리더들과 달랐음
- 손을 잡아주지도, 부드러운 말도 하지 않음
- 다음과 같은 특징이 있었음
- 설익은 아이디어는 바로 거절함
- 복잡함을 위한 복잡함을 싫어함
- 깔끔하고 유지 보수 가능한 효율적인 코드만 중요시함
- 회고에서도 돌려 말하지 않고 문제를 직접 지적함
- 처음에는 냉혹한 성격이라 생각했지만, 그 이면에는 다른 철학이 있었음
- 자존심을 흔든 피드백의 전환점
스프린트 리뷰에서 자신 있는 기능을 시연했지만 매니저는 중간에 끊고 물음
“이건 취약해. 부하 상황에선 어떻게 돼? 롤백 계획은?”
대답을 제대로 하지 못하자 매니저는 말함:
“지금 넌 코더처럼 생각하고 있어. 엔지니어처럼 생각해야 해”
- 처음엔 화났지만, 결국 스스로의 코드 스타일이 회복력보다는 영리함에 치중했다는 걸 자각하게 됨
- 진짜 교훈: 그 매니저는 나를 개인적으로 공격한 게 아니었음
- 사고방식에 큰 변화가 생김
- “똑똑한” 코드 대신 읽기 쉬운 코드를 작성함
- 실패 상황을 대비한 설계에 집중함
- 본인을 위한 코드가 아니라 후속 개발자를 위한 코드를 작성함
- 이후 그 매니저의 코드 리뷰는 거침없이 통과됨
- 매니저가 달라진 게 아니라, 나 자신이 성장했기 때문임
- 내 리더십 스타일에 남긴 영향
- 엔지니어링 매니저가 된 후 그 경험을 많이 떠올렸음
- 사람들이 싫어하는 리더는 되고 싶지 않았지만, 부드럽기만 한 리더도 되고 싶지 않았음
- 다음과 같은 방식으로 스타일을 정립함
- 배경 설명이 있는 직설적인 피드백을 줌
- 시스템적 사고를 강조함
- 높은 기준은 유지하되 인간적인 피드백을 제공함
- 엔지니어들은 도전받는 걸 원하지만 무시당하는 느낌은 싫어함
- 단호한 매니저가 필요할 때
- 리더십에는 자존심, 마감, 압박이 얽혀 있어 혼란스러움
- 단호한 매니저는 다음을 통해 이 혼란을 걷어냄
- 기능이 아닌 확장성을 생각하게 함
- 영리한 코드보다 유지 가능한 코드를 쓰게 함
- 실패와 예외 상황을 미리 대비하게 함
- 감정보다 코드의 생존 가능성을 더 중요하게 여김
- 단호한 매니저 아래에서 생존하고 성장하는 방법
- 숨 막히는 리더 아래에 있다면 다음과 같이 대처할 수 있음
- 개인적인 공격으로 받아들이지 말 것: 피드백은 코드에 대한 것
- 피드백 이후 “왜?”를 물어볼 것: 대부분 단호한 리더는 호기심을 존중함
- 실패 지점을 스스로 먼저 생각해 볼 것: 매니저처럼 사고하기 시작해야 함
- 리더라면 다음을 실천해야 함
- 높은 기준을 제시하되, 그 기준이 중요한 이유를 설명할 것
- 모호한 피드백 대신 구체적으로 말할 것
- 성공보다 성장을 축하할 것: 개발자가 매니저보다 먼저 문제를 포착했다면 칭찬할 것
- 거절된 Pull Request가 준 최고의 선물
- 처음엔 자존심이 상했지만, 지금 돌아보면 그 거절된 PR은 인생 최고의 기회였음
- 코딩을 개인 프로젝트가 아닌 시스템 구축으로 보게 되는 계기였음
- 단호한 매니저는 기분을 좋게 해주진 않지만, 개발자로서 성장하게 함
- 진정한 성장은 PR이 통과될 때가 아니라, 거절될 때 시작됨
弊社に5年間在籍していたロシアの天才ハッカーが先日退職しました。
ハッキング世界大会優勝の経歴を持ち、テレビ出演の経験もある彼ですが、正直こんなに長く活躍してくれるとは思っていませんでした。彼のようなタレントが入社した場合、得てして日本の大企業にありがちな官僚主義に辟易してすぐに退職するか、もしくはマスコットキャラとして落ち着くかのどちらかのケースがほとんどなのですが、彼は最後まで現場の第一線で活躍してくれました。
そんな彼が最後に残していった退職メールがなかなか印象的だったので、その拙訳をここに掲載します(転載について本人同意済み。弊社特有の部分は一部省いています。)
ああ、なんという長い旅だったろう。この会社で5年間もセキュリティを担当していたよ(諸々の失敗は許してくれ)
俺は他の退職者のように面白いことは書けないが、私のこの退職メールを読んでくれている人、特に新人エンジニアのために、仕事を改善するための、いくつかの俺の考えを伝えよう。 これを俺の”新人エンジニアサバイバルガイド”と名付ける。中堅エンジニアにも、いくつかのアイデアを汲み取って、新人教育に活用してほしい。 このガイドには、この会社でエンジニアとしてスタートダッシュを決めて、高給取りのエンジニアになるための、俺のちっぽけなアイデアが詰め込んである。
Application Engineer
1.技術的なスキルをマスターしよう。もっともよい教材のリストはこれだ。 https://www.google.com/about/careers/students/guide-to-technical-development.html コースに学生向けと書かれていても気にするな。俺は学生じゃないけどここにあるほとんどのコースを受講した。
2.コードのクオリティに腹をたてるな。同僚の2倍のスピードでリリースをするよう心がけろ。 自分の担当箇所以外でも、明らかに壊れてる箇所を見つけたら、pull requestを送れ。 そうすればお前もイカした奴の仲間入りだ。 品質を確保するためのツールをマスターしろ(IDEs, Jenkins and testing suites, git, ssh)
3.Stack Overflowを使うな。内容をよく理解しないであそこからコピペをするものには、大いなる災いが訪れるであろう。 特にひどいのが暗号化のサンプルだ。99%のサンプルは間違っている!それを使うのではなく、社内のセキュリティチームに相談をしてアドバイスを受けろ。それが賢い人間のやり方ってもんだ。
4.英語を学ぼう。もし海外から来て日本で働いてるなら、日本語を学ぼう。もし両方マスターしてるなら、Javaの勉強でもしたらいいんじゃないかな ;-)
5.Chef, Ansible, Puppetを学ぼう。運用エンジニアの時間を浪費するのはやめよう。
6.常に4つの環境を用意しておこう。3つじゃなくて4つだ。すなわち、開発環境、QA環境(次期バージョンのテスト用)、統合テスト環境(現行バージョンから次期バージョンへのデプロイテスト用)、そして本番環境だ。
Infrastructure Engineer
1.SLAがいくつに設定されているのか、またそれがどのように計算されるかを理解しよう。単一のデータセンターで運用する限り、目標とするSLAには決して到達しないだろう。
2.Failoverにダウンタイムが伴う構成は、high availabilityなシステムとは呼べない。
3.常にTLSを使おう。社内サービスであってもだ。
4.アプリケーションはnginxを経由して公開しよう。
5.システムのハードニングをしよう。そのためのchefのレシピがここにある。 http://dev-sec.io/
6.開発者と一緒に仕事をしよう。彼らが何をしたがってるのか理解するよう努めよう。よりよいソリューションの布教活動をしよう。例えば、キューワーカーモデル、非同期IO、中央レポジトリとフォワーダーによる非同期ロギング、自動化デプロイ、オートスケーリングなどだ。
Database Administrator
1.技術的なスキルをマスターしよう。たとえ、濃縮ウラン認定DBA資格を取ったとしても、学習をやめてはならない。学ぶべきことはまだまだあるのだから。
2.CAP理論を学習し、各データベースソリューションにどのような違いがあるのかを理解しよう
3.それぞれのDBに管理者ごとにユーザを作成しよう。LDAPと連携していればよりベターだ。ログをできるだけ残せ。最低でも監査ログとスロークエリログは忘れるな。そしてそのログをSplunkやKibanaで見れるようにするんだ。
4.証明書ベースの認証をアプリケーションに推奨しよう。そして接続にはTLSを使おう。
5.DBのハードニングをしよう。特にOracleの場合は。 — https://benchmarks.cisecurity.org
6.テスト環境をできるだけ本番環境に近づけよう。もし本番でExadataを使っているならば、ステージング環境、統合テスト環境も同様にそうすべきだ。そこでコストをケチってはいけない。
Security Engineer
この中には新人向けとしては、いささか高度すぎるものも含まれている。
1.不満を述べるのをやめて、修正のためのPull Requestを送ろう。さもなくばマネージャーにでもなったほうがましだろう。でないと、問題を解決することなく、何度も何度も苦しむことになる。
2.セキュリティソリューションを構築せよ。"encryption as a service" や "AppScan as a service" といった人間を介さないサービスを提供できたら素晴らしい。 HashiCorp Vault as a serviceや、TLS証明書管理ツール、 GRCツールなどやるべきことはたくさんある。
3.暗号理論に秀でよ。これは学べば学ぶほど退屈な代物だ。ただ、HMACしてから暗号化と、暗号化してからHMACの違いがわからないようでは、到底エースセキュリティエンジニアとはいえない。
Technical Program Manager
新人の君がこれにあたることはないだろう。この章はむしろエンジニアからマネジメントへのキャリアチェンジを試みている人のためにある。 スポンサーをゲットしろ。スポンサーとは君の案件について、強いモチベーションを持つ役員のことだ。もしそのようなスポンサーがいなければ、その案件は中止し他のもっと重要なものにフォーカスしよう。役員を説得しようとするな。彼らはきっと君の相手に疲れてしまうから。
2.君の案件が最重要案件だと思い込むな。会社には君の案件より重要な無数の最重要案件がある。その時は辛くても、その新しい案件にフォーカスしなおし、時が来るのを待とう。
3.社内の様々な部署の人間とネットワークを構築しよう。
4.経理を学習しよう。
5.プロダクトマネジメントを学習しよう。
6.スピードよりクオリティを優先しよう。急いでもそんなによいことはないし、急がせることは君の責任ではない。よりよいものを提供するために十分な時間を確保しよう。
えーと、これで全部かな。 もしこのアドバイスが横柄に感じられたとしたら謝ろう。 参考にするもよし、無視するもよし、賛成するもよし、しないもよしだ。 これは、すべて俺の経験に基づいた個人的な考えだ。
The Mistakes I Made As a Beginner Programmer
初心者プログラマが犯しがちな間違いと、それらを特定し、避けるための習慣を学ぶ方法。
まず最初に言っておくことがあります。 この記事は、誤りを犯すことを悪いと糾弾するために作成されたものではありません。 むしろ貴方が誤りに自ら気付き、あるいはその兆候を見いだし、それらを避けられるようにするために書かれたものです。
私は過去これらの誤りを犯し、それぞれから学びを得てきました。 今ではこれらを避けるようなコーディングを習慣付けるようにしています。 貴方もそうしましょう。
紹介は順不同です。 設計せずに実装する
高品質なコンテンツは、一般的には容易に作成できるものではありません。 それには慎重な思考と研究が必要です。
高品質なプログラムももちろん例外ではありません。 良いプログラムは、適切なフローに従って書かれるものです。 思考、研究、計画、実装、検証、修正。 残念ながら、これを一言で表す適当な語句がありません。 それぞれのプロセスにどれだけのウェイトを置くか、適切な重み付けを検討する習慣を作る必要があります。
私が初心者だった頃に犯した最大の間違いは、思考や研究をせずいきなりコードを書いたことでした。 これは小さなスダンドアローンアプリには有効な手段かもしれませんが、大規模なアプリには多大な悪影響をもたらします。
考える前に話すことで後悔することがあるかもしれない、と考えるの同様に、考える前にコーディングすることで後悔することがあるかもしれない、と考える必要があります。 コーディングも考えを伝える手段のひとつです。
> 怒ってるときは、口を開く前に10数えよ。激おこであれば100だ。 > > Thomas Jefferson.
私が言い換えるとこうなります。
> コードを書いてるときは、リファクタする前に10数えよ。テストを書いてないなら100だ。 > > Samer Buna
プログラミングとは、主に既存のコードを読むことです。 そして必要な機能と現在の実装の乖離を調査し、どのようにすれば最小限のテストでその差異を埋められるかを設計することです。 実際のコードの記述は、おそらくプロセス全体の10%程度しかありません。
プログラミングとはコードを書くことだ、とは思わないでください。 プログラミングは、成長を必要とするロジカルな創造性です。2) 実装する前に設計しすぎる
コードを書く前に計画を立てるのは良いことです。はい。 しかし、あまりに多くをしすぎると却って悪くなります。 ただの水でも量が過ぎれば毒になるように。
完璧な設計を作り上げようとしてはいけません。 プログラミングの世界にそれは存在しません。 実装を始めるのに必要で十分なレベルの設計を探してください。 実際、設計はよく変わるものです。 適切な設計はコードの構造をクリアにするために必要なものです。 しかし、多すぎる設計は、単に時間の無駄です。
設計は少しずつ行った方がよい、ということです。 全ての機能を一度に設計することは、単純に禁止すべきです。 それはウォーターフォールと呼ばれ、システムを順番にひとつひとつ終わらせていく設計です。 その手法ではいったいどれだけの設計が必要になるでしょう。 ほとんどのソフトウェアプロジェクトでは、ウォーターフォール設計はうまくいきません。 複雑なものになるほどアジャイルでしか対応できなくなります。
プログラム開発は、変化に敏感である必要があります。 ウォーターフォール設計時点では無かった機能を実装することがあるでしょう。 ウォーターフォール設計時点では考慮していなかった理由のために機能を削除することがあるでしょう。 バグは修正し、変化に適応する必要があります。 すなわちアジャイルである必要があります。
ただし、次に実装する予定のいくつかの機能については常に設計してください。 少なすぎる設計も、多すぎる設計も、あなたのコードの品質を損ないます。 そして低品質なコードは、あなた自体の品質に繋がります。3) 品質管理の過小評価
コードを書くときに優先することをひとつだけ挙げるとするならば、それは読みやすさです。 読みにくいコードはガラクタです。 コードはまたリサイクル可能でなければなりません。
コードの品質管理の重要性を過小評価しないでください。 コーディングは実装を伝える手段だと考えてください。 コーダーの主な仕事は、作業中のソリューションの実装を伝えることです。
プログラミングに関する、私のお気に入りのフレーズのひとつを紹介します。
コードを書くときは、メンテナはあなたの住所を知っているサイコパスである、と肝に銘じてコーディングしなさい。 - John Woods
John、素敵なアドバイスをありがとう。
小さなことですら問題です。 たとえば、インデントと大文字小文字が正しくないだけで、あなたにはコーディングの資格がないとみなされます。
tHIS is WAY MORE important than you think
他にすぐわかる不味い点は、長い行です。 80文字を超えるような行はより読みづらくなります。 ifブロックを見やすくするため、複数の条件式を1行にまとめて書きたくなるかもしれません。 そのようなことをしてはいけません。 80文字の制限を超えてはいけません。
このような単純な問題の多くは、Linterや整形ツールで簡単に修正可能です。 JavaScriptであればESLintとPrettierというふたつの優れたツールが存在します。 常にそれらを使うようにしてください。
コード品質については、いくつもの地雷が存在します。 関数の行数が多すぎる
長いコードは、常に個別にテスト可能な小さな単位に分割する必要があります。 個人的には10行以上の関数は長すぎると思っていますが、これはあくまで目安です。 二重否定を使う
使ってはいけません。 二重否定を使うのは非常に悪くなくないです。 短すぎる、汎用的な、データ型を使った命名
変数名には説明的で、曖昧ではない名前を付けます。
> コンピュータサイエンスで難しいことはたった二つだけだ。キャッシュ削除と命名だ。 - Phil Karlton
マジックナンバーのハードコーディング
文字列や数値で固定のプリミティブ値を設定したい場合は、その値を定数に入れ、適切な名前を付けます。
const answerToLifeTheUniverseAndEverything = 42;
問題を回避する
ショートカットや回避策を弄して問題から逃げてはいけません。 現実に直面しましょう。 長いコードが良いと考える
大抵の場合は短いコードの方がよいです。 コードが読みやすくなるのであれば冗長なコードを選びましょう。 コードを短くするために、技巧を凝らしたワンライナーや、三項演算子のネストなどを書いたりしないでください。 とはいえ、必要のないときにまで意図的にコードを長くする必要もありません。 不要なコードを削除することは、プログラムに対して行える最もよい改善点です。
> プログラムの進捗を行数で計るのは、飛行機建造の進捗を重さで量るようなものだ。 - Bill Gates
条件付きロジックの多用
条件付きロジックが必要だと思われているケースの大半では、条件付きロジックが不要です。 代替案も確認し、最も読みやすいと思われる選択肢を選びましょう。 明らかに速度が異ならないかぎり、パフォーマンスを最適化する必要はありません。 またヨーダ記法や条件式中での値代入なども避けましょう。4) 最初の解決策に飛びつく
私がプログラムを始めたころ、提示された問題に対して解決策を見付けたら即座にそれに飛びついていたことを覚えています。 最初の解決策の複雑さの程度について考える前に実装を始め、そして必然的に失敗に結びついていました。
最初の解決策は魅力的かもしれませんが、よくよく考えてみると大抵はより優れた解決策を見付けられます。 問題に対して複数の解決策を考えつくことができないようであれば、それはおそらく問題を完全には理解できていないということです。
プログラマーとしてのあなたの仕事は、問題の解決策を見つけることではありません。 最もシンプルな問題の解決策を見つけることです。 シンプルとは、解決策が正しく適切に機能し、その上で読みやすく、理解しやすく、保守しやすいということです。
> ソフトウェアの設計にはふたつの方法がある。ひとつめは、可能なかぎりシンプルにして明らかに欠陥がないようにすること。もうひとつは、可能なかぎり複雑にして明らかな欠陥がないようにすることだ。 - C.A.R. Hoare
諦めない
私が最も頻繁に犯した間違いが、『最初の解決策が最も簡単な解決策ではないことに気付いた後も、最初の解決策に固執する』ことでした。 諦めない精神が悪い形で出ています。 諦めない精神は、たいていの活動においてはよい心がけですが、プログラミングに適用すべきではありません。 ことプログラミングにおいては、正しい心は早々に死滅し、頻繁に失敗します。
解決策に疑問を覚えたなら、一度それを投げ捨てて問題を再考してみましょう。 その解決策に、それまでどれだけの投資をしていたとしてもです。 gitのようなソース管理ツールは、様々な解決策を使い分けて試してみるのに適しています。
そのコードにどれだけの努力を払ったかは、コードの品質には全く関係ありません。 悪いコードは排除する必要があります。6) ググらない
問題を解決しようとする際に、最初にすべきだったことをしなかったがために多大な時間を浪費したことがたくさんあります。
よほど最先端の技術でも使用していないかぎり、あなたが出会った問題は、大抵の場合誰かが既に同じ問題に遭遇して解決したことのあるものです。 つまり最初にググれということです。
時には、あなたが問題だと思っていたことは別に問題ではないということもGoogleは明らかにしてくれます。 あなたに必要なのは、問題を修正することではなく、むしろそれを受け入れることです。 問題を解決するのに必要なことが全てわかっている必要はありません。 Googleは驚くべき解決策を持ってきてくれるでしょう。
ただし、Googleを使うときは念頭に置いてください。 初心者にありがちな行動のひとつが、出てきたコードを読まずにそのままコピーして使用することです。 たとえ問題を正しく解決するコードだったとしても、理解していないコードは決して使用しないでください。
> クリエイティブな人間として最も危険な考えは、自分がやっていることは自分が知っていることだ、と思い込むことです。 — Bret Victor
カプセル化しない
ポイントは、オブジェクト指向パラダイムを使用するという意味ではないことです。 技術にかかわらずカプセル化の考え方は常に有用です。 カプセル化を行わないシステムは、しばしば保守が困難になります。
アプリケーションには、ある機能を処理する場所は一カ所しかありません。 それは通常、ひとつのオブジェクトの責任です。 そのオブジェクトが公開するのは、外からそのオブジェクトを使うのに必要な最低限の情報だけでなければなりません。 これは機密を保つためではなく、アプリケーションの各部分の依存関係を減らすというコンセプトに基づくものです。 これらの規則に従うことで、どこか離れた場所で何かが動かなくなるのではないかと心配することなく、クラス、オブジェクト、メソッド内部を安全に変更することが可能になります。
クラスは、関連するロジックとステートを集めた概念的集合の単位で作ります。 By class, I mean a blueprint template. This can be an actual Class object or a Function object. モジュール、もしくはパッケージとして識別されることもあります。
ロジッククラスでは、ひとつの独立したタスクにはひとつのメソッドが必要です。 メソッドはひとつのことだけを行い、それを正しく処理しなければなりません。 同じようなクラスは同じメソッドを持っているべきです。
初心者プログラマだった頃、私はどのようにクラスを分けるべきかの概念的集合がよくわからず、何が独立したタスクなのかを切り分けることもできませんでした。 それぞれの関係が特にないような雑多なコードが詰め込まれた"Util"クラスができあがってくれば、それは初心者である兆候です。 一カ所に簡単な変更を加えたところ、別のところに問題が波及し、何カ所も修正を行わなければならなかった場合、それもまた初心者コードの特徴です。
クラスにメソッドを追加する、あるいはメソッドに機能を追加する前に、考える時間を取ってください。 考えを後回しにしたり、後でリファクタリングすればいいやなどと考えたりしないでください。 ここが正しい道への第一歩です。
よい考え方は、コードは高凝集で低結合なものにするということです。 「高凝集で低結合」とは、関連するコードはひとつのクラスにまとめて記述し、異なるクラス間での依存関係を減らす、という意味を表すファンシーな用語です。8) 不要な拡張性を盛り込む
現在の解決策を超えた方法を考えることはしばしば魅力的です。 あなたが書いたあらゆる行で、「もしここで○○だったら」という考えがよぎるかもしれません。 これはエッジケースのテストについて考えるときにはよいことですが、まだ実装されていない対象について対応するのは間違いです。 頭をよぎった「もしここで○○だったら」が、両者のどちらであるかをしっかり分類する必要があります。 今日必要の無いコードは今日書かないでください。 決まっていない事象を織り込まないでください。
> 成長のための成長は癌細胞だ - Edward Abbey
正しいデータ構造を使わない
コードレビューの際、初心者プログラマはアルゴリズムに重点を置きがちです。 適切なアルゴリズムを特定し、必要に応じてそれらを使用するのはよいことですが、それだけでは天才プログラマにはなれないでしょう。
使用している言語に用意されている様々なデータ構造について、その長所と短所を覚えておくと、より良い開発者になれるはずです。
不適切なデータ構造を使うことは、つまり『ここに初心者がいますよ』と触れ回るに等しい行為です。
この記事ではデータ構造の詳細にまでは立ち入りませんが、簡単な例を幾つか挙げておきます。 Using lists (arrays) instead of maps (objects) to manage records
最もよくあるデータ構造選択の誤りは、複数のレコードをmapではなくlistで管理することです。 はい、レコードの管理はmapを使わなければなりません。
以下は各レコードにそのレコードを特定するための一意のキーが存在する場合についての話になります。 スカラー値にlistを使っても問題なく、特に値をpushして使っていた場合にはより良い選択になります。
JavaScriptでは最も一般的なlistはarrayで、最も一般的なmapはobjectです(最近はmapもあります)。
レコードを管理するためにlistを使うのは誤りです。 これが重要である理由は、識別子を使ってレコードを検索する際に、mapはlistより遙かに高速だということです。 実際に目に見える影響が出てくるのはコレクションが巨大になってきたときだけですが、それだけでも固執するには十分な理由です。 Not Using Stacks
繰り返しを必要とするコードを書く場合、単純に再帰を使うのは簡単な選択です。 しかし、再帰コードを最適化するのは非常に難しいです。 特にシングルスレッド環境であればなおさらです。
再帰関数の最適化は、対象によって難易度が著しく異なります。 たとえば2値以上の値を返すコードの最適化は、返り値がひとつだけの関数よりも遙かに難しくなります。
初心者が見落としがちなのが、再帰のかわりに使えるデータ構造があるということです。 それはスタックと呼ばれます。 関数を呼び出すかわりにスタックに積んで、用意が出てきたらpopします。10) コードを悪化させる
このように乱雑な部屋を与えられたと想像してください。
この部屋に新たなアイテムを設置するよう求められました。 部屋は既にじゅうぶん乱雑なので、適当に置いてもかまわないと考えるかもしれません。 その作業は数秒で完了することでしょう。
乱雑なコードでそれをしてはいけません。 決して悪化させてはいけません。 少しでいいから、作業を開始したときよりもコードを綺麗にしましょう。
上の部屋に行うべき正しいことは、新しいアイテムを置くために必要な位置を整頓することです。 たとえば、アイテムが衣服であった場合、まずはクローゼットへの道を片付ける必要があります。 それこそが、あなたが仕事を正しく行うことの一部です。
コードをしばしば悪化させる例を、いくつか挙げておきます。 Duplicating code
コードをコピペして一部の行を変更する行為は重複コードと呼ばれ、コードは純粋に悪化します。 汚れた部屋の例で言うと、高さが調整可能な椅子を導入するのではなく、高さの異なる椅子を導入するようなものです。 できるかぎり抽象的に使うように心がけてください。 Not using configuration files
環境や時間帯によって異なる値を使用したい場合、その値は設定ファイルに書き出しましょう。 コード内の複数箇所でひとつの値を使用したい場合、その値は設定ファイルに書き出しましょう。 コードに新しい値を導入する際は、その値は設定ファイルに書き出すべきかどうかを考えてください。 なお、大抵の場合答えはイエスです。 Using unnecessary conditional statements and temporary variables
全てのif文は少なくとも2回テストする必要がある分岐です。 可読性を下げることなく分岐を避けられるのであれば、そうすべきです。
新たな関数を作るかわりに、関数に分岐ロジックを導入した際によく問題になります。 if文や新たな関数が必要になるたびに、その変更は適切か、もっと異なる次元で対応すべきか、自問してください。
function isOdd(number) {
if (number % 2 === 1) {
return true;
} else {
return false;
}
}
isOddはいくつか問題がありますが、最も大きな問題はどこでしょうか。
if文は明らかに不要で、コードは以下と同じです。
function isOdd(number) {
return number % 2 === 1;
}
意味の無いコメントを書く
できればコメントは書かないようにしたいですが難しいところです。 ほとんどのコメントは、コード内の要素名を適切に置き換えることで排除できます。
// This function sums only odd numbers in an array
const sum = (val) => {
return val.reduce((a, b) => {
if (b % 2 === 1) {
// If the current number is even
a += b; // Add current number to accumulator
}
return a; // The accumulator
}, 0);
};
このコードは、以下のようにコメント無しで書くことができます。
const sumOddValues = (array) => {
return array.reduce((accumulator, currentNumber) => {
if (isOdd(currentNumber)) {
return accumulator + currentNumber;
}
return accumulator;
}, 0);
};
単に関数名や引数名を適切に付けるだけで、大抵のコメントは不要になります。 コメントを書く前に思い出してください。
しかし、どうしてもコメントを書かなければならない状況に陥ることもよくあります。 それは、このコードは何であるか(WHAT)ではなく、このコードは何故そうなのか(WHY)を説明しなければならないときです。
コードにWHATコメントを書くことが求められている場合でも、明らかに明白なことは書かないでください。
// create a variable and initialize it to 0
let sum = 0;
// Loop over array
array.forEach(
// For each number in the array
(number) => {
// Add the current number to the sum variable
sum += number;
},
);
これらはコードにノイズを加えるだけの、全く役に立たないコメントです。 このようなプログラマになってはいけません。 このようなコードを受理してはいけません。 対処が可能ならコメントを削除してください。 部下がこのようなコメントを書いてきたら即座に解雇してください。12) テストを書かない
要点を簡潔に述べましょう。 あなたが自分を、テストを書かずとも思考をそのままコードに落とし込める腕を持っている熟練プログラマである、と考えているのであれば、あなたは初心者です。
テストコードを書いていない場合は、それ以外の方法でプログラムを手動テストすることが多いでしょう。 Webアプリを作っているのであれば、コードを数行書くごとに画面を再描画して確認します。 私もそれは行います。 コードを手動テストするのはおかしなことではありません。 ただし、それと同時にコードを自動テストする方法についても考えておかねばなりません。 手動テストが正常に終わり、コードエディタに戻り、新たなコードを書き、再び手動テストを行う、このように全く同じ動作を行うのであれば同じ動作を自動的に実行するコードを記述しないわけにはいきません。
あなたは人間です。 すなわち、あなたは前回行ったテストの内容を忘れます。 そのような繰り返しはコンピュータにやらせましょう。
可能であれば、コード本体を書き始める前にコードが満たすべき条件を設計・推測するところから始めるとよいでしょう。 テスト駆動開発 ( TDD ) は伊達ではなく、機能やデザインについて考えることにプラスの影響を与えます。 TDDは全ての人に適しているわけではなく、うまく適用できないプロジェクトも存在しますが、とはいえ一部でも適用できるならば導入すべき手法です。13) コードが動いてるなら、コードは正しい
奇数だけを足し合わせるsumOddValues関数を見てみましょう。 何か問題はあるでしょうか。
const sumOddValues = (array) => {
return array.reduce((accumulator, currentNumber) => {
if (currentNumber % 2 === 1) {
return accumulator + currentNumber;
}
return accumulator;
});
};
console.assert(sumOddValues([1, 2, 3, 4, 5]) === 9);
assertは問題なく動作します。よかったよかった。
このコードは未完成です。 このコードはサンプルコードを含めたいくつかのテストを通しますが、それ以上に問題があります。 例を挙げてみましょう。
Problem #1
引数が空の時の処理がありません。 この関数を引数なしで呼び出すとエラーが発生します。
> TypeError: Cannot read property 'reduce' of undefined.
これは2つの点で良くないコードです。 関数の使用者は、その実装の詳細を知りません。 このエラーメッセージは使用者にとって役立ちません。
この関数は機能しませんでしたが、たとえば次のように適切な例外を出したりすることで、その理由が使用者が誤って使ったことだとわかるようになります。
> TypeError: Cannot execute function for empty list.
しかし、おそらくはエラーを投げるかわりに0を返すような設計にした方が適切かもしれません。 何れにせよ、元のままではなく何らかの改修を行う必要はあるでしょう。
Problem #2
不正な入力への対策がありません。 配列ではなく文字列、数値、Objectなどが突っ込まれたときにはどうなるでしょうか。
sumOddValues(42);
TypeError: array.reduce is not a function
array.reduceは間違いなく関数なので、このエラーメッセージはとても残念です。 引き数名にarrayと名前を付けたので、引数は何であれarrayという名前になってしまいます。 エラーメッセージが意味するところは、42.reduceは関数ではないということです。 このエラーメッセージは明らかに混乱を助長するでしょう。 以下のようなメッセージを出した方が有用です。
> TypeError: 42 is not an array, dude.
問題点1と2はエッジケースと呼ばれます。 エッジケースは対応方法がほとんどパターン化されているので、対応方法について考慮を必要とするようなエッジケースはほとんどありません。 以下の例はどうでしょう。
> sumOddValues([1, 2, 3, 4, 5, -13]) // => still 9
-13は奇数であるにもかかわらず、この関数は9を返してきます。 この関数には、この機能が必要ですか? この入力には例外を出す必要がありますか? 負数を受け入れる必要がありますか? 今のように負数を無視するだけでいいですか? そうであれば関数名はsumPositiveOddNumbersのほうが適切でしょう。
上記例ではどのように仕様を決めるかは簡単でした。 重要なポイントは、その仕様を明文化するためのテストケースを書いていなかった場合、将来の保守担当者は負数を無視することが意図的なものかバグなのかわからないことです。
> それは仕様です。 - 詠み人知らず
Problem #3
有効な全てのケースがテストされていません。 この関数には、処理が正しく行われない非常に単純なエッジケースが存在します。
> sumOddValues([2, 1, 3, 4, 5]) // => 11
2は奇数ではないのに結果に含まれてしまっています。 理由は簡単で、reduceに第二引数を渡すとaccumulatorの初期値として扱います。 第二引数を渡さない場合、reduceはコレクションの最初の値をaccumulatorの初期値にします。 これによって、sumOddValuesの結果にはコレクションの1番目の値が常に含まれてしまいます。
コードを書いたときに、これらの値をチェックするテストを書いていれば、問題をすぐに発見することができたでしょう。 テストを最小限しか書かない、エッジケースのテストを書かない、などの兆候は初心者の証です。14) 既存コードを疑わない
あなたが常にソロで働いているスーパースターでもないかぎり、品質のよくないコードに出会わないということはありません。 初心者は出会ったコードの品質を気にせず、正しく動くのだから良いコードだと認識し、自分の知識に取り入れます。
さらに悪いこと、彼らはそれらが良いコードであると思っているため、至る所でその悪いコードを量産するようになります。
一見非常によくないコードのように見えるものもありますが、何らかの特別な理由によってあえてそのように書かれているコードも時にはあります。 そのような場合は、そのコードがどうしてそう書かれているのかを解説するコメントが付いていることが、よいコードの見分け方になります。
初心者であるならば、理解できないうえに解説も書かれていないコードは悪いコードだ、と考えておくとよいでしょう。 それらについて質問し、git blameしましょう。
そのコードの作者が既にいない、あるいは内容を覚えていない場合は、そのコードを調査し、中身を理解しましょう。 コードを完全に把握できたときにのみ、そのコードについての善し悪しを判断しましょう。 理解する前に仮定を当て推量してはいけません。15) ベストプラクティスに拘泥する
"ベストプラクティス"という言葉は有害だと私は考えています。 ベストプラクティスはつまり、これ以上研究する余地はない、疑問を差し挟んではいけない、ということです。
ベストプラクティスなど存在しません。 現時点で、そのプログラミング言語に対しての"グッドプラクティス"が存在するだけです。
かつてベストプラクティスとされていた文法のいくつかは、現在ではバッドプラクティスだと認定されています。
十分に時間をかければ、常によりよい方針を見つけることができるでしょう。 ベストプラクティスにこだわるのをやめ、ベストを尽くすことに集中しましょう。
どこかでそうしろというのを見たから、誰かがそうしているのを見たから、誰かにそう言われたから、だからそうする、ということはしないでください。 これには、私がこの記事で示している全てのアドバイスも含まれています。 全てを疑い、定石に挑戦し、全ての選択肢を調べ、意義のある意思決定を行いましょう。16) 最適化に拘泥する
> 時期尚早な最適化は、プログラミングにおける諸悪の根源だ - Donald Knuth
ドナルド・クヌースがこの発言をして以来、プログラミングは大きく変わりましたが、この発言の重要性は変わっていません。
ひとつ覚えておくべきことは、ボトルネックがどこにあるのかを測定するまでは最適化するべきではないということです。
コードを実行する前に最適化するのは時期尚早であり、そもそも最適化が完全に不要である可能性すらあります。
もちろん、新しいコードを導入する際は常に検討しておくべき最適化項目は存在します。 たとえばNode.jsでは、イベントループを溢れさたり、コールスタックをブロックしたりしないことが非常に重要です。 これらは念頭に置いておくべき、真っ先に最適化するべき例です。 実装するコードはコールスタックをブロックするかについては毎回自問してください。
既存のコードに対して、測定を伴わずに行う最適化は有害であり、避けるべきです。 パフォーマンスの向上と引き替えに、予想外のバグが発生する可能性があります。
発生していないパフォーマンス問題の最適化のために時間を無駄にしてはいけません。17) エンドユーザの視点に立たない
アプリケーションに機能を追加する最も簡単な方法は何でしょう。 自分の立場で考えると、既存のインターフェイスに適合するところを選ぶのが適切でしょう。 その機能がユーザからの情報入力を必要とする場合は、既に存在するフォームに追加します。 その機能がページへのリンクを追加することであれば、既に存在するリンクメニューに追加します。
開発者視点で見てはいけません。 自分がエンドユーザであるという視点で物事を見ましょう。 その機能の使用者は何が必要であるか、ユーザはどのように行動するかを考えましょう。 必要なのは、ユーザがその機能を簡単に見つけて簡単に使える方法であって、簡単に実装する方法ではありません。18) 適切なツールを使わない
誰もが、プログラミングについてのお気に入りツールを持っています。 いくつかのツールは素晴らしいものであり、いくつかのツールはよくないものですが、ほとんどのツールは、ある分野には強力ですが他の分野にはそれほどでもありません。
ハンマーは釘を壁に打ち込むには良い道具ですが、ねじを回すには最悪の道具です。 どれだけハンマーが好きだったとしても、それをねじ回しとして使ってはいけません。 Amazonのユーザレビューで5.0を取っていたとしてもです。
使うツールを人気で選ぶのは初心者の証です。
問題の理由のひとつは、その仕事により適したツールについて知らないことでしょう。 あなたが今使っているツールは、あなたが今知っている中では最良のツールであるかもしれませんが、しかし決して全てのツールの中で最良というわけではありません。 使えるツールには絶えず手を出し、新しいツールについても使い始めることができるようになっている必要があります。
一部のコーダーは新しいツールの使用を拒否します。 彼らは既存のツールに慣れきっており、新しいツールを習得したがらないでしょう。 彼らの気持ちは理解できますが、しかしその態度は単に間違っています。
あなたは原始的なツールで時間を浪費しながら家を建てることも、良いツールにお金と時間を投資した後に短時間でよりよい家を建築することもできます。 ツールは絶え間なく改善されており、それらについて絶え間なく学習し、使っていく必要があります。19) コードの問題がデータの問題に派生する
プログラムの重要な仕事のひとつは、何らかの形のデータの管理です。 プログラムは、新しいレコードを追加したり、古いレコードを削除したり、レコードを変更したりするためのインターフェイスです。
プログラムのバグはほんの小さなものであっても、致命的で予測不可能なダメージをデータに与える可能性があります。 全てのデータがバグのあるプログラムを通っている場合、事態はさらに深刻です。
初心者は、コードとデータの関係性が結びつきにくいかもしれません。 その機能は現在動作しておらず、重要でもないので、気にせずバグの入ったコードを使い続けているかもしれません。 問題は、バグの入ったコードが、データの完全性を誰も気がつかないうちに壊してしまっている可能性があることです。
より悪いのは、データに起こったバグに対応せずにコードのバグだけを修正することです。 そのコードは小さなデータの問題を増幅し、ときに回復不可能なレベルにまでデータが破損してしまいます。
これらの問題からデータを守る方法は? たとえばデータの整合性を検証する複数のレイヤを使用できます。 ひとつのレイヤだけに整合性の担保を頼ってはいけません。 フロントエンド、バックエンド、ネットワーク、およびデータベースのレイヤに検証を入れましょう。 それができないとしても、最低限データベースレベルの制約は使用しなければなりません。
データベースの制約について理解し、テーブルや列を追加するときに使うべき制約は必ず使用しましょう。
NOT NULL
NOT NULL制約は、その列に対してNULL値の設定を禁止します。 アプリケーションがそのフィールドの値を必須としているのであれば、データベースにはNOT NULL制約を入れなければなりません。
UNIQUE
UNIQUE制約は、その列がテーブル全体で重複する値を持つことができない制約です。 たとえばユーザテーブルのユーザ名、メールアドレスなどが指定するのに適切です。
CHECK
CHECK制約は、その式を満たさないかぎりデータを受け入れません。 たとえば、値が0以上100以下でなければならない場合、CHECK制約を使うことでそれを強制できます。
PRIMARY KEY
PRIMARY KEYは、列の値がNULLではなくユニークであることを表します。 おそらくこれは使用しているでしょう。 データベース内の各テーブルには、レコードを識別するためのPRIMARY KEYが必要です。
FOREIGN KEY
FOREIGN KEYは、列の値が、別のテーブルの列、通常はPRIMARY KEYでしょう、と一致しなければならないことを意味します。
新人が犯しがちな、データの整合性に関するもうひとつの問題が、トランザクションという考え方の欠如です。 複数の操作が互いに依存しているデータを変更する場合、それらの操作のひとつが失敗したときに全てを元に戻すために、トランザクションを使う必要があります。20) 車輪の再発明
ここは難しい点です。 プログラミングはいまだに全てがわかっている分野ではなく、いくつかの車輪には再発明する価値があることもあります。 多くの物事が非常に早く変化し、新しい要素がどんどん流入してきます。
例えば、現在の時間帯に応じて異なる速度で回転する車輪が必要になった場合は、既に存在している車輪をカスタマイズするのではなく、おそらく車輪の再設計が必要になるでしょう。 ただし円形をしていないなど、既存設計に則っていない車輪は、それがどうしても必要でないかぎり再発明しないでください。
多くの選択肢の中から、適切なブランドの車輪を選択することはしばしば困難です。 購入する前にいくつかの選択肢を試してみてください。 ソフトウェアの良いところは、その多くが無料であり、車輪の内部を直接見ることができることです。 車輪の品質は、内部のコード設計を見ることで容易に判断できます。 可能であればオープンソースの車輪を使用してください。 オープンソースは簡単にパッケージを修正することができ、簡単に交換することができ、さらに社内でサポートすることもできます。
なお、車輪が必要な場合は、車を1台購入するのではなく、既に所有している車に車輪だけを取り替えてください。 ひとつふたつの関数を使用するためにライブラリ全体を導入してはいけません。 このことに関する適切な例はJavaScriptのlodashライブラリでしょう。 配列をシャッフルするためには、shuffleメソッドだけをインポートすればよいことで、lodashライブラリ全体をインポートする必要はありません。21) コードレビューへの向かい方
初心者に見られる兆候のひとつが、コードレビューを批判と捉えることです。 彼らはそれを好まないし、感謝しないし、剰えそれを恐れさえします。
それは間違っています。 そのように感じたとしたら、すぐに向き合う態度を変える必要があります。 全てのコードレビューは学習の機会と考えてください。 それらを歓迎し、認め、それらから学びましょう。 そして最も重要な点はレビュアーに感謝することです。
あなたは永遠にコードの学習者です。 それを認識しなければなりません。 ほとんどのコードレビューは、あなたが知らなかったことを教えてくれます。 学習リソースであると分類しましょう。
時にはレビュアーが誤っていて、あなたが彼らに何かを教える番になることもあるでしょう。 ただし、あなたのコードだけではどちらが良くないか明らかではないのであれば、コードを修正する必要があるかもしれません。 レビュアーに対して何かを教える機会があるならば、それはプログラマーとして最も有益な活動のひとつです。22) バージョン管理しない
初心者はバージョン管理システムの力を知りません。 ここではGitを対象とします。
バージョン管理は、単に他人のコードに変更を加えてpushするだけのものではありません。 バージョン管理は、つまり歴史です。 コードについて疑念があったときに、そのコードの歴史は疑問を解決してくれる役に立つことでしょう。 従ってコミットメッセージは重要なものになります。 それはあなたの実装が何のために行われたものなのかを表現する手段のひとつです。 コミットはできる限り小規模にすることで、将来のメンテナが、コードが何故そのような状態になっているのかを調査するのに役立ちます。
頻繁に早期に一貫的にコミットし、コミットメッセージは現在形を使用します。 コミットメッセージには要約を、詳しく記載します。 メッセージが数行以上必要になるようであれば、それはコミットが大きすぎるという証なのでrebaseしましょう。
コミットメッセージには不要なものを含めないでください。 たとえば追加変更削除されたファイル名の一覧などは不要です。 それらはコミット自体に入っていて、コマンドで簡単に表示させることが可能なので、単なるノイズでしかありません。 また、ファイルごとに異なるコミットメッセージを付けたいと考える人もいるかもしれませんが、それもおそらくコミットが大きすぎる兆候のひとつでしょう。
バージョン管理は、到達可能性に関するものでもあります。 ある関数の設計や必要性に疑問を感じたときに、その関数が導入されたコミットを見つけて当時の状況を知ることができます。 コミットはまたプログラムにバグが混入されたタイミングを特定するのにも役立ちます。 bisectコマンドを使って、バグが入ってきたコミットをバイナリ検索で特定することができます。
バージョン管理は、変更を公式に取り込むという用途以外でも大活躍します。 ステージング環境の構築、パッチの選択、修正のリセット、棚上げ、コミットの修正、差分の確認、取り消しなどなど、コードフリーに機能豊富なツールが追加されます。 これらを理解し、学習し、使用しましょう。
知っているGitの機能が少ないほど初心者に近いと言えます。23) グローバル使いすぎ
ここでは関数型プログラミングとそれ以外のパラダイムの差異を話す、わけではありません。 それは別の記事でやります。
ここで話すのは、グローバルは全ての元凶であり、可能な限り避けるべきものである、という事実にすぎません。 万一それが不可能である場合でも、グローバルの使用は必要最小限に抑えなければなりません。
私が初心者だったころに認識していなかったこととして、定義した全ての変数は共有状態にあるということがあります。 要するにその変数は、その変数と同じスコープにある全ての要素から操作可能であるということです。 スコープがグローバルに近づくほど、この共有状態の治安は悪化します。 可能な限り小さなスコープを保ち、外側に流出しないようにしてください。
複数のリソースが同時にひとつの変数を操作しようとしたときに、グローバルの大きな問題が発生します。 レースコンディションです。
初心者は競合状態、特にデータのロックについての問題への回避策として、タイマーを使用したがる傾向があります。 それは危険信号です。 してはいけません。 コードレビューで指摘し、拒絶してください。24) エラーを嫌う
エラーはよいことです。 コードが前進していることを意味します。 つまり、改善のフォローアップが簡単に行えます。
プロの開発者はエラーを愛しますが、初心者は嫌います。
エラーが気に障ると考えているのであれば、エラーへの態度を改める必要があります。 エラーはヒントであり、対処し、活用するものであると考えましょう。
いくつかのエラーは例外に改修する必要があります。 例外は、ユーザが定義するエラーの一種です。 また、他のいくつかのエラーはそのままにしておく必要があります。 それらはアプリをクラッシュさせて強制終了させます。25) 休憩を取らない
あなたはおそらく人間であり、脳には休憩が必要です。 あなたの身体には休息が必要です。
あなたはしばしばゾーンに入り、寝食を忘れて集中することもあるでしょう。 私はそれを初心者の兆候であると考えています。 これは何某かで代替できるようなものではありません。
ワークフローに休息を統合しましょう。 短い休憩をたくさん取り、机から少し離れて周囲を歩き、次に何をするか考えてみましょう。 心機一転してコードに戻ってください。
このポストはとても長いものでした。あなたは休憩が必要です。 読んでくれてありがとう。
The Mistakes I Made As a Beginner Programmer
초보 프로그래머 범하는 실수들을 특정해 그것을 피하는 습관을 배우는 방법.
우선 처음으로 말해둘 것이 있습니다.
이 글은, 실수를 일으키는 것이 나쁘다는 전제로 쓴 글이 아닙니다.
오히려 실수를 스스로 깨닫아 그것을 징후를 간파해, 피하기 위한 글입니다.
나는 과거에 이런 실수를 범해 여러가지를 배웠습니다.
지금은 이것을 피하기 위한 코딩을 습관으로 가지고 있습니다.
당신들도 그렇게 할 수 있습니다.
순서는 무작위입니다. 설계하지 않고 구현한다
품질 높은 컨텐츠는 일반적으로 용의주도하게 작성하지 않으면 안됩니다.
그러기 위해서는 신중한 사고와 연구가 필요합니다.
품질 높은 프로그램도 물론 예외가 아닙니다.
좋은 프로그램은 적절한 흐름에 의해 적어있어야합니다.
생각, 연구, 게획, 구현, 검증, 수정.
아쉽게도 이를 한 마다로 표현할 적당한 말은 없습니다.
각각의 프로세스에 어느 정도의 비중을 둘까, 적절한 가중치를 검토하는 습관을 만드는 것이 중요합니다.
내가 초보일 때 범한 큰 실수는 생각, 연구하지 않고 갑자기 코드를 적는 것이었습니다.
이것은 작은 독립 앱에서는 유효한 수단일지 모르나, 대규모 앱에는 엄청난 악영향을 끼칩니다.
생각하기 전에 말해 후회한 적이 있을지도 모릅니다.
이런 생각처럼, 생각하기 전에 코딩하는 것을 후회할지 모릅니다.
생각할 필요가 있습니다.
코딩도 생각을 전달하는 수단의 하나입니다.
화가 나면, 입을 열기 전에 10을 세라, 개빡쳤다면 100을 세라. Thomas Jefferson.
제가 바꿔 말하면 이렇게 됩니다.
코드를 쓸 때는, 리팩토링 전에 10을 세라, 테스트를 적지 않았다면 100을 세라. Samer Buna
프로그래밍이란 주로, 기존의 코드를 읽는 것입니다.
그리고 필요한 기능과 현재 구현의 괴리를 조사해, 어떻게 해야 최소한의 테스트로 그 차이를 메울 수 있는지 설계하는 것입니다.
실제 코드 작성은 이 프로세스 전체의 10%정도 밖에 되지 않습니다.
프로그래밍은 코드를 적는 것이다 생각하지 맙시다.
프로그래밍은 성장을 필요하는 논리적 창조성입니다. 구현하기 전에 설계를 너무한다
코드를 적기전에 계획을 세우는 것은 좋습니다. 맞습니다.
그러나 너무 과하면 오히려 나빠집니다.
물을 너무 많이 마시면 독이 되는 것처럼.
완전한 설계를 하려는 것은 안 됩니다.
프로그래밍 세계에 그것은 존재하지 않습니다.
구현을 하기위해 필요한 적당한 수준의 설계를 찾아봅시다.
실제 설계는 자주 바뀌는 것 입니다.
적절한 설계는 코드 구조를 클린하게 하기 위해서 필요합니다.
하지만 과한 설계는 그저 시간을 허비하는 것입니다.
설계는 조금씩 하는 것이 좋습니다.
모든 기능을 한 번에 설계하는 것은 단호하게 금지해야합니다.
그것은 워터폴이라 부르며, 시스템 순서에 하나하나 완성시켜 설계하는 것입니다.
이 방법에는 도대체 어느 정도의 설계가 필요해질까요.
대부분의 소프트웨어 프로젝트에는 워터폴 설계는 제대로 돌아가지 않습니다.
복잡하면 할수록 애자일외에는 방법이 없습니다.
프로그램 개발은 변화에 민감할 필요가 있습니다.
워터폴 설계시점에는 없던 기능을 구현한 적이 있을 것입니다.
워터폴 설계시점에 고려하지 않았다는 이유로 기능을 삭제한 적도 있을 것입니다.
버그는 수정하고, 변화에 적응할 필요가 있습니다.
즉 애자일이어야 할 필요가 있습니다.
단, 다음 구현할 기능에 대해서 미리 설계해야합니다.
너무 적은 설계도 너무 많은 설계도 당신의 코드 품질을 깍아먹습니다.
그리고 품질 낮은 코드는, 당신 자체의 품질과 연결됩니다. 품질관리의 과소평가
코드를 적을 때 우선해야할 한가지는 그것은 "읽기 편함"입니다.
읽기 불편한 코드는 잡동사니입니다.
코드는 재활용할 수 있어야합니다.
코드의 품질관리의 중요성을 과소평가하지 맙시다.
코딩은 구현을 전달하는 수단이라 생각합시다.
코더의 주 임무는, 작업한 솔루션의 구현을 전달하는 것입니다.
프로그래밍에 관해 마음에 드는 문구를 소개합니다.
코드를 적을 때는, 유지관리자가 당신의 주소를 아는 사이코패스라는 것을 잊지말고 코딩해라. Jonh Woods
John의 조언의 훌륭합니다.
작은 것조차 문제입니다.
만약에 인텐트와 대문자, 소문자가 바르게 사용되지 않으면, 당신은 코딩할 자격이 없다 여겨집니다.
tHIS is
WAY MORE important
than
you think
또 금방 알 수 있는 찝찝한 점은 긴 행입니다.
80자 넘은 행만큼 읽기 괴로운 것은 없습니다.
if 블록을 보기 좋게 하기 위해서 복수의 조건식을 1행에 넣어버리고 싶을지도 모릅니다.
그러나 그딴 짓을 하면 안 됩니다.
80자 제한을 넘겨서는 안 됩니다.
이렇게 단순한 문제의 대부분은 Linter나 제형 도구로 간단히 수정가능합니다.
JavaScript라면 ESLint와 Prettier 이 두가지 우수한 도구가 존재합니다.
반드시 이들을 사용하도록 합시다.
코드 품질에는 몇 가지 지뢰가 존재합니다.
함수의 행수가 너무 많다.
긴 코드는 항상 단위 테스트 가능한 작은 단위로 분할할 필요가 있습니다.
개인적으로 10행 이상 함수는 너무 길다 생각한다. (필수가 아닌 가볍게 지향점이라 여기면 됩니다.)
이중부정을 사용한다.
사용하면 안 됩니다.
이중부정을 사용하는 것은 무지하게 나쁜 것이라 생각하지 않을 수가 없습니다.
(이중부정을 사용하는 것은 무지하게 나쁜 것입니다.)
너무 짧거나, 범용적인 데이터 타입을 사용한 명명
변수명에는 설명이 들어가야하며, 애매하지 않은 이름을 붙여야합니다.
CS에 어려운 점은 캐시삭제랑 이름 짓기, 단 2개입니다. Phil Karlton
매직넘버 하드코딩
문자열이나 수치에 고정된 값을 설정하고 싶은 경우에는 값을 변수에 넣어, 적절한 이름을 붙입시다.
const answerToLifeTheUniverseAndEverything = 42;
문제를 회피합니다.
쇼트 커트나 회피책을 그릇한 문제에서 피하면 안 됩니다.
현실을 직면합시다.
긴 코드가 좋다 생각합시다.
대부분의 경우 짧은 코드가 좋습니다.
코드가 읽기 좋게하려면 긴 코드를 고릅시다.
코드를 짧게하기 위해서는 기교를 부려서 one-liners나 삼항연산자를 쓰지 맙시다.
하지만 필요하지 않는데 의도적으로 코드를 길게 쓸 필요는 없습니다.
하지만 필요하지 않는 부분까지 의도적으로 코드를 길게할 필요는 없습니다.
불필요한 코드를 삭제하는 것이 프로그램에 최적의 가장 좋은 개선방법입니다.
프로그램 진척을 행수로 계산하는 것은 비행기 구조의 진취를 무게로 정하는 것과 같습니다. Bill Gates
조건 로직의 과용
조건 로직이 필요한 경우의 태반은 조건 로직이 불필요합니다.
대체방법을 확인해, 가장 읽기편한 선택지를 고릅시다.
명백하게 속도가 차이나지 않는 경우, 퍼포먼스을 최적화할 필요가 없습니다.
또 요다기법이나 조건식 중에 대입도 피합시다. 최초의 해결책에 몰두한다.
프로그램을 시작할 때, 게시된 문제에 대해 해결책을 발견하면 즉석에서 그것에 몰두한 적이 있습니다.
처음 해결책은 복잡한 정도에 대해 생각하기 전에 구현을 시작해, 그것은 필연적으로 실패로 귀결됩니다.
처음 떠올린 해결책은 매력적일지도 모르겠지만, 잘 생각해보면 대체로 더 좋은 방법을 발견할 수 있습니다.
문제에 대해 복수의 해결책을 생각한다는 것은 문제를 완전히 이해하고 있다는 소리입니다.
프로그래머로 당신의 일은 문제의 해결책을 찾는 것이 아닙니다.
더욱 간단하게 문제를 해결책을 찾는 것입니다.
간단하게라는 뜻은, 해결책이 똑바로 적절하게 기능하면서, 읽기도, 이해하기도, 보수하기도 쉬운 것이라는 뜻입니다.
소프트웨어 설계에는 두가지 방법이 있다.
하나는 가능한 간단하면서, 명백하게 결함이 없는 것
다른 하나는 가능한 복잡하면서, 명백하게 결함이 없는 것이다. C.A.R Hoare 포기하지 않는다.
가장 높은 빈도로 범한 실수는 [처음 해결책이 가장 간단한 해결책이 아니라는 것을 눈치채고도 그 방법을 고집한다] 입니다.
포기하지 않은 정신의 나쁜 버전입니다.
포기하지 않는 정신은 대체로 활동에 좋은 방법이지만, 프로그래밍에 적용하면 안 됩니다.
프로그래밍에서 올바른 마음은 빨리 사라지며, 빈번히 실패합니다.
해결책의 의문을 갖는다면, 한 번 그것을 던져버리고 생각을 다시해봅시다.
그 해결책에 얼마나 많은 투자를 했어도 말입니다.
git과 같은 소스관리 도구는 다양한 해결책을 나눠 테스트하는 것에 최적화 되어 있습니다.
그 코드에 얼마나 많은 노력을 했어도, 코드 품질에는 전혀 관계없는 소리입니다.
나쁜 코드를 배제할 필요가 있습니다. 검색하지 않는다.
문제를 해결하려할 때, 처음에 해야할 것을 하지 않아 많은 시간을 소비한 적이 많습니다.
정말 최첨단 기술에서 사용하는 것이 아니라면, 당신이 만난 문제는, 대체로 누군가가 이미 같은 문제를 만나 해결한 것이기도합니다.
즉, 처음에는 검색하자는 소리입니다.
경우에 따라 당신이 문제라 생각하는 것이 문제가 아니라 대답해주기도 합니다.
당신에게 필요한 것은, 문제를 수정하는 것이 아니라, 오히려 받아 들이는 것입니다.
문제를 해결하기에는 필요한 것을 모두 알 필요가 없습니다.
인터넷이 놀라울 정도로 해결책을 가지고 있습니다.
물론, 인터넷을 사용할 때 염두해주세요.
초보에게 있을 법한 행동 중에 하나가, 읽지않고 그대로 사용하는 것입니다.
만약 문제를 정확히 해결하는 코드라해더라도, 이해하지 않은 코드를 결코 사용하지 말아주세요.
크리에이티브한 사람하는 가장 위험한 생각은, 자신이 무엇을 하는지 잘 알고 있다 생각하는 것입니다.
-Bret Victor 캡슐화하지 않는다.
요점은 OOP를 이용하라는 소리가 아닙니다.
기술에 상관없이 캡슐화를 생각하는 것이 좋습니다.
캡슐화를 하지 않은 시스템은, 점점 보수가 곤란해집니다.
앱에서 어떤 기능을 처리하는 경우는 하나에 불과합니다.
그리고 통상적으로 하나의 오브젝트의 책임입니다.
오브젝트가 공개하는 것은, 밖에서 오브젝트를 사용할 때 필요한 최소한 정보입니다.
이것은 기밀을 갖기 위함이 아니라, 앱의 각 부분의 의존관계를 적게하기 위한 컨셉을 만들기 위함입니다.
이 규칙에 따라, 어딘가 떨어진 장소에 무엇인가 안 움직이지일까 걱정하지말며, 클래스, 오브젝트, 메서드 내부를 안전하게 변환하는 것이 가능해집니다.
클래스는 관련할 로직과 스테이트를 모은 개념적 집합의 단위로 만들어집니다.
By class, I mean a blueprint template.
This can be an actual Class object or a Function object.
모듈, 혹은 패키지로 식별할 때도 있습니다.
로직클래스에서는 하나의 독립된 태스크에 하나의 메서드가 필요합니다.
메서드는 하나의 행동만 하며, 그것이 정확히 처리되어야 합니다.
같은 클래스는 같은 메서드 가져야합니다.
초보프로그래머일 때, 저는 어떻게 클래스를 나눠야 하는가 개념적 집합을 잘 몰라서, 무엇인 독립한 태스크인가 잘라 나누는 것이 불가능했습니다.
각 관계가 특별히 없도록, 잡다한 코드를 우겨넣은 "Util" 클래스가 있다면, 이는 초보라는 증거입니다.
한 곳에 간단히 변경을 가하는 것으로, 다른 곳에서 문제가 전파되어, 몇 곳이나 수정하지 않으면 안되는 경우, 그것도 초보자 코드의 특징입니다.
클래스 메서드를 추가한다, 혹은 메서드에 기능을 추가하기 전에, 생각할 시간을 가지기 바랍니다.
생각을 나중으로 미루거나, 나중에 리팩토링하면 되지, 생각하는 것을 멈추기 바랍니다.
이것이 올바른 길로 가는 첫 걸음입니다.
좋은 생각은 코드를 응집도를 높히고, 결합도를 낮추는 것입니다.
[고응집, 저결합]이란, 관련하는 코드는 하나의 클래스로 정리해서 적으며, 각 클래스 사이의 의존관계를 줄인다는 의미의 표현하는 귀여운 용어입니다. 불필요한 확장성을 담는다.
현재 해결책을 뛰어 넘는 방법을 생각하는 것은 꽤 매력적입니다.
당신이 쓴 이런 저런행에 [만약 여기에 ㅇㅇ가 있으면] 이런 생각을 떠올릴 수도 있습니다.
이는 엣지 케이스 테스트에 대해 생각할 때는 좋은 방법이지만, 아직 구현되지 않은 대상에 대해 대응하는 것은 실수입니다.
머리가 떠올린 [만약 여기에 ㅇㅇ가 있으면]은 둘 중 무엇인지 반드시 분류할 필요가 있습니다.
오늘 필요하지 않은 코드는 오늘 쓸 필요가 없습니다.
결정되어 있지 않은 일을 집어넣지 마십시오.
성장하기 위한 성장은 암세포이다.
Edward Abbey
올바른 자료구조를 사용하지 않는다.
코드리뷰를 할 때, 초보 프로그래머가 알고리즘에만 중점을 두고는 합니다.
적절한 알고리즘을 특정해서, 필요에 응해 그것을 사용하려하는 것은 좋습니다만, 그것으로 천재 프로그래머가 될 수 없습니다.
사용하고 있는 언어에 준비된 다양한 자료구조에 대해, 그 장점과 단점을 기억하시면 더 좋은 개발자가 될 것 입니다.
부적절한 자료구조를 사용하는 것은, 즉 [여기에 초보가 있습니다.] 말하는 것과 같은 행동입니다.
이 글에서는 자료구조의 상세한 것까지 다루지 않지만, 간단한 예시를 몇 올리겠습니다.
Using lists(arrays) instead of maps (objects) to manage records
가장 좋은 자료구조 선택에서 실수는 복수의 레코드를 map이 아니라 list로 관리하는 것입니다.
맞습니다, 레코드 관리는 map를 사용하면 안됩니다.
이하의 각 레코드에 그 레코드를 특정하기 위한 하나의 키가 존재하는 경우에 대해서만 다룹니다.
스칼라값에 list를 사용하면 문제없이, 특히 값을 push해서 사용하는 경우 더 많은 선택이 됩니다.
JavaScript에는 우선 일반적으로 list는 array로, 가장 일반적인 map은 object입니다.(최근에는 Map도 있습니다.)
레코드를 관리하기 위해 list를 사용하는 것은 잘 못 된 것입니다.
이것이 중요한 이유는 식별자를 사용해서 레코드를 검색하는 경우, map은 list보다 현저히 빠르기 떄문입니다.
실제로 눈에 보이는 영향이 보이는 것은 콜렉션이 거대했을 경우입니다만, 그것만으로도 고집할 충분한 이유입니다.
Not Using Stacks
반복을 필요할 때, 단순히 재귀를 선택하면 됩니다.
하지만, 재귀코드를 최적화하는 것은 꽤 어렵습니다.
특히 싱글 스레드 환경이라면 더욱 그러합니다.
재귀함수의 최적화는 대상에 의해 난이도가 현저히 달라집니다.
만약 2개 이상 값을 반환하는 코드의 최적화라면, 반환이 하나인 함수에 보다 무척 어려워집니다.
초보자가 그냥 넘기는 경우도 있습니다만, 재귀 대신 사용할 수 있는 자료구조가 있다는 것입니다.
바로 스택입니다.
함수를 호출하는 대신에 스택을 쌓아, 완료되면 pop합시다. 코드를 악화시킨다.
지저분한 방을 상상해보세요.
이 방에 아이템을 설치해야한다는 요구를 들었습니다.
방은 이미 충분히 난잡하기에, 적당히 둬도 괜찮지 않을까 생각할 수 있습니다.
이 작업은 몇 초면 되지요.
난잡한 코드에는 그러면 안됩니다.
절대 악화시키면 안됩니다.
조금이라도 좋으니, 작업을 개시하기 전에 코드를 정리합시다.
지저분한 방에 해야할 일은, 새로운 것을 두기 위해 필요한 위치를 정돈하는 겁니다.
예를 들어 둬야할 것이 옷이라면, 우선은 옷장을 정리해야겠지요.
그것만으로, 당신는 올바른 일을 하기 위한 첫 발을 뗀 것입니다.
코드를 점점 악화시키는 방법을 몇 가지 들어보겠습니다.
Duplicating code
코드를 복붙해 일부 행을 변환하는 행위는 중복코드를 부르며, 코드의 순수성를 악화시킵니다.
더러워진 방을 예로 들어면 높낮이가 조절되는 의자를 넣는 것이 아니라, 높낮이가 다른 의자를 넣는 것입니다.
되도록 추상적으로 사용하는 것을 마음에 두십시오.
Not using configuration files
환경이나 시간대에 따라 다른 값을 사용하고 싶은 경우, 이 값은 설정 파일에 적어둡시다.
코드 안에 여러 각 자리에 하나의 값을 사용한 경우, 그 값은 설정 파일에 적어둡시다.
코드에 새로운 값을 도입하는 경우는, 그 값은 설정파일에 적어둡시다.
대부분의 경우 옳은 길입니다.
Using unnecessary conditional statements and temporary variables
모든 if문은 적어도 2회 테스트할 필요가 있는 분기입니다.
가독성을 낮추지 않으며, 분기를 피할 수 있다면, 그렇게 해야합니다.
새로운 함수를 만드는 대신, 함수에 분기로직을 도입한 경우 종종 문제가 됩니다.
if문이나 새로운 함수가 필요가 생길 때마다, 그 변경은 적절한가 다른 차원에 대응할까 자문해 보십시오.
function isOdd(number) {
if (number % 2 === 1) {
return true;
} else {
return false;
}
}
isOdd는 몇 가지 문제가 있습니다만, 가장 큰 문제는 어디일까요?
if문 명백히 필요없으므로, 이렇게 쓰는 것과 같습니다.
function isOdd(number) {
return number % 2 === 1;
}
의미없이 주석을 쓴다.
되도록 주석은 쓰지 않는 것이 좋은데 어려운 일입니다.
대부분의 주석은 코드 내의 요소명을 적절히 바꿔 쓰는 것으로 배제할 수 있습니다.
// This function sums only odd numbers in an array
const sum = (val) => {
return val.reduce((a, b) => {
if (b % 2 === 1) {
// If the current number is even
a += b; // Add current number to accumulator
}
return a; // The accumulator
}, 0);
};
이 코드는 이렇게 쓰면 주석을 쓸 필요가 없습니다.
const sumOddValues = (array) => {
return array.reduce((accumulator, currentNumber) => {
if (isOdd(currentNumber)) {
return accumulator + currentNumber;
}
return accumulator;
}, 0);
};
단순히 함수명이나 인수명을 적절히 붙이는 것으로, 대부분의 주석은 필요하지 않습니다.
주석을 쓰기 전에 생각해보세요.
하지만, 어떻게든 주석을 쓰지 않으면 안되는 경우가 생기기도 합니다.
그럴 때는 이 코드는 무엇인지(WHAT)이 아니라, 이 코드는 왜 그렇게 되는가 (WHY)를 설명해야합니다.
코드에 WHAT 주석을 쓰는 것을 요구받는 경우에도, 너무 명백한 것을 적지 말아주세요.
// create a variable and initialize it to 0
let sum = 0;
// Loop over array
array.forEach(
// For each number in the array
(number) => {
// Add the current number to the sum variable
sum += number;
},
);
이는 코드에 잡음을 넣는 것으로, 전혀 도움이 되지 않습니다.
이런 프로그래머가 되면 안됩니다.
또 저렇게 처리하면 안됩니다.
대처가 가능한 주석을 삭제하세요.
부하가 이렇게 쓰면 바로 한 마디 해줍시다. 테스트를 적지 않는다.
요점을 간결히 말하겠습니다.
당신이 자신은 테스트를 쓰지않아도 생각을 그대로 코드로 옮겨 적을 수 있는 숙련된 프로그래머라 생각한다면 당신은 초보입니다.
테스트 코드를 쓰지 않은 경우, 코드 외의 방법으로 프로그램을 수동테스트것이 많을 때일 것입니다.
Web 앱을 만든다면, 코드 조금 쓸 때마다 화면을 새로고침해서 확인합니다.
저도 그러합니다.
코드를 수동테스트 하는 것은 이상한 것이 아닙니다.
그러나, 그것과 동시에 코드를 자동테스트하는 방법에 대해서도 생각하지 않으면 안됩니다.
수동테스트가 정상적으로 마친 후에, 코드에디터로 돌아가, 새로운 코드를 적고, 다시 수동테스트... 이런 식으로 몇 번이고 같은 짓을 한다면, 이걸 자동적으로 수행하는 코드를 쓰는 것이 좋을 것입니다.
당신은 사람입니다.
즉, 당신은 몇 번 테스트한 내용을 잊어버립니다.
이러한 반복은 컴퓨터에게 시키십다.
가능하다면, 코드 본체를 쓰기 전에, 코드가 가져야 할 조건을 설계, 추측하는 것부터 시작해봅시다.
테스트 주도 개발(TDD)을 말만이 아니라, 기능이나 디자인에 대해서도 긍정적인 영향을 줍니다.
TDD 모든 사람에게 적절한 것은 아니기에, 잘 적용되지 않은 프로젝트도 있습니다.
그렇지만 일부라도 적용할 수 있다면 바로 해야할 기법입니다. 코드가 움직인다면, 코드는 옳다.
홀수만 더하는 sumOddValues 함수를 봅시다.
무엇이 문제일까요?
const sumOddValues = (array) => {
return array.reduce((accumulator, currentNumber) => {
if (currentNumber % 2 === 1) {
return accumulator + currentNumber;
}
return accumulator;
});
};
console.assert(sumOddValues([1, 2, 3, 4, 5]) === 9);
assert은 문제없이 동작합니다. 메테타시 메테타시.
이 코드는 미완성입니다.
이 코드는 샘플 코드를 포함해 몇 몇 테스트를 통과했지만 그 이상 문제가 있습니다.
예를 들어보겠습니다.
Problem #1
인수가 비어있을 때 처리가 없습니다.
이 함수를 인수없이 호출하면 에러가 발생합니다.
> TypeError: Cannot read property 'reduce' of undefined.
이 두가지 점에서 좋지 못한 코드입니다. 함수 사용자는 그 상세한 구현을 모릅니다. 이 에러 메세지는 사용자에게 도움이 되지 않습니다.
이 함수는 기능하지 않습니다만, 만약 다음과 같이 적절한 예외를 던짐으로, 사용자가 실수했다 알 수 있습니다.
> TypeError: Cannot execute function for empty list.
하지만 아마 에러를 던지는 대신 0를 반환하는 설계를 하는 것이 적절할 수도 있습니다.
어찌되었든, 본래대로 있는 것이 아니라 개선을 할 필요가 있겠네요.
Problem #2
그른 입력 대책이 없습니다.
배열이 아니라, 문자열, 수치, Object 등이 들어가면 어떻게 될까요?
sumOddValues(42);
TypeError: array.reduce is not a function
array.reduce은 분명 함수이므로, 이런 메세지는 좀 그럽니다.
인수에 array로 이름 붙였는데, 인수는 어찌 되었든 array라는 이름이 되어버립니다.
에러 메세지가 의미하는 것은, 42.reduce는 함수가 아니라는 것입니다.
이 에러 메세지는 혼란을 조장합니다.
이하와 같은 메세지를 띄우는 것이 현명합니다.
TypeError: 42 is not an array, dude.
문제점 1, 2은 엣지케이스라 합니다.
엣지케이스는 대응방법이 대부분 패턴화 되어있으므로, 대응방법에 고찰을 필요하는 엣지케이스는 그 다지 없습니다.
이하의 예는 어떻습니까?
> sumOddValues([1, 2, 3, 4, 5, -13]) // => still 9
-13가 홀수임에도 불구하고, 이 함수는 9를 반환합니다.
이 함수에는 이 기능이 필요합니까?
이 입력에는 예외를 낼 필요가 있습니까?
음수를 받아들일 필요가 있습니까?
지금처럼 음수를 무시해도 됩니까?
그렇다면 함수명은 sumPositiveOddNumbers가 적절할 것입니다.
상기한 것처럼 어떤 사양을 결정할까는 간단합니다.
중요한 포인트는 그 사양을 명문화 하는 테스트 케이스를 적자 않은 경우, 뒤에 보수담당자에게 음수를 무시하는 것이 의도적인 것인가 버그인 것인가 알 수 없게
그것은 사양입니다. 이름 모를 사람
Problem #3
유효한 모든 케이스가 테스트되어 있지 않습니다.
이 함수에는 처리가 제대로 일어나지 않는, 꽤 단순한 엣지케이스가 존재합니다.
> sumOddValues([2, 1, 3, 4, 5]) // => 11
2는 홀수가 아닌데도, 결과에 포함되어있습니다.
이유는 간단한데, reduce에 제 2인자를 전달하면 accumulator 초기값으로 취급됩니다.
제 2인자를 넘기지 않은 경우, reduce 컬렉션의 처음 값을 accumulator의 초기값으로 합니다.
이로인해, sumOddValues 결과에는 컬렉션의 첫번째 값이 이미 포함되어버립니다.
코드를 적을 때, 이 값을 체크하는 테스트를 쓰지 않았다면, 문제가 바로 발견할 수 있었을 겁니다.
테스트를 최소한밖에 쓰지 않는, 엣지테스트를 쓰지않는다, 등 징조는 초심자라는 증거입니다. 기존의 코드를 의심하지 않는다
당신이 이미 혼자서 일하는 슈퍼스타가 아닌이상, 품질이 좋지 않은 코드를 만날 것입니다.
초보자는 만난 코드의 품질을 신경쓰지 않고, 잘 움직이니까 좋은 코드라 인식해, 자신의 지식으로 만듭니다.
더 나쁜 것은, 그게 좋은 코드라 생각하고 있어서 온갖 장소에 나쁜 코드를 양산합니다.
딱 봐도 나쁜 코드가 있습니다만, 어떤 특별한 이유로인해 계속 그렇게 코드를 쓰던 시기가 있기 마련입니다.
그럴 경우에는 그 코드가 왜 그렇게 쓰여지있는가 주석을 다는 것이 좋은 코드를 구분하는 방법입니다.
초보자라면, 이해할 수 없는데 설명도 없는 나쁜 코드는 나쁜코드이다.
이렇게 생각합시다.
이에 이해 질문하며, git blame 해봅시다.
그 코드의 작성자는 이미 없으며, 어떤 경우에는 내용을 기억조차 못하는 경우 그 코드를 조사해서, 속을 이해합시다.
코드를 완전히 파악한 후에, 그 코드에 대해 좋고 나쁨을 판단합시다.
이해하기 전에 가정을 붙여 추측하면 안됩니다. 베스트 프락티스에 몰두한다
베스트 프락티스는 유해한 단어라 생각합니다.
베스트 프락티스, 즉 이건 이 이상 연구할 여지가 없음, 의문의 가질 틈이 없음 이라는 뜻입니다.
베스트 프락티스라는 건 없습니다.
현 시점에, 그 프로그래밍 언어에 대한 굿 프락티스만 존재할 뿐입니다.
일찍이 베스트 프락티스된 문법의 몇몇은, 현재는 배드 프락티스라 인식되고 있습니다.
충분한 시간을 가하면, 더 좋은 방침을 찾는 것이 될 것입니다.
베스트 프락티스에 몰두하는 걸 그만두고, 베스트를 만드는데 집중합시다.
어디선가 베스트 프락티스를 해라 한다면, 누가 그렇게 하고 있다면, 누가 그렇게 말한다면, 그렇기에 한다.
이런 짓은 하지 말아주세요.
저기에는 제가 이 글에서 밝힌 모든 조언도 포함되어 있습니다.
모든 것을 의심하고, 정석으로 도전하며, 모든 선택지를 조사해, 의식해서 의도를 결정합시다. 최적화에 몰두한다
시기상조한 최적화는, 프로그래밍에서 만악의 근원이다. Donald Knuth
도널드 커누스가 이 발언을 한 이후, 프로그래밍은 크게 변했습니다만, 이 발언의 중요성은 변하지 않았습니다.
하나를 배울 때에는, 병목되는 곳이 어딘가에 있을거라 추측하는 것은 최적화할 필요가 없습니다.
코드를 실행하기 전에, 최적화 하는 것은 시기상조이며, 애초에 최적화가 완전하게 불필요한 가능성도 있습니다.
물론, 새로운 코드를 도입하는 경우 이미 검토해야 할 최적화 항목은 존재합니다.
만약 Node.js라면, 이벤트 루프가 넘치거나, 콜스택을 블록하는 것을 하지 않도록 하는 것이 무척 중요합니다.
이를 염두하면서, 제일 먼저 최적화해야합니다.
구현하는 코드는 콜스택을 블록하는가에 대해 매번 자문해주십시오.
기존의 코드를 보며, 측정을 하지않고 하는 최적화는 유해하며, 피해야 할 일입니다.
퍼포먼스를 올리기 위해 바꿔야하는 것에, 예상 외 버그가 발생할 가능성도 있습니다.
발생하지 않은 퍼포먼스 문제를 최적화 하기 위해서 시간을 소비하는 것은 쓸모없는 행동입니다. 엔드유저 시점으로 보지 않는다
앱에 기능을 추가하는 간단한 방법은 무엇일까요.
자신의 입장으로 생각하면, 기존의 인터페이스에 적합한가 고르는 것이 적절합니다.
그 기능이 유저에서 정보입력을 필요로 하는 경우, 이미 존재하는 폼에 추가합니다.
그 기능이 다른 곳으로의 링크를 추가하는 것이라면, 이미 존재하는 링크 메뉴에 추가합니다.
개발자 시점으로 보지마세요.
자신이 엔드유저라는 것은 시선으로 만사를 봅시다.
그 기능이 사용자가 무엇이 필요로하는가, 유저는 어떻게 행동할까 생각합니다.
필요한 것은 유저가 그 기능을 간단히 발견해 간단히 사용하는 방법이지, 간단히 구현하는 것이 아닙니다. 적절한 도구를 사용하지 않는다
누구나 프로그래밍을 할 때 좋아하는 도구를 몇 가지고 있습니다.
어떤 도구는 멋지며, 어떤 도구는 좋지 않습니다만, 대부분의 도구는 어떤 분야에 강력하지 다른 분야에서는 그렇지 않습니다.
망치는 못을 벽에 박을 때는 좋은 도구지만, 나사를 돌릴 때는 최악의 도구입니다.
망치가 너무 좋아도, 그것으로 나사를 박으면 안됩니다.
Amazon 유저리뷰가 5.0여도 그러합니다.
사용할 도구는 인기로 고르는 것이 초보자인 증거입니다.
그 원인의 하나의 이유는 그 일에 더 적합한 도구인가 모르기 때문이지요.
당신은 지금 사용하고 있는 도구는, 당신이 지금 알고 있는 것중에서 제일 좋은 도구일지도 모르겠습니다만, 하지만 결코 모든 도구 중 가장 좋은 것을 아닙니다.
사용하는 도구에 손을 떼서, 새로운 도구를 시작해 볼 필요가 있습니다.
일부 코더는 새로운 도구 사용을 거부합니다.
그들은 기존의 도구에 익숙해져서, 새로운 도구를 습득하고 싶지 않을 것입니다.
마음은 이해합니다만, 하지만 그 태도는 단순하게 말하면 잘 된 것입니다.
당신은 원시적 도구에 시간을 낭비하면서 집을 세울 수도, 좋은 도구에 돈과 시간을 투자한 후에 단기적으로 더 좋은 집을 세울수도 있습니다.
도구는 끊임없이 개선되며, 그것에 대해 끊임없이 학습해, 사용하는 것이 필요합니다. 코드 문제가 데이터 문제로 파생된다
프로그램의 중요한 일 중 하나는, 모든 데이터의 관리입니다.
프로그램은 새로운 코드를 추가하거나, 낡은 레코드를 삭제하거나, 레코드를 변경하는 인터페이스입니다.
프로그램이 버그는 정말 사소해도, 치명적으로 예측불가능한 데미지를 데이터에 줄 수 있습니다.
모든 데이터가 버그가 있는 프로그램을 지나갔다면, 사태는 더 심각합니다.
초보는 코드와 데이터의 관계성을 묶는 것이 어려울지도 모르겠습니다.
그 기능은 현재 동작하지도 않으면서, 중요하지 않으므로, 무의식적으로 버그가 들어가 코드를 계속 쓸 수도 있습니다.
문제는 버그가 들어가 코드가 데이터의 안정성을 조용히 파괴할 수 있다면 가능성입니다.
더 나쁜 것으나, 데이터에 일어난 버그에 대응하지 않고 코드의 버그만 수정하는 것입니다.
그 코드는 작은 데이터의 문제를 증폭시켜, 결국 회복불가능한 수준가지 데이터를 파손시킵니다.
이런 문제에서 데이터를 지키기 위해서는?
예를 들면 데이터의 정합성을 검토할 수 있는 복수의 레이어를 사용할 수 있습니다.
하나의 레이어로는 정합성을 보장할 수 없습니다.
프론트엔드, 백엔드, 네트웤, 여기에 데이터베이스 레이어에 검증을 넣어봅시다.
이게 어렵다면, 최소한 데이터베이스 레벨의 제약은 사용하면 안됩니다.
데이터베이스 제약에 대해 이해하며, 테이블이나 열을 추가하는 것에 사용할 제약을 반드시 사용합시다.
NOT NULL
NOT NULL 제약은, 그 열에 대해, NULL값 설정을 금지합니다.
앱이 그 필드 값을 필수로 한다면, 데이터베이스에는 NOT NULL제약을 넣어야합니다.
UNIQUE
UNIQUE 제약은 그 열에 테이블 전체에 중복하는 값을 갖지 않도록 하는 제약입니다.
예를 들면 유저테이블의 유저명, 메일주소 같은 곳에 지정하면 좋겠네요.
CHECK
CHECK 제약은 그 식을 충족하지 않은 데이터를 받지 않는 것입니다.
예를 들어, 값이 0이상 100 이하가 아니라면, CHECK 제약을 사용하므로 이를 강제할 수 있습니다.
PRIMARY KEY
PRIMARY KEY는 열의 값이 NULL이 아닌 유니크인 경우를 보여줍니다.
아마 이는 사용하고 계시겠지요.
데이터베이스 안에 각 테이블에는 레코드를 식별하는 것의 PRIMARY KEY가 필요합니다.
FOREIGN KEY
FOREIGN KEY는 열의 값이 다른 테이블의 열, (통상적으로 PRIMARY KEY) 와 일치하지 않으면 안된다를 의미합니다.
초보자 범하기 쉬운 데이터 정합성에 관한 하나의 문제는 트랜잭션이라는 생각의 결여입니다.
복수의 조작이 서로 의존해서 데이터를 변경한다면, 그 조작의 하나가 실패할 경우 모든 것을 처음으로 돌리기 위해 트랜잭션을 사용할 필요가 있습니다.
바퀴의 재발명
이건 어려운 부분입니다.
프로그래밍은 지금도 여전히 모든 것을 알고 있는 분야가 아니며, 어떤 바퀴에는 재발명할 가치가 있기도 합니다.
모든 것이 꽤 빨리 변화하며, 새로운 요소가 점점 유입됩니다.
예를 들어, 현재 시간대보다 잘 돌아가는 바퀴가 필요한 경우는 이미 존재하고 있는 바퀴를 커스터마이즈하는 것이 아니라, 그냥 바퀴를 재발명할 필요가 있습니다.
하지만 원형을 하지 않는 것처럼, 기존설계를 벗어난 바퀴는 그것을 어떻게 보더라도 반드시 그것을 써야한다 하는 것이 아닌 이상 재발명하지 말아주세요.
많은 선택지에서 최적한 브랜드의 바퀴를 선택하는 것은 무척 어렵습니다.
구입하기 전에 여러 선택지를 테스트해보세요.
소프트웨어의 좋은 점은, 많은 것이 무료이며, 바퀴 내부를 직접볼 수 있다는 것이다.
바퀴의 품질은 내부 코드 설계를 보는 것으로 쉽게 판단할 수 있습니다.
가능하다면, 오픈소스 바퀴를 사용해주십시오.
오픈소스는 간단히 패키지를 수정하는 것이 가능하면, 간단히 교환하는 것도 되는데다가, 여기에 커뮤니티의 서포트도 있습니다.
또한 바퀴가 필요한 경우는, 차를 1대 구입하는 것이 아니라, 이미 가지고 있는 차에 바퀴만 바꾸시길 바랍니다.
함수 하나, 둘을 사용하기 위해서, 라이브러리 전체를 도입하지 마세요.
이 것으 관핸서는 적절한 예시가 JavaScript의 Lodash입니다.
배열을 셔플하기 위해서는 shuffle 메서드만 쓰면 되지, lodash 라이브러리 전체를 임포트하면 안됩니다.
역주
import lodash from "lodash";
import { shffule } from "lodash";
import shuffle from "lodash/shffule";
import shuffle from "lodash.shuffle";
1번은 너무 크고, 4번은 패치에 따라 어떻게 변할줄 모른다.
되도록 3번을 고르며, 이렇게 하면 적은 번들사이즈로 만들 수 있다.
- https://www.labnol.org/code/import-lodash-211117 코드리뷰를 대하는 방법
초보자 티가 나는 징후 중 하나는 코드리뷰를 비판/비난으로 여기는 것입니다.
그들은 그걸 좋아하지도, 감사하지요 않습니다, 오히려 무서워하죠.
이건 잘 못된 것입니다.
그렇게 느끼셨다면, 빨리 태도를 바꿀 필요가 있습니다.
모든 코드리뷰는 학습의 계기라 생각해주세요.
그것 환영하고, 인정해 그것을 배웁시다.
그리고 가장 중요한 점은 리뷰어에게 감사하자는 것입니다.
당신은 영원히 코드를 배워야합니다.
그것을 의식해주세요.
대부분의 코드리뷰는 당신이 모르는 것을 알려줍니다.
학습기회라 여깁시다.
가끔 리뷰어가 실수해서 당신도 그들에게 무엇인가 알려줄지도 모릅니다.
단, 당신의 코드만으로 어디가 나쁜지 명백히 알 수 없다면, 코드를 수정할 필요가 있습니다.
리뷰어에 대해 무엇인가 배울 기회가 있다면, 그건 프로그래머에게 무척 유익한 활동중 하나입니다. 버전 관리하지 않는다
초보자는 버전관리 시스템의 힘을 모릅니다.
여기는 Git을 예로 듭니다.
버전관리는 단순히 다른 사람의 코드에 변경을 더해 push하는 도구가 아닙니다.
버전 관리는, 즉 역사입니다.
코드에 의심이 생겼을 때, 그 코드의 역사는 의문을 해결해줄 때 도움이 됩니다.
그러므로 커밋 메세지도 중요합니다.
그것은 당신의 구현이 무엇을 위해 있는지 표현하는 하나의 수단입니다.
커밋은 되도록 소규모로 하면, 미래의 관리자가 코드가 왜 그런 상태가 되었는지 조사할 때 도움이 됩니다.
빈번하고 짧게 커밋하며, 커밋 메세지는 현재형을 사용합시다.
커밋 메세지에 요약을 자세히 기술합시다.
메세지가 수행이상 필요하다면, 그 커밋이 너무 크다는 증거이므로 rebase합시다.
커밋 메세지에는 불필요한 것은 넣지맙시다.
예를 들어 추가, 변경, 삭제된 파일명 리스트는 필요없겠죠.
그것은 커밋자체에 들어가서, 커맨드로 간단히 볼 수 있으므로, 소음에 불과합니다.
또 파일 마다 다른 커밋 메세지를 붙이려는 분도 있겠습니다만, 그것은 아마 커밋이 크다는 징후 중 하나입니다.
버전관리는 도착가능성에 관한 것입니다.
어떤 함수의 설계, 필요성에 의문을 느낄 때, 그 함수가 도입된 커밋을 발견해서 당시의 상황을 알 필요가 있습니다.
커밋은 또 프로그램에 버그가 난입된 타이밍을 특정하는데 도움이 됩니다.
bisect 커맨드를 사용해 버그가 들어간 커밋을 이진탐색으로 특정 것도 가능해집니다.
버전관리는 변경을 공식으로 받아들인다는 용도가 아닌 곳에서도 대활약합니다.
스테이징 환경 구축, 패치 선택, 수정의 리셋, 보류, 커밋의 수정, 차이 확인, 되돌리기 등등 코드를 다루는데 풍부한 기능이 있는 도구가 생기는 것입니다.
이것을 이해해, 학습하며, 사용합시다.
일고 있는 Git의 기능이 적은 사람은 초보자에 가깝다 할 수 있습니다. 글로벌의 과용
여기서는 함수형 프로그래밍과 그 이외의 패러다임의 차이를 말하는 것이 아닙니다.
그건 다른 글이 있습니다.
여기서는 글로벌한 것은 만약의 원흉이라는 것, 가능하다면 무조건 피해야한다는 것이라는 사실을 말할 것입니다.
만의 하나 그것이 불가능한 경우라면, 글로벌를 사용은 필요한 최저로 눌러주시길 바랍니다.
제가 초보자가 일 때 의식하지 못한 것 중 하나로, 정의한 모든 변수가 공유상태에 놓여있었다는 것입니다.
다시 말하면, 그 변수는 그 변수와 같은 스코프에 있는 모든 요소에서 조작가능하다는 뜻입니다.
스코프가 글로벌에 가까울수록, 그 공유상태의 치안이 악화됩니다.
가능하다면 작게 스코프를 가지며, 밖으로 유출시키지 마세요.
복수의 리소스가 동시에 하나의 변수를 조작하면, 글로벌은 큰 문제가 생깁니다.
즉, 경합상태입니다(Race Condition).
초보자는 경합상태, 특히 데이터 잠금에 문제의 회피책으로 타이머를 사용하는 경향이 있습니다.
그건 위험신호입니다.
하지마세요.
코드리뷰에서 지적할 일이고, 막을 일입니다. 에러를 싫어한다
에러는 좋은 것입니다.
코드가 전진한다는 의미죠.
즉, 개선의 추적을 간단히 할 수 있습니다.
프로 개발자는 에러를 사랑하지만, 초보는 그렇지 않습니다.
에러가 마음에 들지 않는다면, 에러를 향한 태도를 바꿀 필요가 있습니다.
에러는 힌트이며, 대처이며, 활용한다 생각합시다.
어떠한 에러는 예외적으로 개선하는 필요가 있습니다.
예외는 유저가 정의하는 에러의 하나입니다.
또 다른 몇 에러는 그대로 할 필요가 있습니다.
그것은 앱을 크래시해서 강제종료합니다. 휴식을 하지 않는다면
당신은 인간입니다, 뇌에는 휴식이 필요합니다.
몸도 휴식이 필요합니다.
당신은 점점 자신만의 영역에 들어가, 먹고 자는 것조차 잊으며 집중하기도 할 것입니다.
저는 이것이 초보라는 증거라 생각합니다.
이것은 누가 대신해줄 수 있는 것이 아닙니다.
일의 흐름에 휴식을 넣어야합니다.
짧은 휴식을 많이 취해, 책상에서 떨어져 주변을 걷고, 다음에 무엇을 할지 생각합시다.
심기일전해서 코드로 돌아옵시다.
> "엘리트 코더가 다른 코더보다 뛰어난 능력을 발휘하는 방법"
코더가 아닌 엔지니어가 될 것 (Be an engineer, not a coder)
> 엔지니어링은 문제를 해결하는 것 > 최고의 엔지니어는 코드를 목적 달성을 위한 수단으로 생각함 > 코드를 작성하는 즐거움은 있지만 목적이 없는 코드를 작성하는 것은 의미가 없음. 대신 코드는 사용자를 위한 솔루션을 설계하는 데 사용됨 > 코딩은 창의성을 추구함! 창의력은 제약 조건 하에서 많이 발생함. 해결해야 할 명확한 문제라는 '제약'을 추가하면 엔지니어는 자신이 적합하다고 생각하는 방식으로 솔루션을 탐색하고 만들 수 있는 자유를 누릴 수 있음 > 최고의 엔지니어들은 제품 중심적이며, 무엇보다도 사람을 위한 문제 해결을 최우선으로 생각하며, 이는 다음 단계로 이어짐
컴퓨터가 아닌 인간을 위한 코드 (Code for the human, not the computer)
> "바보라도 누구나 컴퓨터가 이해할 수 있는 코드를 작성할 수 있습니다. 훌륭한 프로그래머는 인간이 이해할 수 있는 코드를 작성합니다." - 마틴 파울러 > 코드는 컴퓨터뿐만 아니라 인간을 위한 것 > 코드는 그 코드를 읽고, 유지 관리하고, 당신의 코드 위에 빌드하는 같은 팀 엔지니어를 위한 것 > 코드는 휴대전화를 사용하는 어린아이, API를 호출하는 개발자, 본인 등 사용자를 위한 것 > 최고의 엔지니어들은 항상 모든 사용자를 위해 코드의 가치를 평가했음 > 만약 그들이 고객 중 한 명이라도 만족시키지 못하면 그 코드는 프로덕션에 적용되지 못했음
코드 자체에서 벗어나기 (Detach from the code itself)
> 뛰어난 엔지니어는 코드 자체에 집착하지 않음 > 그들은 최종 결과물이 전반적으로 더 좋아질 수 있다면 90% 정도 완성된 코드라도 삭제하고 다시 시작하는 것을 두려워하지 않음 > 코드는 개인적인 것이 아니기 때문에 피드백을 적극적으로 받아들임 > 코드는 완벽하지 않음. 아무도 완벽한 코드에 관심을 두지 않음. 변화를 가져오는 코드에 관심이 있을 뿐 > 코드에 집착하지 않도록 스스로를 가르치는 가장 좋은 방법은 "20년 후에는 당신 코드의 대부분이 기술 부채가 되거나 더 이상 사용되지 않거나 다시 작성될 가능성이 높다는 것을 깨닫는 것"
일관된 표준 사용 (Use consistent standards)
> 코드를 작성할 때 일관된 표준과 코딩 스타일을 고수할 것 > 일관성(Consistency)을 유지하면 미래의 당신과 팀원 모두가 코드를 더 쉽게 읽고 이해할 수 있게 해줌 > 일관된 스타일 가이드를 사용하면 팀과 코드베이스 모두 더 쉽게 확장할 수 있음 > 이게 Meta/Google 같은 회사가 시간이 지나도 코드베이스를 읽을 수 없거나 유지 관리할 수 없게 되는 일 없이 많은 코드를 신속하게 배포하는 방법 > 모든 뛰어난 성과를 내는 기업은 스타일 가이드를 내재화하고 그 이점을 알고 최대한 이를 따랐음 > 구글은 일부 스타일 가이드를 오픈소스로 공개했음 > 메타는 그들의 일부 오픈소스에 C++ 스타일 가이드가 있음 > 팁: 당신의 팀을 위해서 Linter를 포맷팅하는 것은 확실히 시간을 들여 설정할 가치가 있음
간단한 코드를 작성 (Write simple code)
> 내가 아는 모든 엘리트 엔지니어는 생성하기엔 복잡했을 수도 있지만, 결국엔 읽고 이해하기 쉬운 코드를 생성했음 > 이에 대해 내가 한 가장 좋은 말은 그들의 코드가 "미학적으로 만족스럽다는 것" > 그들의 코드는 깔끔하고, 체계적이며, 논리적(clean, organized, and logical) > 코드에서 내린 각 결정은 의미가 있었고, 그렇지 않은 경우엔 코드내에 잘 문서화 되어 있었음 > 깔끔한 코드를 작성하는 좋은 방법은 SOLID 원칙과 같은 원칙을 따르는 것. 처음에는 OOP(객체 지향 프로그래밍)를 염두에 두고 설계되었지만 일반 프로그래밍에도 확장할 수 있음 > Single Responsibility: 한 클래스는 하나의 책임만 가져야 함 > Open-Closed: 소프트웨어 객체(클래스, 모듈 등)는 확장에는 개방적이지만 수정에는 폐쇄적이어야 예측 가능하고 유지 관리 가능한 코드를 만들 수 있음 > Liskov Substitution: 하위 유형은 프로그램의 정확성에 영향을 주지 않으면서 기본 유형으로 대체할 수 있어야 함 > Interface Segregation: 코드가 모든 것을 사용하지 않는 거대한 인터페이스에 종속되어서는 안 됨. 대신 패키지는 더 작은 특정 인터페이스를 포함하고 임포트할 수 있도록 허용해야 함 > Dependency Inversion: 상위 레벨 모듈이 하위 레벨 모듈에 종속되어서는 안 되며, 둘 다 추상화에 종속되어 보다 유연하고 분리된 시스템 설계를 촉진해야 함 > 그 예로 이름 짓기(Naming)를 들 수 있음: 좋은 이름에는 마법의 값이 없고, 구분이 명확하며, 설명적인 함수 이름과 이해하기 쉬운 변수를 표현함
의외성을 허용하지 않음 (Don’t allow surprises)
> 코드는 예상치 못한 결과를 만들어서는 안 됨. 이는 코드 원칙을 따르고 적절한 테스트를 작성함으로써 가능 > 좋은 코드는 예측 가능함 > 테스트는 코드의 명확성과 예측 가능성을 강화하고, 자신감을 줌. 우수한 자동화된 테스트를 통해 팀은 보이지 않는 부분을 깨뜨릴 염려 없이 코드를 변경할 수 있음 > 몇가지 테스트 유형 > 개별 컴포넌트 및 격리된 함수에 대한 단위 테스트 > 여러 컴포넌트 간의 상호 작용을 위한 통합 테스트 > 사용자 관점에서 전체 시스템의 기능을 평가하는 엔드투엔드 테스트 > 테스트는 간단해야 함. 실패한 테스트를 읽었을 때 무엇이 잘못되었는지 쉽게 파악할 수 있어야 됨 > 테스트하지 말아야 할 항목을 아는 것도 중요 > 예를 들어, 엔드투엔드 테스트의 수고가 프로그램의 실제 이점보다 크다면 테스트는 신중한 문서화, 모니터링 및 적절한 사람(예: 코드 소유자)에게 알림을 보내는 것으로 대체 > 또한 테스트는 프론트엔드 코드에서 특정 CSS 선택기를 테스트하는 것과 데이터 속성 또는 스크린샷 테스트만을 사용하는 것과 같이 코드 내의 구현 세부 사항을 테스트해서는 안 됨
자주 소통하기 (Communicate often)
> 훌륭한 시스템은 혼자서 만들어지지 않음. 훌륭한 엔지니어들은 설계 검토를 거치고, 피드백을 요청하고, 코드에 대한 초기 설계를 계속 반복했음 > 누구나 자신의 지식에는 다른 사람이 채워줄 수 있는 빈틈이 있음. 새로운 관점은 종종 코드를 더 명확하게 만들거나 이전에는 생각하지 못했던 새로운 접근 방식을 제공하는 데 도움이 될 수 있음 > 최고의 엔지니어들은 더 나은 최종 결과물을 얻기 위해 시간을 들여 함께 작업하는 것을 두려워하지 않고 소통과 협업을 중시 > 문서에 대한 빠른 검토를 위해 팀원에게 핑을 보내거나 중요한 풀 리퀘스트에 코드 검토자를 추가하는 것처럼 간단하게 할 수 있음
빠르게... 그리고 느리게 코딩하기 (Code fast… and slow)
> 내가 아는 최고의 엔지니어들은 프로젝트를 빠르게 완료하지만 코딩은 느리게 함 > 이상하게 들리죠? > 위의 모든 원칙과 습관은 코딩의 첫 번째 단계에 더 많은 시간을 추가함. 하지만 이러한 원칙과 습관을 통해 엔지니어는 프로젝트의 진행 상황을 한 단계씩 발전시킬 수 있음 > 표준을 사용하고, 제대로 테스트하고, 원칙을 사용하고, 자주 소통하는 데 시간을 할애함으로써 장기적으로 더 많은 시간을 절약할 수 있음 > 인턴과 주니어 엔지니어 시절에 제가 직접 경험했고, 다른 많은 엔지니어들도 마찬가지겠지만, 3보 전진을 서두르다 장애물에 부딪혀 5보 후퇴하게 될 수 있음
맹목적으로 규칙을 따르지 말 것 (Don’t follow rules blindly)
> 위의 '규칙'과 '원칙'은 단순한 가이드라인일 뿐. 모든 것이 가이드라인에 깔끔하게 잘 들어맞는 것은 아님 > 때로는 작성 중인 코드가 원 안에 들어가지 않는 정사각형일 수도 있지만 괜찮음 > 이 경우 코드가 특정 방식으로 작성된 이유를 문서화할 것 > 그렇지 않으면 미래의 여러분과 같은 누군가가 나중에 코드를 보고 "와, 그때는 내가 멍청했었지. 왜 이게 우리 표준을 따르지 않는 거지?"라고 생각할 수 있음 > 그러면 그들은 이전과 같은 결론에 도달하기 위해 20시간 동안 표준에 맞게 다시 코딩하는 데 시간을 소비할 것 > 소프트웨어 개발의 현실은 모든 코드가 깔끔하거나 규칙을 완벽하게 따를 수 없다는 것 > 하지만 일관성 있고, 깔끔하고, 이해하기 쉽고, 테스트할 수 있고, 가치 있는 코드는 존재할 수 있음 > 최고의 엔지니어에게서 발견한 또 다른 패턴들 > 적어도 한 가지 분야에 대한 깊은 도메인 지식을 가짐. 제가 기록했던 모든 엔지니어는 프론트엔드 인프라, 분산 시스템, 깔끔한 UI 등 특정 분야에 집중하여 전문가가 되었기 때문에 현재 해당 분야에서 최고의 자리에 올랐음 > 자신을 자주 그리고 적절하게 마케팅함. 이 엔지니어들은 눈에 잘 띄지 않는 곳에 숨어 있지 않았음. 팀원들과 함께 일하는 모든 사람들이 자신의 가치와 전문성을 알고 있었고, 이는 적절한 마케팅과 영향력 있는 프로젝트를 수행한 결과
규동 기본 재료
- 얇게 썬 소고기 (샤브샤브용 또는 우삼겹) 160g~200g - 양파 1/4개 ~ 1개 (채 썰기) - 쪽파 또는 대파 약간 (송송 썰기) - 계란 노른자 (선택 사항) - 밥
규동 소스 재료
간장 1~3 큰술
맛술 또는 미림 1~2 큰술
청주 1 큰술 (optional)
설탕 1 큰 술
쯔유 25ml (또는 시판 쯔유 대체 가능)
물 100~200ml
생강가루 약간
다진 마늘 1 작은 술 (optional)
조리법
- 팬에 식용유를 두르고 얇게 썬 소고기를 살짝 볶다가 채 썬 양파를 넣어 투명해질 때까지 볶는다. - 물, 간장, 설탕, 맛술, 쯔유, 청주, 생강가루 등을 섞어 만든 소스를 부어 센 불에서 졸이듯 끓인다. - 밥 위에 소고기와 양파 소스를 올리고, 송송 썬 쪽파와 계란 노른자를 얹어 마무리한다. - 노른자를 터뜨려 섞어 먹으면 부드럽고 감칠맛이 더욱 살아난다.
수란(온천달걀)을 집에서 정확하고 부드럽게 만드는 방법은 다음과 같다.
준비물
- 달걀 (상온, 1시간 이상 꺼내놓기) - 물 (끓는 물과 상온 물을 섞음) - 냄비와 뚜껑
만드는 방법
- 냄비에 물 7컵을 끓인다. - 물이 끓기 시작하면 불을 끄고 상온 물 3컵을 부으면 대략 74~75도 정도의 온도가 된다. - 상온에 둔 달걀을 깨지지 않게 조심스럽게 넣는다. - 냄비 뚜껑을 덮고 16분간 그대로 둔다(뚜껑 덮기 필수). - 시간이 지나면 달걀을 꺼내어 실온에서 5분간 식힌다.
Wired 창립 편집장 케빈 켈리(KK)가 올해 68세 생일날 블로그에 올린 훌륭한 조언들 간단 번역
Learn how to learn from those you disagree with, or even offend you. See if you can find the truth in what they believe.
당신이 동의하지 않거나, 심지어 당신을 기분 상하게 하는 사람에게서도 배우는 방법을 익히세요. 그들이 믿는 것에서 진실을 찾을 수 있는지 보세요.
Being enthusiastic is worth 25 IQ points.
열정적인 것은 IQ 25의 가치가 있습니다.
Always demand a deadline. A deadline weeds out the extraneous and the ordinary. It prevents you from trying to make it perfect, so you have to make it different. Different is better.
항상 데드라인을 요구하세요. 데드라인은 관계없거나 평범한 것들을 제거합니다. 데드라인이 "완벽하게" 만들지 못하게 방해해주니까, "다르게" 만들어야 합니다. 다른 것이 좋습니다.
Don’t be afraid to ask a question that may sound stupid because 99% of the time everyone else is thinking of the same question and is too embarrassed to ask it.
99%의 사람들은 같은 질문을 생각하니까, 멍청한 질문이라고 생각되는 것이라도 두려워하지 마세요.
Being able to listen well is a superpower. While listening to someone you love keep asking them “Is there more?”, until there is no more.
잘 들을 수 있는 것은 초능력입니다. 당신이 좋아하는 사람의 말을 들을 때, 그 사람이 더 말할 게 없을 때까지 "더 없어?"라고 물어보세요.
A worthy goal for a year is to learn enough about a subject so that you can’t believe how ignorant you were a year earlier.
한해동안 가치 있을 만한 목표는 "1년 전에는 어쩜 이걸 몰랐을까?" 싶은 주제에 대해 배우는 것입니다.
Gratitude will unlock all other virtues and is something you can get better at.
감사하는 것은 다른 모든 미덕의 시작이며, 당신이 더 나아지도록 합니다.
Treating a person to a meal never fails, and is so easy to do. It’s powerful with old friends and a great way to make new friends.
사람들에게 식사를 대접하는 것은 실행하기도 쉽고 절대 실패하지 않습니다. 오랜 친구에게도 강력하고 새로운 친구를 사귀기에도 좋은 방법입니다.
Don’t trust all-purpose glue.
다목적 접착제는 믿지 마세요
Reading to your children regularly will bond you together and kickstart their imaginations.
아이들에게 정기적으로 책을 읽어주면 당신과 끈끈해지고 상상력을 길러줄 수 있습니다.
Never use a credit card for credit. The only kind of credit, or debt, that is acceptable is debt to acquire something whose exchange value is extremely likely to increase, like in a home. The exchange value of most things diminishes or vanishes the moment you purchase them. Don’t be in debt to losers.
신용카드를 사용하지 마세요. 허용 가능한 유일한 부채는 '집'처럼 가격이 끝내는 오를만한 것을 사려고 할 때뿐입니다. 대부분 물건의 가치는 구입순간부터 감소하거나 사라집니다. 빚지지 마세요.
Pros are just amateurs who know how to gracefully recover from their mistakes.
전문가(Pro)는 실수로부터 우아하게 회복할 방법을 아는 아마추어일 뿐입니다.
Extraordinary claims should require extraordinary evidence to be believed.
특별한 주장은 믿을만한 특별한 증거를 요구하는 게 좋습니다.
Don’t be the smartest person in the room. Hangout with, and learn from, people smarter than yourself. Even better, find smart people who will disagree with you.
방에서 가장 똑똑한 사람이 되지 마세요. 자신보다 더 똑똑한 사람들과 만나고 배우세요. 더 나아가 당신에게 동의하지 않는 똑똑한 사람들을 찾으세요.
Rule of 3 in conversation. To get to the real reason, ask a person to go deeper than what they just said. Then again, and once more. The third time’s answer is close to the truth.
대화에서의 3의 법칙. 진짜 이유를 들으려면 누군가가 말한 것에 대해 좀 더 깊이 얘기해 달라고 하세요. 그리고 한번, 다시 한번 더. 세번째 대답이 진실에 가깝습니다.
Don’t be the best. Be the only.
최고가 되지 말고, 유일한 사람이 되세요.
Everyone is shy. Other people are waiting for you to introduce yourself to them, they are waiting for you to send them an email, they are waiting for you to ask them on a date. Go ahead.
모두 부끄러워합니다. 다른 사람들은 당신이 자신을 소개해주기를, 이메일을 보내주기를, 데이트를 요청해주기를 기다리고 있어요. 지금 실행하세요.
Don’t take it personally when someone turns you down. Assume they are like you: busy, occupied, distracted. Try again later. It’s amazing how often a second try works.
누군가 당신을 거절할 때 그걸 개인적으로 받아들이지 마세요. 그들도 당신과 같다고 생각하세요. 바쁘고, 뭔가에 점유되어 있고, 산만합니다. 나중에 다시 시도하세요. 두 번째 시도가 얼마나 잘 성공하는지 놀라실걸요.
The purpose of a habit is to remove that action from self-negotiation. You no longer expend energy deciding whether to do it. You just do it. Good habits can range from telling the truth, to flossing.
습관의 목적은 자기 자신과 타협하는 행동을 제거하는 것입니다. 할지 말지 고민하는 데 에너지를 쓰지 마세요. 그냥 하세요. 좋은 습관은 진실을 말하는 것부터 치실(flossing)을 하는 것까지 다양합니다.
Promptness is a sign of respect.
신속함은 존중의 표시입니다.
When you are young spend at least 6 months to one year living as poor as you can, owning as little as you possibly can, eating beans and rice in a tiny room or tent, to experience what your “worst” lifestyle might be. That way any time you have to risk something in the future you won’t be afraid of the worst case scenario.
젊었을 때 가능하다면 적어도 6개월에서 1년까지 아주 작은 방이나 텐트에서 콩과 쌀만 먹으며 빈곤하게 생활해보세요. "가장 나쁜" 생활이 어떨지 한번 경험해보세요. 그러면 미래에 뭔가 위험을 감수해야 할 때, 최악의 시나리오를 두려워하지 않을 것입니다.
Trust me: There is no “them”.
저를 믿으세요: "그들"이란 건 없습니다. (역주: 뭔가 내 의견에 반하는 '사람들'이 있는게 아니고 우린 모두 다른 의견을 가진 거라고 생각하고 번역했습니다.)
The more you are interested in others, the more interesting they find you. To be interesting, be interested.
다른 사람들에게 관심을 가질수록, 다른 사람들도 당신에게 흥미를 느끼게 됩니다. 흥미로워지려면 관심을 가지세요.
Optimize your generosity. No one on their deathbed has ever regretted giving too much away.
관대함을 최적화하세요. 죽을 때 너무 많이 나눠줬다고 후회하는 사람은 없습니다.
To make something good, just do it. To make something great, just re-do it, re-do it, re-do it. The secret to making fine things is in remaking them.
좋은 것을 만들려면 그냥 하세요. 위대한 것을 만들려면 다시 하고, 다시 하고, 다시 하세요. 훌륭한 것을 만드는 비결은 다시 만들어 보는 것입니다.
The Golden Rule will never fail you. It is the foundation of all other virtues.
황금률 (The Golden Rule, 다른 사람이 해 주었으면 하는 행위를 하라 [1])은 절대 실망하게 하지 않습니다. 그것은 다른 모든 미덕의 기초입니다.
If you are looking for something in your house, and you finally find it, when you’re done with it, don’t put it back where you found it. Put it back where you first looked for it.
집에서 뭔가를 찾고 있을 때 마침내 찾았다면 그 자리에 다시 두지 말고, 맨 처음 찾아봤던 곳에 두세요.
Saving money and investing money are both good habits. Small amounts of money invested regularly for many decades without deliberation is one path to wealth.
돈을 절약하고 투자하는것은 좋은 습관입니다. 아주 깊이 생각지 않고, 수십년간 소량의 돈을 정기적으로 투자하는 것은 부자가 되는 방법중 하나 입니다.
To make mistakes is human. To own your mistakes is divine. Nothing elevates a person higher than quickly admitting and taking personal responsibility for the mistakes you make and then fixing them fairly. If you mess up, fess up. It’s astounding how powerful this ownership is.
실수를 하는 것이 인간입니다. 당신이 실수한다는 것은 매우 신성한 것입니다. 자신이 저지른 실수에 대해 신속하게 인정하고, 공정하게 바로 잡는것 보다 사람을 훌륭하게 만들어주는 것은 없습니다. 뭔가를 망쳤다면, 털어 놓으세요. 이 "실수에 대한 소유권"이 얼마나 강력한지 놀랄겁니다.
Never get involved in a land war in Asia ( 아시아에서 내전에 관여하지 마십시오 = 분에 넘치는 일은 하지 마세요 ) ( 역주: 몽고메리/맥아더가 썻다고 알려진 표현 입니다. 주석에 링크 달겠습니다 [2] )
You can obsess about serving your customers/audience/clients, or you can obsess about beating the competition. Both work, but of the two, obsessing about your customers will take you further.
고객/청중/사용자에게 집중하거나, 경쟁에서 이기는 것에 집중할 수 있습니다. 두가지 다 동작하지만, 고객에 집중하는 것이 더 멀리 갈 수 있습니다.
Show up. Keep showing up. Somebody successful said: 99% of success is just showing up.
보여주세요. 뭔가를 계속 보여주세요. 성공한 사람이 말하길: 99%의 성공은 그저 보여주는 것입니다. ( 역주: Show up 은 뭔가를 만들어서 보여주는 것, 어딘가에 참석해서 보여주는 것 의 의미도 있지만 [3]의 글을 참고하시면 뭔가를 시작하는 것으로도 이해할수 있습니다. 헬스장에 등록하고 가는 것도 시작, 매일 글을 쓰는 것, 수업에 참석하는 것, 프로젝트에 참여하는 등 뭔가를 시작하는 것을 보여주는 것이라고 이해하면 될 것 같습니다.)
Separate the processes of creation from improving. You can’t write and edit, or sculpt and polish, or make and analyze at the same time. If you do, the editor stops the creator. While you invent, don’t select. While you sketch, don’t inspect. While you write the first draft, don’t reflect. At the start, the creator mind must be unleashed from judgement.
창작과 개선과정을 분리하세요. 쓰는것과 편집하는것, 조각하고 다듬는 것, 만들고 분석하는 것을 동시에 할수는 없습니다. 동시에 한다면 내 안의 편집자가 창작자를 막게 됩니다. 발명하는 동안 선택하지 마세요. 스케치 하는동안 검사하지 마세요. 초안 작성중에는 반영하지 마세요. 처음에는 창작자의 마음이 판단으로부터 해방되어야 합니다.
If you are not falling down occasionally, you are just coasting.
당신이 가끔 쓰러지지 않는다면, 설렁 설렁하고 있는 것입니다.
Perhaps the most counter-intuitive truth of the universe is that the more you give to others, the more you’ll get. Understanding this is the beginning of wisdom.
아마도 우주의 진리중 가장 반직관적인 것은 "남에게 더 많이 줄수록, 더 많이 얻게 된다는 것" 입니다. 이것을 이해하는 것이 지혜의 시작입니다.
Friends are better than money. Almost anything money can do, friends can do better. In so many ways a friend with a boat is better than owning a boat.
친구가 돈보다 낫습니다. 돈이 할 수 있는 거의 모든 것은, 대부분 친구들이 더 잘합니다. 여러가지면에서 배를 소유하는 것보다, 배를 가진 친구가 낫습니다.
This is true: It’s hard to cheat an honest man.
분명한 사실: 정직한 사람을 속이는 것은 어렵습니다.
When an object is lost, 95% of the time it is hiding within arm’s reach of where it was last seen. Search in all possible locations in that radius and you’ll find it.
물건을 잃어버렸을 때, 95%는 마지막으로 본 곳에서 팔 닿는곳에 있습니다. 해당 반경내에서 모든 곳을 뒤져보면 찾을수 있습니다.
You are what you do. Not what you say, not what you believe, not how you vote, but what you spend your time on.
당신은 당신이 하는 일로 표현됩니다. 당신이 하는 말이 아니라, 믿는 것이 아니라, 투표하는 방식이 아니라, 당신이 시간을 쓰는 그 것이 당신을 말해줍니다.
If you lose or forget to bring a cable, adapter or charger, check with your hotel. Most hotels now have a drawer full of cables, adapters and chargers others have left behind, and probably have the one you are missing. You can often claim it after borrowing it.
케이블,어댑터,충전기를 잃어버리거나 안 가져왔을 때 호텔에 문의하세요. 대부분의 호텔은 누군가 놓고간 케이블, 어댑터 및 충전기로 가득찬 서랍을 가지고 있을겁니다. 당신이 잃어버린게 거기 있을지도 몰라요.
Hatred is a curse that does not affect the hated. It only poisons the hater. Release a grudge as if it was a poison.
증오는 미움 받는 사람(the hated)에게는 영향을 주지 않는 저주입니다. 증오하는 본인(the hater)만 아프게 하는 독약과 같습니다. 독약인 것 처럼 원한을 놓아버리세요.
There is no limit on better. Talent is distributed unfairly, but there is no limit on how much we can improve what we start with.
더 잘 하는 것 (better) 에는 제한이 없습니다. 재능은 불공평하게 분배되지만, 우리가 가지고 시작한 것을 얼마나 향상시킬 수 있는지는 제한이 없습니다.
Be prepared: When you are 90% done any large project (a house, a film, an event, an app) the rest of the myriad details will take a second 90% to complete.
준비하세요: 큰 프로젝트 (집, 영화, 이벤트, 앱)를 90% 완료하면, 무수한 세부사항의 나머지를 완료하는데 두번째 90%가 걸립니다.
When you die you take absolutely nothing with you except your reputation.
당신이 죽을 때 평판외에는 아무것도 가져가지 못합니다.
Before you are old, attend as many funerals as you can bear, and listen. Nobody talks about the departed’s achievements. The only thing people will remember is what kind of person you were while you were achieving.
나이가 들기전에 가능한 많은 장례식에 참여하고 들으세요. 떠난 사람의 업적에 대해 얘기하는 사람은 없습니다. 사람들이 유일하게 기억하는 것은 당신이 업적을 달성하는 동안 어떤 사람이었나 하는 것 뿐입니다.
For every dollar you spend purchasing something substantial, expect to pay a dollar in repairs, maintenance, or disposal by the end of its life.
뭔가 비용을 들여서 큰 것을 구매할 때마다, 그것의 수명이 다할때까지 수리, 유지보수, 폐기하는데에도 같은 비용이 들어갈 것을 예상하세요.
Anything real begins with the fiction of what could be. Imagination is therefore the most potent force in the universe, and a skill you can get better at. It’s the one skill in life that benefits from ignoring what everyone else knows.
현실은 있을법한 허구에서 시작합니다. 그러므로 상상력은 우주에서 가장 강력한 힘이며, 당신이 더 향상시킬수 있는 기술입니다. 그건 다른 사람들이 모두 다 아는 것을 무시함으로써 혜택을 얻는 유일한 기술 입니다.
When crisis and disaster strike, don’t waste them. No problems, no progress.
위기와 재난이 닥쳤을때, 그걸 낭비하지 마세요. 문제가 없다면 진보도 없습니다.
On vacation go to the most remote place on your itinerary first, bypassing the cities. You’ll maximize the shock of otherness in the remote, and then later you’ll welcome the familiar comforts of a city on the way back.
휴가를 갈 땐, 도시를 벗어나 일정상 가장 먼곳으로 먼저 가세요. 멀리 떨어진 곳에서 타인이 되어보는 충격을 최대화 하면, 돌아올 때 도시의 친숙한 편안함을 즐기게 될겁니다.
When you get an invitation to do something in the future, ask yourself: would you accept this if it was scheduled for tomorrow? Not too many promises will pass that immediacy filter.
미래에 뭔가 해달라는 초대를 받았을 때 자신에게 물어보세요: 만약 그게 내일로 예정된 것이라면 수락할 것인가요? 많은 약속들이 이 빠른 필터를 통과하지 못합니다.
Don’t say anything about someone in email you would not be comfortable saying to them directly, because eventually they will read it.
누군가에게 직접 말하는 게 불편한 내용은 이메일에서도 언급하지 마세요. 그 사람은 결국 그걸 읽게 될테니까요.
If you desperately need a job, you are just another problem for a boss; if you can solve many of the problems the boss has right now, you are hired. To be hired, think like your boss.
당신이 정말 직업이 필요한거라면, 보스에겐 당신은 또 다른 문제일 뿐입니다. 당신이 보스가 지금 당면한 문제들을 해결해 줄 수 있다면 당신을 뽑을 겁니다. 채용되려면 당신의 보스처럼 생각하세요.
Art is in what you leave out.
생략한 것이 예술이 됩니다.
Acquiring things will rarely bring you deep satisfaction. But acquiring experiences will.
물건을 얻는 것은 가끔 깊은 만족감을 주기도 합니다. 하지만 경험을 얻는 것은 항상 깊은 만족감을 줍니다.
Rule of 7 in research. You can find out anything if you are willing to go seven levels. If the first source you ask doesn’t know, ask them who you should ask next, and so on down the line. If you are willing to go to the 7th source, you’ll almost always get your answer.
조사할 때 7의 법칙. 7단계를 갈 수 있다면 무엇이든 찾을 수 있습니다. 첫번째 물어본 사람이 모르면, 그 사람에게 다음으로 누구한테 물어야 할지를 물어보고 계속 하세요. 7번째 까지 가려고 할때면 거의 항상 답을 얻을 것입니다.
How to apologize: Quickly, specifically, sincerely.
사과 하는법 : 신속하게, 구체적으로, 진심을 담아.
Don’t ever respond to a solicitation or a proposal on the phone. The urgency is a disguise.
전화로 오는 요청이나 제안에 응답하지 마세요. 긴급함은 위장입니다.
When someone is nasty, rude, hateful, or mean with you, pretend they have a disease. That makes it easier to have empathy toward them which can soften the conflict.
누군가가 당신에게 불쾌하고 무례하거나 증오하고 심술맞게 굴때 그들이 병에 걸렸다고 생각하세요. 그들에게 공감하는걸 쉽게 만들어서, 갈등을 완화시키는데 도움이 됩니다.
Eliminating clutter makes room for your true treasures.
주변의 어지러운 것들을 제거하면, 진정한 보물을 위한 공간이 만들어집니다.
You really don’t want to be famous. Read the biography of any famous person.
당신은 진짜로 유명해지고 싶지는 않을꺼에요. 누구든 유명한 사람의 전기를 한번 읽어보세요.
Experience is overrated. When hiring, hire for aptitude, train for skills. Most really amazing or great things are done by people doing them for the first time.
경험은 과대평가 되고 있습니다. 누군가를 고용할 때, 적성을 보고 뽑고, 기술은 가르치세요. 사람들이 하는 가장 놀랍거나 위대한 일들은 보통 처음 해보는 것들입니다.
A vacation + a disaster = an adventure.
휴가 + 재난 = 모험
Buying tools: Start by buying the absolute cheapest tools you can find. Upgrade the ones you use a lot. If you wind up using some tool for a job, buy the very best you can afford.
도구를 살때: 가장 싼 도구를 사서 시작하세요. 많이 쓰는 도구를 업그레이드 하세요. 만약 어떤 도구를 사용하여 일을 마무리했을 때, 당신이 감당할 수 있는 최상의 것을 사세요.
Learn how to take a 20-minute power nap without embarrassment.
부끄러워 하지 않고 20분동안 Power Nap(에너지를 보충하는 짧은 낮잠) 자는 법을 익히세요.
Following your bliss is a recipe for paralysis if you don’t know what you are passionate about. A better motto for most youth is “master something, anything”. Through mastery of one thing, you can drift towards extensions of that mastery that bring you more joy, and eventually discover where your bliss is.
어떤 것에 열정을 가지고 있는지 모른 체 단순히 행복만을 좇다보면 무기력해지게 됩니다. 많은 젊은이들을 위한 좀 더 좋은 모토는 "뭔가를 마스터하세요. 어떤것이라도" 입니다. 한 가지 숙달하는 것을 통해서 더 큰 기쁨을 주는 다른 것으로 확장해 갈 수 있고, 결국엔 행복이 어디에 있는지 알게 됩니다.
I’m positive that in 100 years much of what I take to be true today will be proved to be wrong, maybe even embarrassingly wrong, and I try really hard to identify what it is that I am wrong about today.
나는 100년안에 오늘 내가 진실이라고 믿는 것의 대부분이 틀렸다고 밝혀지거나, 난처할 정도로 잘못한 것이 될 것임을 확신하고, 오늘 내가 틀린것이 무엇인지 확인하기 위해 열심히 노력합니다.
Over the long term, the future is decided by optimists. To be an optimist you don’t have to ignore all the many problems we create; you just have to imagine improving our capacity to solve problems.
장기적으로 미래는 낙관론자 들에 의해 결정됩니다. 낙관론자가 되기 위해 우리가 만드는 많은 문제를 무시할 필요는 없습니다. 문제를 해결하는 능력을 향상시키도록 계속 꿈꿔야 합니다.
The universe is conspiring behind your back to make you a success. This will be much easier to do if you embrace this pronoia.
온 우주가 당신을 성공시키기 위해 뒤에서 협력하고 있습니다. 이 낙관적 믿음(Pronoia)을 받아들이면, 훨씬 쉬워질겁니다.
왜 잘못된 일이 벌어지는가 Scale AI CEO Alexandr Wang의 메모
Scale AI의 CEO, Alexandr Wang이 2019년 Scale AI 팀에게 보낸 메모 중 일부
정보 압축: 왜 일이 잘못되는가?
- 정보 압축이란 무엇인가?
- 현실 세계의 복잡한 상황을 인간이 이해할 수 있도록 간단한 언어나 그림으로 전달하는 과정이 바로 ‘정보 압축’임.
- 하지만 이 과정에서 대부분의 뉘앙스와 중요한 맥락이 사라짐.
- 왜 정보 압축이 문제를 일으키는가?
- 압축 과정에서 필연적으로 정보 손실이 발생, 결과적으로 왜곡된 메시지가 전달됨.
- 상대방은 실제 상황과는 거리가 먼 이미지를 머릿속에 그리게 되고, 그 기반 위에서 문제를 해결하려다 엉뚱한 결과가 나옴.
- 대부분의 조직 내 의사소통 실패와 비효율성의 근본 원인은 이 정보 압축의 한계에 있음.
- 조직 규모와 정보 압축의 상관관계
- 작은 스타트업(5명 미만) 은 모든 구성원이 맥락을 공유하고, 사전 지식(prior)이 비슷해 압축된 정보만으로도 충분히 소통이 가능함.
- 조직이 커질수록 부서 간 벽(사일로)이 생기고, 공유 컨텍스트와 사전 지식이 약화되어 정보 압축의 부작용이 커짐.
- 결과적으로 불필요한 인계, 오해, 비효율적인 결과물이 늘어남.
- 정보 압축 문제의 대표적 사례
- 고객의 요구사항: 고객이 자신의 문제를 압축해서 전달하지만, 실제로 원하는 것과는 거의 일치하지 않음.
- 비개발자→개발자 요청: 비개발자가 개발자에게 일을 요청할 때, 실제 난이도와 맥락이 전달되지 않아 엉뚱한 결과가 나옴.
- 실제 문제와 무관한 솔루션: 표면적으로는 문제를 해결하는 것 같지만, 실질적 개선 효과가 없는 결과물이 나옴.
- 정보 압축의 해법
- 인계 최소화, 직접 경험: 문제를 직접 경험하고, 인계를 줄이는 것이 최선.(예: 도그푸딩, 다양한 역할 직접 경험)
- 강한 조직 문화: 사전 지식(prior)과 맥락을 조직 내에서 공유해야 함.
- 고객과 코드의 거리 최소화: 고객 문제와 실제 개발이 긴밀하게 연결되어야 함.
- 호기심과 추가 질문: 문제를 해결하는 사람이 끊임없이 질문하고, 맥락을 파악하려 노력해야 함.
- 고객 출신 인재 채용: 실제 문제를 잘 아는 사람이 팀에 있으면 맥락 손실이 줄어듦.
- 핵심 요약
- 정보 압축은 불가피하지만, 항상 불완전하다.
- 조직이 커질수록 정보 압축의 부작용이 커진다.
- 최고의 해법은 '압축'에 의존하지 않는 조직 구조와 문화, 그리고 직접 경험이다.
왜 사실만으로는 생각이 바뀌지 않는가 — "구조가 답이다" (vasily.cc)
- 갈릴레오의 지동설 논쟁 사례처럼, 사회적 권력과 신념 체계는 단순한 '사실'만으로 바뀌지 않음
- 교회·권력·이념은 성경, 우주관, 예술, 사회 규범 등 서사와 구조적 연결을 통해 현실을 설명하고 정당화함
- 신념 구조(그래프)는 핵심 노드와 연결(엣지)로 구성되어 있어, 한 부분만 흔들려도 전체 세계관이 동요함
- 논쟁의 핵심은 사실이 아니라 각자의 구조적 틀(그래프)에서 노드나 연결고리를 공격·방어하는 심리적/사회적 작동임
- 구조적 복원력, 내부 결속, 감정적 공명이 강할수록 신념은 유지되며, 팩트는 구조적 틀 안에 녹아들 때 비로소 영향력 가짐
사실이 아니라 구조가 신념을 결정
Galileo Galilei가 지동설을 제기했을 때 교회는 단순한 무지함 또는 미신 때문만이 아니라, 사회 질서를 유지하는 신념 체계를 수호하기 위해 저항함
- 지구중심 우주관이 신앙·사회 질서의 핵심 구조로 작동했기 때문
이 신념 체계는 이야기, 상징, 교리가 유기적으로 연결되어 권위와 질서를 정당화함
성경 구절들은 지구 중심 우주관을 뒷받침하며, 인간이 우주의 중심이라는 사회적·도덕적 서열구조와 연결됨
이러한 구조는 단순한 논쟁이 아닌, 전체 세계관, 예배 달력, 성당 건축, 예술, 일상의 규범 등에 강하게 반영됨 한 개념에 도전한다는 것은, 하나의 아이디어만이 아니라 그 전체 네트워크와 권위를 건드리는 행위임. 핵심 노드(지구중심설)를 건드리는 순간 전체 구조가 위태로워짐
신념 구조(그래프)의 예시
- 현대에도 신념 구조는 개념(노드)과 연결(엣지) 로 이루어진 '그래프'로 설명 가능
- 예시로, "성장 우선 자본주의" 와 "생태 지속 가능성" 구조는 각각 다른 논리와 연결망을 가짐
- Growth-First Capitalism(성장우선 자본주의) 혁신→이익→주주 수익→구매력→경쟁→혁신... 각 연결이 상호 보강하여 강화하는 체계, 내부 일관성·복원력 강함
- Ecological Sustainability(생태 지속가능성) 기후위기→정책변화→재생에너지→배출감소→커뮤니티 회복력 연결을 통한 선순환 구조로 인간 복지와 행성 건강의 연결, 집단 행동, 회복 탄력성을 중시 이 그래프의 노드 연결(엣지) 은 심리적 힘으로 지속적으로 강화됨 인지 부조화 상태에 처하면 인간의 뇌는 기존 세계관을 유지하기 위해 동기화 추론과 사후 합리화 과정을 사용 이 때문에 신념 구조가 매우 견고하고 변화에 저항적임
구조적 공격—노드·엣지의 흔들림
- 경쟁하는 신념 체계 간의 진짜 '전쟁'은 논리적 주장이 아니라 서로의 구조를 바꾸려는 시도임
- 상대의 핵심 노드를 무너뜨리거나, 개념 사이의 연결을 약화시키거나, 상대의 매력적인 요소를 흡수함으로써 구조에 영향을 주려 함
- 이로써 단순히 의견 교환을 넘어서 신념 구조 자체가 변형되는 과정이 일어남
- 핵심 노드 공격(Node Attack) : 한 개의 핵심 노드에 대한 집중적인 공격이 신념 체계 전체를 약화시킬 수 있음
- 예: "기후 변화 위협"이라는 노드가 공격당하면, 정책 변화 동기가 약화되어 전체 시스템이 불안정해짐. 공격이 성공하면, 신념 체계의 주요 피드백 루프가 붕괴되며 구성 자체가 해체 위험에 놓임
- 엣지 공격(Edge Attack) : 아이디어 사이의 연결(엣지) 을 공격해 신념 체계의 논리를 우회적으로 만들고 설득력을 약화 예: "주주 이익"이 실질적인 구매력 증가로 이어지는지를 비판하면, 자본주의 체계의 광범위한 번영 주장이 약화됨 엣지 공격이 지속되면, 시스템의 사회적 정당성이 무너지고 대안적 구조에 더 쉽게 흡수됨
- 이 외에도 신념 체계는 경쟁하는 구조의 강점을 흡수하거나, 틈새를 통해 진화하거나, 자가 교정을 통해 회복 탄력성을 얻는 다양한 전략을 구사함
인간 심리와 신념 구조
- 신념 시스템(밈, 이데올로기 등)은 사람들의 뇌 구조 안에서만 실질적 작동이 일어남
- 신념 구조는 인간의 인지 아키텍처에 의해 유지되고, 보호받으며, 때로는 '개인 정체성'과 깊이 얽혀서 도전 자체를 개인 공격처럼 느끼게 함
- 단순 논리가 아니라, 인지 부조화·동기화 추론 등 뇌의 자동화된 심리기제에 의해 안정적으로 유지
- 뇌는 위협적 정보를 무의식적으로 거르고, 모순되는 증거에 직면할 때 인지 부조화를 해소하기 위해 합리화를 시도함
- 이는 신념 구조가 외부 공격에 매우 견고하게 버티는 이유
구조적 경쟁과 실제 사례
- 오늘날의 사회적 논쟁은 단순한 사실이 아니라, 서로 양립할 수 없는 신념 템플릿 간의 충돌임
- 각 진영은 자신만의 연결 구조, 핵심 아이디어, 그리고 이를 뒷받침하는 논리 체계를 갖고 있고, 상대의 논리 자체를 쉽사리 수용하지 못함
- 한 집단의 신념 네트워크가 단단하고 연결이 강할수록 외부 공격에 대한 저항력과 영향력이 커짐
- 반면, 내부적으로 분열되거나 연결이 약화되면 집단 영향력이 급격히 약해짐
- 이 때문에 적대적 세력이 내부 분열을 유발하면 전체 권력 균형에도 영향을 미침
조직적 허위 행동(coordinated inauthentic behavior)
- 여론 조작을 위해 가짜 계정 여러 개가 협업하는 소셜미디어 작전
- 단순한 허위 정보 전파가 아니라, 신념 그래프의 핵심 연결을 체계적으로 약화시키는 전략
- 예를 들어 러시아 IRA는 미국 내 인종 갈등을 심화시키기 위해, 동시에 서로 반대되는 목소리를 증폭시켜 사회적 연결 구조를 흔듦 BLM-반BLM, 백신 찬반, 기후 논쟁 등 분열 유도—핵심 연결을 약화해 전체 구조를 불안정하게 만듦
- 이러한 대규모 네트워크 공격은 한 방향의 허위 정보보다, 구조적 연결 약화에 더 중점을 둠
- Cambridge Analytica 사례처럼, 마이크로 타겟팅 기술과 개인화 메시지는 신념 구조 내 취약 노드 및 엣지를 정밀하게 겨냥할 수 있음
- 최근에는 LLM(대규모 언어 모델)로 인해 이런 구조적 조작의 규모와 민첩성이 폭발적으로 증가함
우리의 신념 구조를 어떻게 지킬 것인가
- 팩트체크, 반박, 진실만으로는 한계가 있음. '구조'와 '내적 결속', '감정적 공감력'을 강화해야만 신념 시스템이 복원력 갖춤
- 진실은 사람들이 머무를 수 있는 구조적 틀 속에 있어야 지속적으로 살아남고 퍼짐
- 조작과 분열을 막으려면, 내구성 높은 서사, 자기 신념 체계의 구조적 일관성 및 회복 탄력성 강화, 템플릿 간의 연결 다리 구축, 감정적으로도 공명하는 내러티브 형성이 필요함
- 신념의 메커니즘을 이해하면 누구나 수동적 대상이 아니라 능동적 구조 설계자가 될 수 있음. 견고하고 적응력 있으며, 더 개방적인 새로운 신념 체계 설계가 가능함
- 진실은 사람들이 머무를 수 있는 구조적 틀 속에 있어야 지속적으로 살아남고 퍼짐
결론
- 우리는 단순한 정보 소비자가 아니라, 자신의 신념 구조를 설계하는 건축가가 될 수 있음
- 구조적 이해를 바탕으로, 복원력 있고 연결적인 신념 체계 설계가 문화전쟁·여론 조작 시대의 진정한 대응책임
게임 엔진 없이 비디오 게임 개발하기 (2025) (noelberry.ca)
- 상용 게임 엔진 없이도 충분히 쉽고 재미있게 게임 개발을 할 수 있음
- 대형 엔진의 대부분 기능이 필요 없고, 직접 도구를 작성하면 유연성과 개발 효율성이 커짐
- 현대 C# 및 오픈소스 라이브러리를 활용하면 팀 규모와 관계없이 충분한 개발 환경 제공 가능함
- FMOD, SDL3, Dear ImGui 같은 라이브러리와 자체 툴 결합으로 필요에 맞는 파이프라인을 구성할 수 있음
- 크로스플랫폼 개발, 유지보수, 이식성 측면에서 직접 구축한 경량화 프레임워크가 매우 유리함
서문: 20년차 게임 개발자의 소회
- 2025년에도 상용 게임 엔진 없이 비디오 게임을 개발 중임
- 주변에서 상용 엔진을 쓰지 않는 점에 놀라는 경우가 많음
- Unity나 Unreal 같은 대형 엔진의 기본 기능들은 직접 구현하는 것에 비해 만족스럽지 않고, 결국 많은 부분을 다시 만들게 됨
- 상용 엔진을 활용할 때 잦은 비즈니스 정책 변경이나 업데이트로 인한 문제에 노출됨
- 개별 프로젝트에 딱 맞는 작은 도구를 직접 만드는 것이 더 효율적이고, 장기적으로도 유지보수가 쉬움
게임 개발에 필요한 프로그래밍 언어 선택
- 오랜 기간 C# 을 주력 언어로 사용함
- 현대의 C#은 과거에 비해 성능과 문법, 개발 경험이 많이 개선됨
- dotnet watch 같은 핫리로드 기능이 있어, 실시간 코드 수정 및 테스트에 매우 편리함
- 비개발자도 쉽게 접근해 팀원 간 역할 분담과 협업 효율성이 높음
- 내장된 reflection 기능으로 에디터나 툴 제작에 강점이 있음
크로스플랫폼 라이브러리와 렌더링·입력 구현
- SDL3를 사용하여 윈도우, 렌더링, 컨트롤러, 크로스플랫폼 지원 등 모든 기본 기능을 구현함
- SDL3의 GPU abstraction으로 DirectX, Vulkan, Metal 등 다양한 환경 지원이 쉬워짐
- SDL 상단에 직접 작성한 C# 레이어(예: Foster)를 공용 유틸리티로 활용함
- FMOD를 마지막 남은 상용 오디오 툴로 사용, 이외에는 오픈소스 기반 파이프라인 구축
- 기존에는 OpenGL/DirectX 직접 구현도 경험, SDL의 안정성이 상당한 이점임
에셋(Assets) 처리 방법
- 직접 엔진을 사용할 경우, 게임에서 필요한 파일만 간단히 로딩
- 픽셀 아트 게임처럼 소규모 에셋의 경우 모든 파일을 초기화 때 한 번에 적재함
- 대형 프로젝트에서는 필요한 에셋만 요청 시 로딩하고, 장면 전환시 메모리 해제 방식 적용
- 컨버팅이 필요한 경우 컴파일 시 자동 처리 스크립트 작성만으로 충분함
레벨 에디터 및 UI 툴
- LDtk, Tiled, Trenchbroom 등 오픈소스 레벨 에디터와 데이터 연동이 쉬움
- 대체로 프로젝트마다 맞춤형 에디터를 직접 구현함
- UI 본체는 직접 작성하지 않고, Dear ImGui의 즉시모드 GUI를 적극 활용함
- C#의 reflection과 ImGui 조합으로 게임 오브젝트 상태를 실시간 시각화 가능
- 필요시 목적에 적합한 외부 툴과 자체 툴을 혼용함
크로스플랫폼 및 콘솔 이식성
- 과거엔 콘솔 이식 문제로 C++ 선택 필요성이 컸으나, C# Native-AOT 등장으로 해결됨
- FNA 등 오픈소스 프레임워크에서 적극적으로 콘솔 지원 확장 중임
- SDL3가 지원하는 범용 추상화 레이어를 활용하면 대부분 시스템에서 동일한 코드 베이스 운용 가능함
개발 환경: Linux 중심의 오픈 생태계
- 주력 개발 플랫폼을 Linux로 전환, 오픈소스 툴체인과의 궁합이 매우 좋음
- 특정 상용 소프트웨어와의 연결이 남아 있지만(예: vscode, github), 오픈소스 생태계가 넓어질수록 지원도 확대됨
- 개인적으로 Steam Deck 등 다양한 Linux 기반 플랫폼에서 동일한 작업 환경 구성 중임
추가 Q&A 및 사례
- Godot 사용 문의: 오픈소스 엔진 중심 개발 니즈가 있다면 Godot 추천, 그 외에는 커스텀 툴 선호함
- 3D 작업: 대형 엔진 장점이 있으나, 소규모 특화된 프로젝트엔 맞춤 프레임워크로 충분함 고성능 기술 요구: 요구 수준에 따라 Unreal 등 대형 엔진 사용도 무방함 팀 단위 엔진 변경: 소규모/단독 개발에 적합, 중대형 스튜디오도 장기 리스크 회피 이유로 커스텀 엔진 전환 사례 증가 중임 에셋 워크플로우: Aseprite 파일을 빌트인 태그와 타이밍을 활용해 자동으로 애니메이션 변환 가능함
결론
- 상용 게임 엔진 없이 게임 제작을 하는 것은 취향과 작업 방식에 달린 선택임
- 필요와 재미를 최우선으로 자신에게 적합한 방법을 선택하면 됨
2025년 셀프 호스팅 가이드
https://kiranet.org/self-hosting-like-its-2025/
데이터 수집 중심의 중앙화된 서비스에 대한 대안으로 셀프 호스팅이 최근 인기를 얻고 있음
다양한 도구와 앱을 실험후 1년 이상 안정적으로 운영 중인 경험을 바탕으로 유용했던 도구들을 소개
- 컨테이너 런타임, 웹 기반 관리도구, 리버스 프록시와 VPN, 그외 셀프호스팅 도구들 추천글 모음
특정 솔루션의 우열을 가리기 위한 글이 아니며, 다양한 문제에는 다양한 해법이 존재한다는 점을 강조
컨테이너 런타임
- 요즘은 컨테이너가 호스팅의 기본이 되었고, 전통적인 방식은 점점 보기 어려워짐
- 이는 홈서버 사용자(homelabber) 에게는 매우 긍정적인 흐름이며, 컨테이너는 소프트웨어 배포를 간편하게 만들고 가상머신보다 효율적인 성능을 제공함
- 대부분은 Docker를 사용하지만, 이 글에서는 홈 환경에서 사용할 수 있는 다양한 대안 런타임을 소개함
- Docker
- 가장 널리 사용되는 원조 컨테이너 런타임
- 풍부한 문서와 커뮤니티 덕분에 IT에 익숙하지 않아도 GitHub에서 docker-compose.yml을 복사해 실행해볼 수 있음
- 단, 보안 관련 설정은 별도로 고려할 필요 있음
- Podman
- 루트리스(rootless) 구조와 Docker CLI 호환성 덕분에 주목받고 있는 차세대 컨테이너 런타임
- 데몬 없이 작동하기 때문에 보안을 중시하거나, 관련 기술을 학습하려는 사람에게 적합
- 대부분의 Docker 명령어를 그대로 사용할 수 있고, docker 명령어와 호환되는 alias 제공으로 전환이 쉬움
- 초기에는 진입 장벽이 있지만, 문서와 커뮤니티가 발전하면서 점점 접근성이 향상됨
- 추가로, Podman Quadlets를 통해 docker compose 대신 systemd 기반 선언적 컨테이너 관리도 가능함
- Kubernetes
- 호기심 많고 실험적인 홈서버 사용자에게는 도전 욕구를 자극하는 고급 툴
- 수많은 인스턴스를 우아하게 관리할 수 있는 오케스트레이션 툴로서, 엔터프라이즈 수준의 관리 경험 제공
- 단, 기능이 매우 많고 복잡하기 때문에 대부분 사용자에겐 과함
- 홈 환경에서는 학습 자체가 주된 목적이며, 실제 활용보다는 기술 이해에 초점이 맞춰짐
- Docker
웹 기반 컨테이너 관리 도구
- 어떤 사용자들은 로컬 디스크에 compose 파일들을 모아두고 관리하길 선호하지만, 매번 SSH로 서버에 접속해 로그를 확인해야 하는 번거로움이 있음
- 이를 대신해 웹 기반 컨테이너 관리 도구를 사용하면 훨씬 더 편리하게 작업 가능함
- Portainer
- Docker, Kubernetes, Podman과 모두 호환되는 가장 안정적인 웹 UI 관리 도구
- 홈서버부터 기업 환경까지 널리 쓰이며, 실전 활용을 통한 학습에도 매우 유익함
- 오픈소스 커뮤니티 버전과 추가 기능이 포함된 엔터프라이즈 버전 존재 (3개 라이선스는 무료 제공)
- 직관적인 인터페이스와 다양한 기능 덕분에 컨테이너 관리에 매우 유리함
- Dockge
- Uptime Kuma 개발자가 만든 신생 웹 기반 Docker Compose 관리 도구
- 아직 Portainer만큼 성숙하지는 않았지만, 매우 간단하고 직관적인 UI가 강점
- 개발자가 GitHub 이슈에 신속하게 대응하고, 정기적인 업데이트가 이뤄짐
- 가볍고 미니멀한 도구를 선호하는 사용자에게 적합
- Portainer
리버스 프록시와 VPN
- 외부에서도 셀프 호스팅한 애플리케이션에 접근하려면 두 가지 주요 방법이 있음:
- 서비스를 인터넷에 직접 노출
- VPN을 통해 내부 네트워크에 접근
- VPN은 보안상 더 안전하지만, 인터넷 노출 방식도 설정만 잘 하면 충분히 유용함
- Pangolin
- VPN과 리버스 프록시를 하나로 결합한 혁신적인 솔루션
- 마치 셀프 호스팅용 Cloudflare 같은 역할
- VPS 등에 인그레스 서버만 설치하면, 다양한 환경에서 VPN 클라이언트로 간편하게 연결 가능
- CrowdSec 연동, 기본적인 SSO 기능까지 탑재됨
- 작성자가 이 글을 쓰게 된 계기일 정도로 인상 깊은 툴이며, 시간이 지나면 기존 솔루션의 표준 대안이 될 가능성 있음
- Nginx Proxy Manager (NPM)
- TCP/UDP/HTTP(S) 프록시를 웹 UI로 쉽게 설정할 수 있는 Nginx 프론트엔드
- 많은 사용자들이 활용 중이지만, 작성자는 일부 기능(예: 비밀번호 보호)이 불안정하다고 평가
- 처음 접했던 툴로써 좋은 인상은 아니었지만, 작동 시에는 제 역할을 충실히 수행함
- Caddy
- 단순한 설정 파일(Caddyfile) 로 프록시 설정부터 HTTPS 인증서 발급까지 자동 처리
- 웹 UI가 없기 때문에 초보자에게는 추천하지 않지만, UNIX 철학을 좋아하는 사용자에겐 최고의 선택
- Let’s Encrypt를 기본 지원하며, 복잡한 구성이 필요 없는 것이 장점
- NetBird
Tailscale에 익숙하다면 바로 적응할 수 있는 VPN 솔루션
- WireGuard 기반 네트워크를 자동으로 구성하며, 복잡한 설정을 줄여줌
- 클라우드 무료 티어 또는 자가 호스팅 모두 가능하여 유연성 있음
- Pangolin
상태 모니터링 및 알림 도구
- Uptime Kuma - Zabbix나 Grafana 같은 무거운 스택 없이도 간편하게 서비스 상태 모니터링 가능 - 단 한 번의 배포로 다양한 채널을 통한 알림 설정 가능 - 셀프 호스팅 시스템의 가용성 체크에 탁월함 - Gotify - 간단한 HTTP 요청으로 푸시 알림 전송이 가능한 알림 서버 - 모바일 앱 설치 후 알림 수신 가능하며, Uptime Kuma 등과의 통합도 가능 - 다양한 셀프 호스팅 툴과 함께 사용할 수 있어 실용적임
셀프 호스팅 앱 검색을 위한 추가 자료
- 다양한 셀프 호스팅 애플리케이션을 찾을 수 있는 유용한 자료 모음임 - Awesome-Selfhosted - GitHub에서 제공하는 방대한 소프트웨어 리스트 - 다소 정리되지 않았고, 개발이 중단된 프로젝트도 일부 포함되어 있음 - Selfh.st - 작성자가 가장 좋아하는 자료 출처임 - 틈새 애플리케이션 추천 뉴스레터와, 정렬 기능이 있는 대형 애플리케이션 디렉토리를 제공함 - 매우 유용한 사이트임 - awesome-docker-compose - 즉시 실행 가능한 Docker Compose 파일 모음 - 일부 애플리케이션은 업데이트로 인한 호환성 문제를 가질 수 있으나, 전반적으로 좋은 참고 자료임
SPF, DKIM, DMARC 가이드
- https://github.com/nicanorflavier/spf-dkim-dmarc-simplified
이 가이드는 무엇을 위한 것인가?
- 이메일을 보내는 애플리케이션을 개발, 지원, 유지하는 사람들에게 필수적인 가이드임.
- 이메일이 스팸 폴더가 아닌 수신자의 받은 편지함에 도착하도록 보장함.
- 사이버 범죄자와 스팸 발송자로부터 도메인을 보호하는 방법을 설명함.
왜 이 가이드를 선택해야 하는가?
- 간단하고 명확한 설명과 예시로 SPF, DKIM, DMARC를 이해하기 쉽게 설명함.
- GitHub에 호스팅되어 개발 환경과 통합하여 빠르게 정보에 접근할 수 있음.
- 커뮤니티가 지속적으로 업데이트하고 유지할 수 있는 문서임.
이 가이드는 무엇을 위한 것이 아닌가?
- 이메일 서버 설정이나 암호화, 보안 이메일 게이트웨이와 같은 고급 주제를 다루지 않음.
SPF, DKIM, DMARC 간단히 설명하기
SPF (Sender Policy Framework)
- SPF: 이메일을 보낼 수 있는 친구 목록과 같음.
- SPF 레코드: 이 친구 목록을 DNS TXT 레코드에 저장함.
- 예시: v=spf1 ip4:123.123.123.123 ~all
DKIM (DomainKeys Identified Mail)
- DKIM: 이메일 내부에 비밀 노트를 넣는 것과 같음.
- DKIM 레코드: 공개 키를 DNS TXT 레코드에 저장하여 수신자가 이메일의 진위를 확인할 수 있게 함.
- 예시: v=DKIM1; k=rsa; p=NICfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBolTXCqbxwoRBffyg2efs+Dtlc+CjxKz9grZGBaISRvN7EOZNoGDTyjbDIG8CnEK479niIL4rPAVriT54MhUZfC5UU4OFXTvOW8FWzk6++a0JzYu+FAwYnOQE9R8npKNOl2iDK/kheneVcD4IKCK7IhuWf8w4lnR6QEW3hpTsawIDAQ0B
DMARC (Domain-based Message Authentication, Reporting & Conformance)
- DMARC: SPF와 DKIM의 규칙을 종합하여 큰 규칙 책을 만드는 것과 같음.
- DMARC 레코드: 이 규칙 책을 DNS TXT 레코드에 저장하여 수신자가 이메일을 처리하는 방법을 결정함.
- 예시: v=DMARC1; p=none; rua=mailto:postmaster@example.com
SPF, DKIM, DMARC의 실제 사용 예시
- 모바일 앱: 피트니스 앱이나 은행 앱이 이메일을 보낼 때 SPF, DKIM, DMARC를 사용하여 이메일이 스팸 폴더가 아닌 받은 편지함에 도착하도록 보장함.
- 이메일 서비스 제공자: Gmail, Yahoo, Outlook 등은 SPF, DKIM, DMARC를 사용하여 수신 이메일을 인증함.
- 소셜 미디어 플랫폼: LinkedIn, Facebook, Twitter 등은 알림 이메일을 보낼 때 SPF, DKIM, DMARC를 사용함.
- 기업: 프로모션 이메일을 보낼 때 SPF, DKIM, DMARC를 사용하여 이메일이 스팸으로 표시되지 않도록 하고 도메인이 이메일 스푸핑에 사용되지 않도록 함.
- 정부 기관: 시민에게 알림을 보낼 때 SPF, DKIM, DMARC를 사용하여 피싱 공격을 방지함.
이제 무엇을 해야 할까?
- 이메일 주소와 도메인 식별: 앱에서 사용하는 이메일 주소와 도메인을 파악함.
- 현재 상태 확인: 이미 SPF, DKIM, DMARC 레코드가 있는지 확인하고 올바르게 설정되었는지 확인함.
- 도메인 접근 권한: DNS 레코드를 변경할 수 있는 권한이 있는지 확인함.
- DMARC 모니터링: DMARC 보고서를 모니터링하여 문제가 없는지 확인하고, 필요한 경우 수정함.
SPF, DKIM, DMARC 상태 확인
- MXToolbox:
- https://mxtoolbox.com/ 방문
- 'SPF Record Lookup', 'DKIM Record Lookup', 'DMARC Record Lookup' 도구 사용
- DMARCTester: https://www.dmarctester.com/ 방문 이메일 보내기 또는 이메일 헤더 붙여넣기 방법 사용
FAQ's with SPF, DKIM and DMARC
- DMARC 보고용 이메일 주소: 여러 사람이 확인할 수 있는 공유 메일박스를 사용하는 것이 좋음.
- SPF 레코드의 ~all, -all, ?all, +all 차이:
- ~all (SoftFail): 목록에 없는 서버에서 온 이메일도 허용하지만 의심스러울 수 있음.
- -all (Fail): 목록에 없는 서버에서 온 이메일은 거부함.
- ?all (Neutral): 특별한 지침 없이 이메일을 처리함.
- +all (Pass): 모든 서버에서 온 이메일을 허용함.
- SPF 없이 DMARC 설정 가능 여부: 가능하지만 비효율적임. SPF와 DKIM을 함께 사용하는 것이 좋음.
- 이메일 헤더에서 여러 SPF 실패와 일부 SPF 통과가 보일 때: 자신의 도메인과 관련된 SPF 체크를 신뢰해야 함.
마무리
- SPF, DKIM, DMARC는 이메일 보안의 숨은 영웅임.
- 이 세 가지가 이메일의 신뢰성을 유지하는 데 중요한 역할을 함.
GN⁺의 의견
- 이메일 보안의 중요성: 이메일은 중요한 커뮤니케이션 수단으로, 보안이 매우 중요함.
- SPF, DKIM, DMARC의 필요성: 이 세 가지 기술은 이메일 스푸핑과 피싱 공격을 방지하는 데 필수적임.
- 도입 시 고려사항: 설정과 모니터링이 필요하며, 잘못된 설정은 이메일 전달에 문제를 일으킬 수 있음.
- 관련 도구: MXToolbox와 DMARCTester와 같은 도구를 사용하면 설정 상태를 쉽게 확인할 수 있음.
- 업계 표준: 이메일 보안을 강화하기 위해 SPF, DKIM, DMARC는 업계 표준으로 자리 잡고 있음.
케빈 켈리의 알았더라면 좋았을 103가지 조언 (kk.org)
Wired 창립 편집장 케빈 켈리(KK)가 올해 70세 생일날 블로그에 올린 훌륭한 조언들 번역
About 99% of the time, the right time is right now.
- 약 99%의 경우, 적절한 시간은 바로 지금입니다.
No one is as impressed with your possessions as you are.
- 당신만큼 당신의 소유물에 인상을 받는 사람은 없습니다.
Dont ever work for someone you dont want to become.
- 되고 싶지 않은 사람을 위해 일하지 마세요
Cultivate 12 people who love you, because they are worth more than 12 million people who like you.
- 당신을 사랑하는 12명을 키우세요. 그들은 당신을 좋아하는 1200만명보다 더 가치가 있습니다.
Dont keep making the same mistakes; try to make new mistakes.
- 같은 실수를 반복하지 마세요; 새로운 실수를 하려고 노력하세요.
If you stop to listen to a musician or street performer for more than a minute, you owe them a dollar.
- 음악가나 길거리 공연자를 듣기위해 1분이상 멈췄다면, 그들에게 1달러를 빚진 것입니다.
Anything you say before the word “but” does not count.
- "하지만" 전에 얘기한 모든 말은 중요하지 않습니다.
When you forgive others, they may not notice, but you will heal. Forgiveness is not something we do for others; it is a gift to ourselves.
- 다른 사람을 용서할 때 그들은 알아차리지 못할 수도 있지만, 당신은 치유될 것입니다. 용서는 다른 사람을 위해 하는것이 아니라, 우리 자신에게 주는 선물입니다.
Courtesy costs nothing. Lower the toilet seat after use. Let the people in the elevator exit before you enter. Return shopping carts to their designated areas. When you borrow something, return it better shape (filled up, cleaned) than when you got it.
- 예의는 비용이 들지 않습니다. 변기 시트는 사용 후에 내리세요. 엘리베이터는 사람들이 내리고 나서 타세요. 쇼핑카트는 지정된 위치에 반납하세요. 뭔가를 빌렸다면, 빌렸을 때 보다 더 좋은 상태로 반납하세요(채워지고, 청소한 상태로)
Whenever there is an argument between two sides, find the third side.
- 양측 사이에서 논쟁이 있다면, 세번째 측을 찾으세요.
Efficiency is highly overrated; Goofing off is highly underrated. Regularly scheduled sabbaths, sabbaticals, vacations, breaks, aimless walks and time off are essential for top performance of any kind. The best work ethic requires a good rest ethic.
- 효율성은 매우 과대 평가 되고, 쉬는 것(농땡이 치는 것)은 매우 과소 평가 됩니다. 정기적으로 잡힌 안식일, 안식년, 휴가, 휴식, 목적없는 산책은 모든 것에서 최고의 성과를 내는데 필수적입니다. 최고의 직업 윤리는 좋은 휴식 윤리를 요구합니다.
When you lead, your real job is to create more leaders, not more followers.
- 당신이 리드할 때, 당신의 진짜 임무는 더 많은 팔로워를 만드는게 아니라 더 많은 리더를 만드는 것입니다.
Criticize in private, praise in public.
- 비공개로 비판하고, 공개적으로 칭찬하세요.
Life lessons will be presented to you in the order they are needed. Everything you need to master the lesson is within you. Once you have truly learned a lesson, you will be presented with the next one. If you are alive, that means you still have lessons to learn.
- 인생의 교훈들은 그게 필요한 순서대로 당신에게 제공됩니다. 교훈을 마스터하는데 필요한 모든 것은 당신 안에 있습니다. 당신이 진정으로 교훈을 배우고 나면, 그 다음 교훈이 제시될 것입니다. 당신이 살아있다면, 그것은 당신이 아직 배울 교훈이 있다는 것을 의미합니다.
It is the duty of a student to get everything out of a teacher, and the duty of a teacher to get everything out of a student.
- 교사에게서 모든 것을 얻어내는 것은 학생의 의무이고, 학생에게서 모든 것을 끄집어 내는 것은 교사의 의무입니다.
If winning becomes too important in a game, change the rules to make it more fun. Changing rules can become the new game.
- 게임에서 이기는 것이 너무 중요하다면, 규칙을 변경하여 더 재미있게 만드십시오. 규칙을 바꾸는 것은 새로운 게임이 될 수도 있습니다.
Ask funders for money, and they’ll give you advice; but ask for advice and they’ll give you money.
- 투자자에게 돈을 요청하면 조언을 제공할 것입니다. 하지만 조언을 요청하면 그들은 돈을 줄 것입니다.
Productivity is often a distraction. Don’t aim for better ways to get through your tasks as quickly as possible, rather aim for better tasks that you never want to stop doing.
- 생산성은 종종 주의를 산만하게 합니다. 당신의 작업을 가능한 빨리 완료하는 방법을 목표로 하지말고, 절대 그만두기 싫은 더 좋은 작업을 목표로 하세요.
Immediately pay what you owe to vendors, workers, contractors. They will go out of their way to work with you first next time.
- 공급업체, 작업자, 계약자들에게 빚진 금액을 즉시 지불하세요. 그들은 다음번에 당신과 일하기 위해 먼저 움직일 것입니다.
The biggest lie we tell ourselves is “I dont need to write this down because I will remember it.”
- 우리가 스스로에게 하는 가장 큰 거짓말은 "기억할 것이기 때문에 기록할 이유가 없다"는 것입니다.
Your growth as a conscious being is measured by the number of uncomfortable conversations you are willing to have.
- 의식을 가진 존재로서의 당신의 성장은 당신이 기꺼이 하고 싶은 불편한 대화의 수로 측정 됩니다.
Speak confidently as if you are right, but listen carefully as if you are wrong.
- 당신이 맞는 것처럼 자신있게 말하고, 당신이 틀린 것처럼 주의깊게 들으세요.
Handy measure: the distance between your fingertips of your outstretched arms at shoulder level is your height.
- 편리한 측정 방법 : 어깨 높이에서 양쪽으로 뻗은 팔의 손가락 사이 거리가 당신의 키 입니다.
The consistency of your endeavors (exercise, companionship, work) is more important than the quantity. Nothing beats small things done every day, which is way more important than what you do occasionally.
- 노력(운동, 관계, 일)의 일관성이 양보다 중요합니다. 매일 하는 작은 것들보다 좋은 것은 없고, 이게 가끔 하는 것보다 훨씬 중요합니다.
Making art is not selfish; it’s for the rest of us. If you don’t do your thing, you are cheating us.
- 예술을 만드는 것은 이기적이지 않습니다: 그것은 다른 사람을 위한 것입니다. 당신이 당신의 일을 하지 않으면, 우리를 속이는 것입니다.
Never ask a woman if she is pregnant. Let her tell you if she is.
- 여성에게 임신 여부를 묻지 마세요. 그녀가 당신에게 얘기하게 하세요.
Three things you need: The ability to not give up something till it works, the ability to give up something that does not work, and the trust in other people to help you distinguish between the two.
- 당신에게 필요한 세가지: 뭔가가 동작할 때까지 포기하지 않는 능력, 동작하지 않는 것을 포기하는 능력, 당신이 그 두가지를 구별할 수 있도록 도와주는 다른 사람에 대한 신뢰
When public speaking, pause frequently. Pause before you say something in a new way, pause after you have said something you believe is important, and pause as a relief to let listeners absorb details.
- 대중앞에서 얘기할 때 종종 멈추세요. 새로운 방식으로 뭔가를 말하기 전에 멈추고, 당신이 중요하다고 믿는 것을 말하고 나서 멈추고, 듣는 사람이 세부사항을 흡수할 수 있도록 돕기 위해 멈추세요.
There is no such thing as being “on time.” You are either late or you are early. Your choice.
- "정시"라는 것은 없습니다. 늦거나 빠른 것입니다. 선택하세요.
Ask anyone you admire: Their lucky breaks happened on a detour from their main goal. So embrace detours. Life is not a straight line for anyone.
- 존경하는 사람에게 물어보세요: 그들의 행운의 휴식은 주요 목표에서 우회했을 때 발생했습니다. 그러니 우회하는 것을 받아들이세요. 인생은 누구에게도 직선이 아닙니다.
The best way to get a correct answer on the internet is to post an obviously wrong answer and wait for someone to correct you.
- 인터넷에서 올바른 답을 얻는 가장 좋은 방법은 명백한 오답을 게시하고 누군가 당신을 고쳐주길 기다리는 것입니다.
You’ll get 10x better results by elevating good behavior rather than punishing bad behavior, especially in children and animals.
- 아이들과 동물에게는 잘못된 것을 처벌하는 것보다 좋은 행동을 강화시키면 10배 이상의 효과를 얻을 수 있습니다.
Spend as much time crafting the subject line of an email as the message itself because the subject line is often the only thing people read.
- 이메일 제목을 작성하는데 본문을 작성하는 만큼 시간을 들이세요. 사람들이 제목만 읽는 경우가 많습니다.
Don’t wait for the storm to pass; dance in the rain.
- 폭풍우가 지나가길 기다리지 마세요; 빗속에서 춤을 추세요.
When checking references for a job applicant, employers may be reluctant or prohibited from saying anything negative, so leave or send a message that says, “Get back to me if you highly recommend this applicant as super great.” If they don’t reply take that as a negative.
- 구직자의 레퍼런스를 확인할때, 부정적인 것을 얘기하는 것을 꺼려하거나 금지당했을 수 있으므로 이렇게 메시지를 남기세요 "이 사람이 매우 훌륭하여 강력히 추천한다면 회신 부탁드려요" 그들이 회신하지 않는다면 부정적인 것으로 간주하세요.
Use a password manager: Safer, easier, better.
- 암호 관리자를 사용하세요: 더 안전하고, 더 쉽고, 더 좋습니다
Half the skill of being educated is learning what you can ignore.
- 교육 받는 기술의 절반은 무시할 수 있는 것을 배우는 것입니다.
The advantage of a ridiculously ambitious goal is that it sets the bar very high so even in failure it may be a success measured by the ordinary.
- 터무니 없이 야심찬 목표의 장점은 기준을 높게 설정함으로써, 실패하더라도 일반적으로 측정하기엔 성공이 될 수 있다는 것입니다.
A great way to understand yourself is to seriously reflect on everything you find irritating in others.
- 당신을 이해하는 훌륭한 방법은 다른 사람들에게서 짜증나는 모든 것을 당신에게 진지하게 반영해 보는 것입니다.
Keep all your things visible in a hotel room, not in drawers, and all gathered into one spot. That way you’ll never leave anything behind. If you need to have something like a charger off to the side, place a couple of other large items next to it, because you are less likely to leave 3 items behind than just one.
- 호텔방에서 모든 물건을 서랍이 아닌 눈에 보이는 한곳에 모아두세요. 그렇게 하면 물건을 두고 오지 않을 것입니다. 충전기 같은 것을 구석에 둬야 한다면 큰 물건 한두개를 그 옆에 두세요. 한개보다는 3개를 두고 올 가능성이 적기 때문입니다.
Denying or deflecting a compliment is rude. Accept it with thanks, even if you believe it is not deserved.
- 칭찬을 거부하거나 무시하는 것은 무례한 행동입니다. 자격이 없다고 생각하더라도 감사하는 마음으로 받아들이세요.
Always read the plaque next to the monument.
- 항상 기념물 옆에 있는 명판을 읽으세요.
When you have some success, the feeling of being an imposter can be real. Who am I fooling? But when you create things that only you — with your unique talents and experience — can do, then you are absolutely not an imposter. You are the ordained. It is your duty to work on things that only you can do.
- 어느 정도 성공하면, 사기꾼이 된 듯한 느낌이 들 수 있습니다. 내가 누구를 속이는 거지? 하지만 독특한 재능과 경험을 가진 당신만이 할 수 있는 것을 만든다면 당신은 절대 사기꾼이 아닙니다. 당신은 임명받은(Ordained) 사람입니다. 당신만이 할 수 있는 일을 하는 것은 당신의 의무입니다.
What you do on your bad days matters more than what you do on your good days.
- 나쁜 시기에 무엇을 하느냐가 좋은 시기에 무엇을 하느냐보다 더 중요합니다.
Make stuff that is good for people to have.
- 사람들이 가지고 있으면 좋은 것들을 만드세요
When you open paint, even a tiny bit, it will always find its way to your clothes no matter how careful you are. Dress accordingly.
- 페인트를 열면 아무리 조심하더라도 아주 조금씩은 당신 옷에 묻습니다. 맞춰서 옷을 입으세요.
To keep young kids behaving on a car road trip, have a bag of their favorite candy and throw a piece out the window each time they misbehave.
- 어린 아이들이 자동차로 여행을 갈 때 올바르게 행동하게 하려면, 그들이 좋아하는 사탕 한봉지를 가져가서 잘 못 행동할 때마다 창밖으로 한조각씩 던지세요.
You cannot get smart people to work extremely hard just for money.
- 똑똑한 사람들이 단지 돈만을 위해서 극도로 열심히 일하게 만들 수는 없습니다.
When you don’t know how much to pay someone for a particular task, ask them “what would be fair” and their answer usually is.
- 특정 일에 대해서 얼만큼 지불해야 할지 모를 때, 그들에게 "얼만큼이면 공정할까요"라고 물어보면, 그들의 답이 보통 맞습니다.
90% of everything is crap. If you think you don’t like opera, romance novels, TikTok, country music, vegan food, NFTs, keep trying to see if you can find the 10% that is not crap.
- 모든 것의 90%는 쓰레기 입니다. 오페라, 로맨스소설, 틱톡, 컨트리 음악, 비건 푸드, NFT가 마음에 들지 않는다고 생각한다면, 쓰레기가 아닌 10%를 찾을수 있도록 노력하세요.
You will be judged on how well you treat those who can do nothing for you.
- 당신을 위해 아무 것도 해줄 수 없는 사람들에게 얼마나 잘 대하는가로 당신은 판단받게 됩니다.
We tend to overestimate what we can do in a day, and underestimate what we can achieve in a decade. Miraculous things can be accomplished if you give it ten years. A long game will compound small gains to overcome even big mistakes.
- 우리는 하루에 할 수 있는 일들을 과대 평가하고, 10년안에 이룰 수 있는 일을 과소 평가하는 경향이 있습니다. 10년을 들이면 기적같은 일이 일어납니다. 긴 게임에선 큰 실수라도 회복할 수 있도록 작은 이익들을 합칩니다.
Thank a teacher who changed your life.
- 당신의 인생을 바꿔준 선생님게 감사드리세요.
You cant reason someone out of a notion that they didn’t reason themselves into.
- 당신은 그들이 스스로 추론하지 않은 개념으로 그들을 추론할 수 없습니다.
Your best job will be one that you were unqualified for because it stretches you. In fact only apply to jobs you are unqualified for.
- 당신의 최고의 직업은 당신이 모잘라서 (자신을 늘려야만 맞는) 자격이 없는 것들중 하나가 것입니다. 당신이 자격이 되지 않아 보이는 직업에 지원하세요.
Buy used books. They have the same words as the new ones. Also libraries.
- 중고 책을 구입하세요. 그들은 새 것과 같은 말을 담고 있습니다. 또는 도서관에 가세요.
You can be whatever you want, so be the person who ends meetings early.
- 당신은 당신이 원하는 무엇이든 할 수 있으니까, 미팅을 일찍 끝내는 사람이 되세요.
A wise man said, “Before you speak, let your words pass through three gates. At the first gate, ask yourself, “Is it true?” At the second gate ask, “Is it necessary?” At the third gate ask, “Is it kind?”
- 현명한 사람이 이야기 하길 "말하기 전에, 말들이 세개의 문을 통과 하게 하세요. 첫번째 문에서 당신에게 물어보세요. '이거 진짜야?' 두번째 문에서는 '이거 필요해?' 세번째 문에서는 '이거 친절해?'"
Take the stairs.
- 계단을 이용하세요.
What you actually pay for something is at least twice the listed price because of the energy, time, money needed to set it up, learn, maintain, repair, and dispose of at the end. Not all prices appear on labels. Actual costs are 2x listed prices.
- 당신이 실제로 지불하는 것은 그것을 만들고, 배우고, 유지보수하고, 수리하고, 마지막에 처분하는데 드는 에너지, 시간, 돈 때문에 실제 표시된 금액의 적어도 두배 이상입니다. 모든 가격이 라벨에 적혀있지 않습니다. 실제 비용은 표시된 가격의 2배입니다.
When you arrive at your room in a hotel, locate the emergency exits. It only takes a minute.
- 호텔의 당신방에 도착하면, 비상구를 확인하세요. 1분밖에 걸리지 않습니다.
The only productive way to answer “what should I do now?” is to first tackle the question of “who should I become?”
- "지금 뭘 해야 할까요?"에 대답하는 유일한 생산적인 방법은 "나는 어떤 사람이 되어야 할까요?"에 대한 질문을 먼저 해결하는 것입니다.
Average returns sustained over an above-average period of time yield extraordinary results. Buy and hold.
- 평균 이상의 기간동안 지속되는 평균 수익률은 놀라운 결과를 가져옵니다. 사고 유지하세요.
It’s thrilling to be extremely polite to rude strangers.
- 무례한 낯선 사람에게 극도로 공손하게 대하는 것은 짜릿한 일입니다.
It’s possible that a not-so smart person, who can communicate well, can do much better than a super smart person who can’t communicate well. That is good news because it is much easier to improve your communication skills than your intelligence.
- 아주 똑똑하지 않지만 의사소통을 잘하는 사람이 의사소통을 잘 못하는 엄청 똑똑한 사람보다 훨씬 더 잘 할 수 있습니다. 당신의 지능보다 의사소통을 향상시키는 것이 더 쉽기때문에 좋은 소식입니다.
Getting cheated occasionally is the small price for trusting the best of everyone, because when you trust the best in others, they generally treat you best.
- 때때로 속는 것은 모든 사람의 최고를 신뢰하기 위한 작은 대가 입니다. 당신이 누군가의 최고를 신뢰할 때, 그들은 일반적으로 당신을 최고로 대우하기 때문입니다.
Art is whatever you can get away with.
- 예술은 당신이 얻을 수 있는 모든 것입니다.
For the best results with your children, spend only half the money you think you should, but double the time with them.
- 자녀와 함께 최고의 결과를 얻으려면, 사용해야 한다고 생각하는 돈의 절반만 사용하고 같이하는 시간을 두배로 늘리세요.
Purchase the most recent tourist guidebook to your home town or region. You’ll learn a lot by playing the tourist once a year.
- 당신의 홈타운 또는 지역의 최신 여행자 가이드를 구입하세요. 일년에 한번 관광객이 되면 많은 것을 배울 것입니다.
Dont wait in line to eat something famous. It is rarely worth the wait.
- 유명한 것을 먹기위해 줄 서지 마세요. 기다릴 가치가 있는 경우가 드뭅니다.
To rapidly reveal the true character of a person you just met, move them onto an abysmally slow internet connection. Observe.
- 당신이 만난 사람의 진정한 성격을 빠르게 보려면, 느린 인터넷 연결로 옮기고 관찰해보세요.
Prescription for popular success: do something strange. Make a habit of your weird.
- 인기있는 성공을 위한 처방 : 이상한 것을 하세요. 이상한 습관을 들이세요.
Be a pro. Back up your back up. Have at least one physical backup and one backup in the cloud. Have more than one of each. How much would you pay to retrieve all your data, photos, notes, if you lost them? Backups are cheap compared to regrets.
- 전문가가 되세요. 백업을 백업하세요. 적어도 하나의 물리적 백업과 하나의 클라우드 백업을 만드세요. 각각 1개 이상 보유하세요. 당신의 모든 데이터, 사진, 노트를 복구하려면 얼마를 지불할껀가요? 백업은 후회보다 쌉니다.
Dont believe everything you think you believe.
- 당신이 믿는다고 생각하는 모든 것을 믿지 마세요.
To signal an emergency, use the rule of three; 3 shouts, 3 horn blasts, or 3 whistles.
- 위험 신호를 보내려면 3의 법칙을 사용하세요; 3번 외치거나, 3번 경적을 울리거나, 3번 휘파람을 부세요
At a restaurant do you order what you know is great, or do you try something new? Do you make what you know will sell or try something new? Do you keep dating new folks or try to commit to someone you already met? The optimal balance for exploring new things vs exploiting them once found is: 1/3. Spend 1/3 of your time on exploring and 2/3 time on deepening. It is harder to devote time to exploring as you age because it seems unproductive, but aim for 1/3.
- 레스토랑에서 훌륭하다고 알려진 것을 주문하나요? 아니면 새로운 것을 시도하나요? 잘 팔릴 것이라고 믿는 것을 만드나요? 아니면 새로운 것을 만드나요? 새로운 사람들과 데이트를 하나요? 아니면 기존에 알던 사람들과 약속을 만드나요? 새로운 것을 탐색하는 것과 기존에 아는 것을 활용하는 최적의 균형은 1/3 입니다. 당신의 시간의 1/3을 탐험하는 데 쓰고, 2/3의 시간은 심화하는데 사용하세요. 나이가 들수록 탐험하는데 시간을 쓰는 것은 비생산적이어서 힘들지만, 1/3이 되도록 노력하세요.
Actual great opportunities do not have “Great Opportunities” in the subject line.
- 진짜로 좋은 기회는 "좋은 기회"라는 제목을 가지지 않습니다.
When introduced to someone make eye contact and count to 4. You’ll both remember each other.
- 누군가를 소개 받을 때 눈을 마주치고 4까지만 세세요. 양쪽이 서로를 기억하게 될겁니다.
Take note if you find yourself wondering “Where is my good knife? Or, where is my good pen?” That means you have bad ones. Get rid of those.
- "내 좋은 칼은 어디있지? 또는 내 좋은 펜은 어디있지?" 라고 당신이 찾는다면, 나쁜 것들을 가지고 있다는 얘기입니다. 그런 것들은 제거하세요.
When you are stuck, explain your problem to others. Often simply laying out a problem will present a solution. Make “explaining the problem” part of your troubleshooting process.
- 뭔가에 막히면 다른 사람에게 문제를 설명하세요. 종종 단순히 문제를 늘어놓는 것만으로도 해결책을 찾게 됩니다. "문제를 설명하는 것"을 당신의 문제해결 프로세스의 일부로 만드세요.
When buying a garden hose, an extension cord, or a ladder, get one substantially longer than you think you need. It’ll be the right size.
- 정원용 호스, 연장 코드, 사다리를 구입할 때 필요하다고 생각하는 것보다 훨씬 긴 것을 구입하세요. 딱 좋은 사이즈가 될겁니다.
Dont bother fighting the old; just build the new.
- 오래된 것과 싸우려고 하지 마세요; 그냥 새 것을 만드세요.
Your group can achieve great things way beyond your means simply by showing people that they are appreciated.
- 당신의 그룹은 사람들에게 감사를 표하는 것만으로 여러분의 능력을 뛰어 넘는 훌륭한 것을 성취할 수 있습니다.
When someone tells you about the peak year of human history, the period of time when things were good before things went downhill, it will always be the years of when they were 10 years old — which is the peak of any human’s existence.
- 누군가가 인류 역사의 전성기, 뭔가가 나빠지기전 좋았던 시기를 이야기 한다면 그것은 - 모든 인간 존재의 절정인 - 10살때 쯤 이야기 일겁니다.
You are as big as the things that make you angry.
- 당신은 당신을 화나게 만드는 것 만큼 큽니다.
When speaking to an audience it’s better to fix your gaze on a few people than to “spray” your gaze across the room. Your eyes telegraph to others whether you really believe what you are saying.
- 청중에게 말을 할 때, 시선을 방 전체에 "뿌리는(spray)" 것보다. 몇명에게 시선을 고정하는 것이 좋습니다. 당신의 눈은 당신이 말하는 것을 진짜로 믿는지를 다른 사람에게 전합니다.
Habit is far more dependable than inspiration. Make progress by making habits. Dont focus on getting into shape. Focus on becoming the kind of person who never misses a workout.
- 습관은 영감보다 훨씬 더 신뢰할 수 있습니다. 습관을 만드는 것으로 발전하세요. 몸매 관리에 집중하지 마세요. 운동을 빼먹지 않는 사람이 되는데 집중하세요.
When negotiating, dont aim for a bigger piece of the pie; aim to create a bigger pie.
- 협상할 때 큰 파이 조각을 목표로 하지 마세요; 큰 파이를 만드는 것을 목표로 하세요.
If you repeated what you did today 365 more times will you be where you want to be next year?
- 오늘 한 일을 365번 더 반복하면 당신이 내년에 원하는 위치에 있게 될까요 ?
You see only 2% of another person, and they see only 2% of you. Attune yourselves to the hidden 98%.
- 당신은 다른 사람의 2%만 보고, 그들도 당신의 2%만 봅니다. 숨겨진 98%에 자신을 맞추세요.
Your time and space are limited. Remove, give away, throw out things in your life that dont spark joy any longer in order to make room for those that do.
- 당신의 시간과 공간은 제한되어 있습니다. 기쁨을 주는 것들이 들어갈 공간을 만들기 위해 더 이상 기쁜을 주지 않는 것들을 인생에서 제거하고, 나눠주고, 버리세요.
Our descendants will achieve things that will amaze us, yet a portion of what they will create could have been made with today’s materials and tools if we had had the imagination. Think bigger.
- 우리의 후손들은 우리를 놀라게 할 것들을 성취할 것이지만, 그들이 만들 것중의 일부는 우리가 상상력이 있다면 요즘의 재료와 도구들로도 만들수 있었을 것입니다. 더 크게 생각하세요.
For a great payoff be especially curious about the things you are not interested in.
- 큰 보상을 위해서는 당신이 관심을 가지지 않는 것에 큰 호기심을 가지세요.
Focus on directions rather than destinations. Who knows their destiny? But maintain the right direction and you’ll arrive at where you want to go.
- 목적지 보다는 방향에 초점을 맞추세요. 누가 그들의 운명을 알까요? 하지만 올바른 방향을 유지하면 가고자 하는 곳에 도착할 겁니다.
Every breakthrough is at first laughable and ridiculous. In fact if it did not start out laughable and ridiculous, it is not a breakthrough.
- 모든 혁신은 처음에는 웃기고 어리석어 보입니다. 사실 웃기고 어리석어 보이게 시작하지 않는다면, 그건 혁신이 아닙니다.
If you loan someone $20 and you never see them again because they are avoiding paying you back, that makes it worth $20.
- 누군가에게 $20를 빌려줬는데 그가 갚지 않으려고 해서 다시 만나지 못한다면, 그 $20은 가치가 있습니다.
Copying others is a good way to start. Copying yourself is a disappointing way to end.
- 다른 사람을 베끼는 것은 시작하는 좋은 방법입니다. 자신을 모방하는 것은 실망스러운 결말입니다.
The best time to negotiate your salary for a new job is the moment AFTER they say they want you, and not before. Then it becomes a game of chicken for each side to name an amount first, but it is to your advantage to get them to give a number before you do.
- 새 직장에 대한 급여를 협상하기에 가장 좋은 시점은 그들이 당신을 원한다고 말한 직후이지 그 전이 아닙니다. 각자가 원하는 금액을 얘기하도록 하는 치킨게임이 되지만, 당신이 원하는 숫자를 먼저 말하기 전에 그들이 얘기하게 하는 것이 당신에게 유리합니다.
Rather than steering your life to avoid surprises, aim directly for them.
- 놀라움을 피하기 위해 인생을 조종하는 것 보다는, 그걸 목표로 삼으세요.
Dont purchase extra insurance if you are renting a car with a credit card.
- 신용 카드로 차를 렌트하는 경우, 추가 보험에 가입하지 마세요.
If your opinions on one subject can be predicted from your opinions on another, you may be in the grip of an ideology. When you truly think for yourself your conclusions will not be predictable.
- 한 주제에 대한 당신의 의견이 당신의 다른 것에 대한 의견에서 추측될 수 있다면, 당신은 아마 이념에 사로잡혀 있을 것입니다. 당신이 진정으로 스스로 생각한다면, 당신의 결론은 예측할 수 없을 것입니다.
Aim to die broke. Give to your beneficiaries before you die; it’s more fun and useful. Spend it all. Your last check should go to the funeral home and it should bounce.
- 죽을때 파산을 목표로 하세요. 당신이 죽기전에 수혜자들에게 나눠주세요; 더 재미있고 유용합니다. 다 쓰세요. 당신의 마지막 수표는 장례식장으로 가야 하고 반송되어야 합니다.
The chief prevention against getting old is to remain astonished.
- 늙어가는 것을 막는 가장 중요한 예방책은 놀라움을 유지하는 것입니다.
ABC 원칙의 일상 적용
- Assume nothing: 아무것도 가정하지 마라
- Believe nothing: 아무것도 믿지 마라
- Challenge everything: 모든 걸 의심하라
6-C 체계적 접근법
- Collect: 정보를 수집하라
- Check: 사실을 확인하라
- Connect: 점들을 연결하라
- Construct: 가설을 세워라
- Consider: 필요한 정보를 고려하라
- Consult: 신뢰할 사람과 상의하라
<img src="image.jpg" fetchpriority="low" loading="lazy" />
CSS에서 시스템 폰트 사용하기
body {
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
Arial, sans-serif;
}
body {
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
:root {
--system-ui:
system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
.element {
font-family: var(--system-ui);
}
- https://cs.stanford.edu/people/karpathy/advice.html
- https://news.hada.io/topic?id=23771
과목에서 좋은 성적 받기: Andrej Karpathy의 성공을 위한 조언 (cs.stanford.edu)
- Andrej Karpathy가 대학생들에게 보내는 학업 성공 조언 정리
- 충분한 수면과 철저한 사전 준비가 학업 성취에 핵심임
- 시험 공부 시 기출문제 분석과 체계적 계획 세우기가 중요함
- 공부는 초기 혼자, 마지막엔 동료와 협업, 그리고 개념을 직접 설명하며 이해도를 높임
- 시험 당일에는 효율적인 식습관과 직전 단기 집중 학습이 효과적임
- 실질적 경험과 프로젝트 참여, 그리고 신뢰할 수 있는 추천인 확보가 학점보다 훨씬 중요함
과목에서 좋은 성적을 받기 위한 Andrej Karpathy의 가이드
- Andrej Karpathy가 대학생들에게 보내는 학업 성공 조언 정리
- 본인의 경험을 바탕으로 공부, 시험 준비, 시험 당일 행동, 장기적 커리어 방향까지 폭넓게 다룸.
일반 원칙
- 밤샘 공부는 효과가 없음: 최적 수면 시간은 7.5시간이며, 최소 4시간은 필요
- 밤에 1시간 동안 해결하지 못한 문제가 아침에 5분 만에 풀리는 경우가 많음
- 뇌가 수면 중에 단기 기억을 장기 기억으로 "커밋" 하는 과정을 거침
- 큰 시험은 며칠 전부터 준비하여 뇌가 자료를 처리할 밤의 횟수를 최대화해야 함
- 튜토리얼이나 복습 세션에 참석: 내용이 지루해도 자료에 대해 생각하게 만드는 것 자체가 중요함
시험 준비
- 큰 그림과 조직화가 핵심: 공부 일정을 작성하고, 알아야 할 모든 내용을 명시적으로 bullet point로 정리
- 각 항목을 신중히 고려하고 소요 시간을 예상
- 이를 하지 않으면 초반 자료에 시간을 너무 많이 쓰고 중요한 후반 내용을 대충 훑게 됨
- 공부를 시작하기 전에 반드시 기출 문제를 확인: 특히 같은 교수가 출제한 경우
- 교수마다 평가 스타일이 다르므로 어떻게 공부해야 할지 강력한 힌트를 얻을 수 있음
- 처음부터 문제를 풀려고 하지 말고 문제 유형을 주의 깊게 파악
- 읽고 이해하는 것과 재현하는 것은 다름: 책에서 공식/유도/증명을 읽고 이해했다면, 책을 덮고 직접 써보기
- 두 과정은 기억의 다른 부분을 사용하므로, 실제로 써보면 많은 경우 할 수 없다는 것을 발견하게 됨
- 가장 중요한 부분을 실제로 쓸 수 있고 언제든 재유도할 수 있도록 확실히 해야 함
- Feynman도 이를 잘 알고 있었음: "내가 만들 수 없는 것은 이해하지 못한 것"
- 다른 사람들과 협력하되, 마지막 단계에서: 초기에는 혼자 공부하되, 마지막에는 다른 사람들과 모임
- 다른 사람들이 중요한 함정을 지적하고 좋은 이슈를 제기하며, 가르칠 기회를 줌
- 실력이 더 강한 학생들하고만 어울리지 말 것: 약한 학생들에게 설명하면 티칭을 통한 이해가 크게 향상됨
- 기말 전에 최소 한 번은 교수 오피스 아워 방문: 질문이 없어도 가기
- 교수가 1:1 상황에서 전체 학급 앞에서는 공개하지 않을 시험 정보를 말해주는 경우가 있음
- 약간 불공정하지만, 교수가 당신을 조금이라도 알게 하는 것이 좋음
- 충분히 미리 공부: 뇌가 자료를 흡수하는 데 시간이 필요하며, 어려워 보이던 것이 시간이 지나면 쉬워짐
- 중간고사는 약 3일, 기말고사는 약 6일 할당 권장
- 상황이 나쁘고 너무 피곤하면 에너지 드링크: 긴급 상황에서는 효과가 있음
- 수학 같은 과목은 연습이 읽기보다 중요: 연습 문제를 풀 준비가 되면 문제를 풀면서 빈틈을 메우기
- 치트 시트 만들기: 시험에 가져갈 수 없어도 만들기
- 내용을 쓰는 것 자체가 도움이 됨
- 전체 과정을 1페이지 이상에 정리하여 "이것이 내가 알아야 할 모든 것"이라고 확신할 수 있도록
- 다른 사람들도 공부하는 장소에서 공부: 자신만 공부하지 않을 때 죄책감을 느끼게 됨
- 배경 소음이 많은 곳은 학습에 부정적 영향을 주므로 도서관과 독서실이 최적
시험 당일
- 최적의 식사/음료 습관은 시험 2시간 전 커피와 음식 섭취 - 시험 직전 커피나 음식은 항상 나쁨 - 잠재적으로 스트레스가 많은 상황 직전의 커피는 항상 나쁨 - 커피를 전혀 안 마시는 것도 나쁨 - 시험 직전에 매우 집중적으로 공부: 많은 사람들이 시험 전에 포기하고 "휴식"을 취한다고 주장 - 단기 기억은 훌륭한 도구이므로 낭비하지 말 것 - 시험 직전까지 최대한 집중적으로 공부 - 휴식이 필요하면 시험 1시간 전에 취하되, 시험 30-45분 전에는 정말 열심히 공부
시험 중
- 항상 연필 사용: 쓰레기 같은 "솔루션"을 지울 수 있어야 함 - 시작 전 모든 문제를 매우 간단히 훑어보기: 문제당 1-3초 정도만 보면 충분 - 핵심 단어를 흡수하고 전체 시험의 규모를 파악 - 쉬운 문제부터 먼저 풀기: 한 문제에 너무 오래 붙잡혀 있지 말고 나중에 다시 돌아오기 - 첫 번째 pass에서 시험의 30%만 완성하는 경우도 있음 - 일부 문제는 "워밍업" 후에 훨씬 쉬워짐 - 시험지를 항상 깔끔하게: 사람이 채점한다는 명백한 사실을 깨닫는 사람이 놀랍게도 적음 - 슬픈 사람은 낮은 점수를 줌 - 항상 답을 박스/원으로 표시: 특히 주변에 유도 과정이 있을 때 - 채점자가 빠르게 체크 표시하고 넘어갈 수 있게 함 - 채점자의 마음가짐을 갖기 - 절대, 절대, 절대 시험을 일찍 떠나지 말 것: 실수를 했을 것이므로(보장함) 찾아서 고치기 - 찾을 수 없으면 시간이 다할 때까지 더 열심히 찾기 - 실수가 없다고 매우 확신하면 시험지를 더 읽기 쉽고 채점하기 쉽게 만들기 - 일찍 떠나는 사람들은 어리석음 - 잠재적 이익이 비용을 완전히 압도하는 상황 - 채점자와 소통: 자신이 적은 것보다 더 많이 안다는 것을 보여주기 - 특정 단계를 할 수 없어도 그 단계를 했다면 어떻게 진행할지 명확히 하기 - 필요할 때 메모를 남기는 것을 두려워하지 말 것 - 채점자들은 종종 더 많은 점수를 찾으려고 노력하므로 쉽게 만들어주기 - 문제당 배점 고려: 많은 시험이 각 문제가 몇 점인지 알려줌 - 무언가 잘못하고 있을 때 매우 강력한 힌트를 줌 - 어떤 문제에 집중해야 할지 강력한 힌트 제공 - 배점이 적은데 상대적으로 어려운 문제에 너무 많은 시간을 쓰는 것은 어리석음 - 5분 미만 남았고 여전히 어떤 문제에 막혀 있다면 중단: 모든 문제를 다시 읽으며 2차 질문을 놓치지 않았는지, 모든 것에 답했는지 확인하는 것이 더 나음 - 사람들이 이런 식으로 잃는 어리석은 점수가 얼마나 많은지 믿을 수 없을 것
가장 중요한 조언
- 학부생들은 수업에 대한 터널 비전을 가지는 경향이 있으며 좋은 성적을 원함 - 깨달아야 할 중요한 사실: 아무도 당신의 성적에 관심이 없음(나쁘지 않은 한) - 가장 똑똑한 학생은 모든 과목에서 85%를 받아 약 4.0 학점을 얻지만 과도하게 공부하지도, 부족하게 공부하지도 않음 - 시간은 귀중하고 제한된 자원: 시험에서 망치지 않을 정도로만 하고 훨씬 더 중요한 노력으로 주의를 전환 - 실제 실무 경험이 극도로 중요: 실제 코드베이스, 프로젝트, 어리석은 과정 연습 외의 문제 작업 - 당신을 알고 좋은 추천서를 써줄 수 있는 교수/사람들이 극도로 중요 - 당신이 주도성, 열정, 추진력을 가지고 있다고 말하는 추천서가 중요 - 취업을 생각 중이라면 여름 인턴십: 대학원 진학을 생각 중이라면 연구 경험을 얻기 - 학교가 제공하는 프로그램에 등록하거나 교수/대학원생에게 연락하여 좋아하는 연구 프로젝트에 참여하기 - 잘 알려진 교수가 당신이 추진력 있고 독립적 사고자라고 쓴 추천서는 다른 모든 것, 특히 성적 같은 사소한 것을 완전히 압도함 - 지원 전에 최소한 한 편의 논문을 끼워 넣으면 많은 도움이 됨 - 프로젝트에 등록한 후 몇 번 만나고 질문을 많이 하다가 갑자기 포기하고 사라지는 학부생이 되지 말 것: 평판을 손상시킴 - 사이드 프로젝트에서 그룹과 함께 참여하거나 처음부터 자신의 프로젝트 시작: 오픈소스에 기여하고, 라이브러리를 만들거나 개선 - 멋진 것을 만들고 잘 문서화하며 블로그 작성 - 몇 년 후 사람들이 관심을 가질 것: 성적은 그저 처리해야 할 골칫거리일 뿐
장치산업이면 PBR 2이내(반도체, 석유화학, 자동차 등등), 소프트웨어같은 무형자산의 기술 기업이라면 PBR은 거의 의미없다고 보고, 그리고 젤 중요하게 보는게 PER 입니다. PER을 볼때는 현재뿐만 아니라 미래에 회사가 벌어들일수 있는 금액을 대충 예상해봐서 따져봐야 합니다. 단, 미래에 년간 회사가 벌어들일수 있는 돈은 회사말만 믿으면 안되고 나름대로 그 회사가 몸담고 있는 시장 규모를 먼저 보시고, 대충 마켓쉐어 + 이익률 정도로 따져보면 대강의 숫자가 나오는데 이걸로 판단하면 됩니다. 참고로 미국 주식의 역사적 PER range 는 5 ~ 25 사이입니다. 지금 PER 70, 200, 400 씩 하는 유명한 주식들이 아무리 미래 가치를 반영했다 하더라도 너무 말이 안되게 비싼 주식들이 많거든요. 회사에서 말하는 미래 매출, 가치가 그대로 구현되는 회사가 얼마나 될까요? 장이 좋을때는 그럴듯 해 보이지만, 장이 안좋을때는 다 빨가벗게 되어 있습니다. 그런면에서 삼전은 PER나 PBR로 봐도 고평가 된 회사라고 보기는 어렵습니다. 반면 하닉은... 한번 살펴보시기 바랍니다. 삼전이랑 비교해 보시면 됩니다.
- 뛰어난 엔지니어는 최고의 프로그래머가 아니라 코드 주변의 사람, 정치, 조율, 모호성을 탐색하는 방법을 터득한 사람들임
- 기술보다는 프로젝트와 팀에서 반복적으로 나타나는 패턴에 초점을 맞춘 내용으로, 사용자 문제 해결, 팀 협업, 코드 품질, 경력 관리 등을 포괄함
- 명확성이 선임 엔지니어의 핵심 자질이며 영리함은 오버헤드일 뿐이라는 점과, 작성하지 않은 코드가 최고의 코드라는 역설적 통찰을 보여줌
- 대규모 조직에서는 정렬 실패가 속도 저하의 주요 원인이며, 측정 지표가 목표가 되면 왜곡된다는 조직 운영의 함정을 드러냄
- 장기적 관점에서 시간이 돈보다 가치 있는 자원이 되며, 네트워크는 각 직장보다 오래 지속되므로 의도적인 경력 설계가 필요함
최고의 엔지니어는 사용자 문제 해결에 집착함
- 기술에 먼저 빠져 적용처를 찾는 것은 유혹적이지만, 가장 큰 가치를 창출하는 엔지니어는 역으로 작업함 - 사용자 문제를 깊이 이해하고 거기서 솔루션을 도출
- 사용자 집착이란 지원 티켓에 시간 투자, 사용자와 대화, 사용자의 어려움 관찰, 근본에 도달할 때까지 "왜"를 질문하는 것을 의미함
- 문제를 진정으로 이해하는 엔지니어는 종종 우아한 솔루션이 예상보다 단순함을 발견함
- 솔루션부터 시작하는 엔지니어는 정당화를 찾기 위해 복잡성을 구축하는 경향이 있음
옳은 것은 쉽지만, 함께 옳음에 도달하는 것이 진짜 업무
- 모든 기술 논쟁에서 이기고도 프로젝트를 잃을 수 있으며, 항상 방에서 가장 똑똑한 사람이 되어 조용한 반감을 축적하는 뛰어난 엔지니어들을 목격함
- 비용은 나중에 "불가사의한 실행 문제"와 "이상한 저항"으로 나타남
- 핵심 기술은 옳은 것이 아니라 문제 정렬을 위해 토론에 참여하고, 타인을 위한 공간을 창출하며, 자신의 확신에 회의적 태도를 유지하는 것
- 강한 의견, 약한 집착 - 확신이 부족해서가 아니라, 불확실성 하의 결정을 정체성에 결합해서는 안 되기 때문
행동 편향을 가지고 출시하라. 나쁜 페이지는 편집 가능하지만 빈 페이지는 불가능
- 완벽 추구는 마비를 초래하며, 한 번도 만들어보지 않은 것의 이상적 아키텍처를 몇 주간 논쟁하는 엔지니어들을 목격함
- 완벽한 솔루션은 사고만으로 나오지 않고 현실과의 접촉에서 등장하며, AI가 여러 방식으로 도움을 줄 수 있음
- 먼저 하고, 제대로 하고, 더 잘하는 순서로 진행 - 못생긴 프로토타입을 사용자 앞에 두고, 지저분한 디자인 문서 초안을 작성하고, 약간 부끄러운 MVP를 출시함
- 한 주의 실제 피드백에서 한 달의 이론적 논쟁보다 더 많이 학습하며, 추진력이 명확성을 만들고 분석 마비는 아무것도 만들지 못함
명확성이 시니어의 징표이며, 영리함은 오버헤드
- 영리한 코드 작성 본능은 엔지니어에게 거의 보편적이며 역량 증명처럼 느껴짐
- 소프트웨어 엔지니어링은 시간과 다른 프로그래머를 추가할 때 발생하며, 그 환경에서 명확성은 스타일 선호가 아닌 운영 리스크 감소를 의미함
- 코드는 장애 중 새벽 2시에 유지보수할 낯선 사람들을 위한 전략 메모이므로, 우아함이 아닌 그들의 이해도를 최적화해야 함
- 가장 존경받는 선임 엔지니어들은 영리함을 명확성과 매번 교환하는 법을 학습함
새로움은 장애, 채용, 인지 오버헤드로 갚는 빚
- 기술 선택을 작은 "혁신 토큰" 예산을 가진 조직처럼 다루고, 실질적으로 비표준적인 것을 채택할 때마다 하나씩 소비함 - 많이 감당할 수 없음
- 요점은 "절대 혁신하지 말라"가 아니라 "고유하게 혁신하도록 보상받는 곳에서만 혁신" 하는 것이며, 나머지는 지루함이 기본값이어야 함
- 지루함은 알려진 실패 모드를 가지고 있기 때문
- "작업에 최고의 도구"는 종종 "많은 작업에 걸쳐 최소-최악의 도구" 를 의미함 - 동물원 운영이 실제 세금이 되기 때문
코드는 당신을 옹호하지 않으며, 사람들이 옹호함
- 초기 경력에서 훌륭한 업무가 스스로 말할 것이라 믿었으나 이는 오류였으며, 코드는 저장소에 조용히 앉아있을 뿐
- 관리자가 회의에서 당신을 언급하거나 하지 않고, 동료가 프로젝트에 당신을 추천하거나 다른 사람을 추천함
- 대규모 조직에서는 초대받지 않은 회의에서, 직접 작성하지 않은 요약으로, 5분과 12개 우선순위를 가진 사람들이 결정을 내림
- 당신이 없는 방에서 아무도 당신의 영향을 표현할 수 없다면 그 영향은 사실상 선택 사항이며, 이는 자기 홍보가 아니라 가치 사슬을 자신을 포함한 모두에게 읽기 가능하게 만드는 것
최고의 코드는 작성할 필요가 없었던 코드
- 엔지니어링 문화에서 창조를 축하하지만, 삭제가 추가보다 시스템을 더 개선하는 경우가 많은데도 코드 삭제로 승진하는 사람은 없음
- 작성하지 않은 모든 코드 라인은 디버깅, 유지보수, 설명할 필요가 없는 라인
- 구축 전 질문을 고갈시켜야 함: "그냥... 하지 않으면 어떻게 될까?" - 때때로 답이 "나쁜 일 없음"이면 그것이 솔루션
- 문제는 엔지니어가 코드를 작성하지 못하거나 AI로 작성하지 못하는 것이 아니라, 너무 잘 작성해서 작성해야 하는지를 묻는 것을 잊는 것
규모에서는 버그조차 사용자를 보유함
- 충분한 사용자가 있으면 모든 관찰 가능한 동작이 의존성이 되며, 약속과 무관함 - 누군가는 API를 스크래핑하고, 특이점을 자동화하며, 버그를 캐싱함
- 이는 경력 수준의 통찰을 창출함: 호환성 작업을 "유지보수"로, 새 기능을 "실제 작업"으로 취급할 수 없으며, 호환성이 곧 제품
- 시간, 도구, 공감으로 지원 중단을 마이그레이션으로 설계해야 함
- 대부분의 "API 설계"는 실제로 "API 은퇴" 를 의미함
대부분의 "느린" 팀은 실제로 정렬되지 않은 팀
- 프로젝트가 지연될 때 본능은 실행을 비난하는 것 - 사람들이 충분히 열심히 일하지 않음, 기술이 잘못됨, 엔지니어가 충분하지 않음 - 하지만 보통 이것이 실제 문제가 아님
- 대기업에서 팀은 동시성의 단위이지만, 팀이 곱해질수록 조정 비용은 기하급수적으로 증가함
- 대부분의 느림은 실제로 정렬 실패를 의미함 - 잘못된 것을 구축하거나, 올바른 것을 호환되지 않는 방식으로 구축함
- 선임 엔지니어는 "코드를 더 빨리 작성"보다 방향, 인터페이스, 우선순위 명확화에 더 많은 시간을 투자함 - 실제 병목이 거기 있기 때문
통제 가능한 것에 집중하고, 불가능한 것은 무시하라
- 대기업에서는 수많은 변수가 통제 밖에 있음 - 조직 변경, 관리 결정, 시장 변화, 제품 전환 - 이것에 몰두하면 행위성 없는 불안을 창출함
- 제정신을 유지하고 효과적인 엔지니어는 영향력 범위에 집중함 - 재조직 발생 여부는 통제할 수 없지만, 업무 품질, 대응 방식, 학습 내용은 통제 가능함
- 불확실성에 직면하면 문제를 조각으로 나누고 자신에게 가능한 구체적 행동을 식별해야 함
- 이는 수동적 수용이 아니라 전략적 집중이며, 바꿀 수 없는 것에 쓰는 에너지는 바꿀 수 있는 것에서 훔쳐오는 에너지
추상화는 복잡성을 제거하지 않으며, 당신이 온콜일 때로 이동시킴
- 모든 추상화는 밑에 무엇이 있는지 이해할 필요가 없을 것이라는 내기이며, 때때로 이 내기에 이김
- 하지만 무언가는 항상 누출되며, 누출될 때 자신이 무엇 위에 서 있는지 알아야 함
- 선임 엔지니어는 스택이 높아질수록 "하위 레벨" 것들을 계속 학습함 - 향수가 아니라, 추상화가 실패하고 새벽 3시에 시스템과 홀로 있는 순간에 대한 존중 때문
- 스택을 사용하되, 기본 실패 모드에 대한 작동 모델을 유지해야 함
글쓰기는 명확성을 강제함. 무언가를 더 잘 학습하는 가장 빠른 방법은 가르치려 시도하는 것
- 글쓰기는 명확성을 강제하며, 개념을 다른 사람에게 설명할 때 - 문서, 발표, 코드 리뷰 코멘트, 심지어 AI와 채팅 - 자신의 이해에서 공백을 발견함
- 무언가를 다른 사람에게 읽기 가능하게 만드는 행위가 자신에게 더 읽기 가능하게 만듦
- 이는 외과의사가 되는 법을 가르쳐서 배운다는 의미는 아니지만, 전제는 소프트웨어 엔지니어링 영역에서 대체로 참
- 이는 지식을 나누는 관대함만이 아니라 이기적인 학습 해크(hack) 이기도 함 - 무언가를 이해한다고 생각하면 간단히 설명을 시도하고, 막히는 곳이 이해가 얕은 곳
- 가르치는 것은 자신의 정신 모델을 디버깅하는 것
다른 업무를 가능하게 하는 업무는 귀중하지만 보이지 않음
- 글루 작업 - 문서화, 온보딩, 팀 간 조정, 프로세스 개선 - 은 필수적이지만, 무의식적으로 하면 기술 궤적을 정체시키고 번아웃을 초래할 수 있음
- 함정은 이를 "도움됨"으로 하는 것이지, 의도적이고, 경계가 있고, 가시적인 영향으로 다루지 않는 것
- 시간 제한을 두고, 순환시키고, 산출물로 전환해야 함: 문서, 템플릿, 자동화 - 그리고 이를 성격 특성이 아닌 영향으로 읽기 가능하게 만들어야 함
- 귀중하지만 보이지 않는 것은 경력에 위험한 조합
모든 논쟁에서 이기면, 아마도 조용한 저항을 축적하고 있는 것
- 자신의 확신을 의심하는 법을 배웠으며, 너무 쉽게 "이길" 때는 보통 무언가 잘못됨
- 사람들이 당신과 싸우는 것을 멈추는 이유는 당신이 설득했기 때문이 아니라 포기했기 때문이며, 회의가 아닌 실행에서 그 불일치를 표현함
- 진정한 정렬은 더 오래 걸림 - 다른 관점을 실제로 이해하고, 피드백을 통합하고, 때로는 공개적으로 마음을 바꿔야 함
- 옳다는 단기적 느낌은 기꺼이 협력하는 동료들과 함께 무언가를 구축하는 장기적 현실보다 훨씬 가치가 적음
측정이 목표가 되면, 측정을 멈춤
- 관리에 노출하는 모든 지표는 결국 게임화되며, 악의가 아니라 인간이 측정되는 것을 최적화하기 때문
- 코드 라인을 추적하면 더 많은 라인을 얻고, 속도를 추적하면 부풀려진 추정치를 얻음
- 선임의 움직임: 모든 지표 요청에 쌍으로 응답함 - 하나는 속도용, 하나는 품질 또는 리스크용 - 그런 다음 임계값 숭배가 아닌 추세 해석을 주장함
- 목표는 통찰이지 감시가 아님
모르는 것을 인정하는 것이 아는 척하는 것보다 더 많은 안전을 창출함
- "모르겠습니다"라고 말하는 선임 엔지니어는 약함을 보이는 것이 아니라 허가를 창출함
- 리더가 불확실성을 인정하면 다른 사람들도 동일하게 할 수 있다는 신호이며, 대안은 모두가 이해하는 척하고 문제가 폭발할 때까지 숨겨지는 문화
- 가장 선임인 사람이 혼란을 인정하지 않는 팀과 그 피해를 목격함 - 질문이 나오지 않고, 가정이 도전받지 않으며, 주니어 엔지니어는 다른 모든 사람이 이해한다고 가정하기 때문에 침묵함
- 호기심을 모델링하면, 실제로 학습하는 팀을 얻음
네트워크는 당신이 가질 모든 직장보다 오래 지속됨
- 초기 경력에서 업무에 집중하고 네트워킹을 소홀히 했으며, 돌이켜보면 이는 실수였음
- 관계에 투자한 동료들 - 회사 안팎 - 은 수십 년간 혜택을 거둠
- 그들은 기회를 먼저 듣고, 더 빠르게 다리를 구축할 수 있었으며, 역할에 추천받고, 수년간 신뢰를 쌓은 사람들과 벤처를 공동 창업함
- 직장은 영원하지 않지만, 네트워크는 각 직장보다 오래 감 - 거래적 허슬이 아닌 호기심과 관대함으로 접근해야 함
- 떠날 때가 오면, 종종 관계가 문을 여는 것
대부분의 성능 향상은 영리함 추가가 아닌 작업 제거에서 나옴
- 시스템이 느려질 때 본능은 추가하는 것 - 캐싱 레이어, 병렬 처리, 더 똑똑한 알고리듬 - 때때로 이것이 맞지만, "계산하지 않아도 되는 것이 무엇인가?"를 묻는 것에서 더 많은 성능 향상을 목격함
- 불필요한 작업 삭제는 거의 항상 필요한 작업을 더 빠르게 하는 것보다 더 영향력이 있으며, 가장 빠른 코드는 실행되지 않는 코드
- 최적화 전에 작업이 존재해야 하는지 의문을 가져야 함
프로세스는 불확실성을 줄이기 위해 존재하며, 서류 흔적 생성을 위해서가 아님
- 최고의 프로세스는 조정을 더 쉽게 하고 실패를 더 저렴하게 만들며, 최악의 프로세스는 관료적 연극 - 도움이 아니라 잘못될 때 비난을 할당하기 위해 존재함
- 프로세스가 어떻게 리스크를 줄이거나 명확성을 높이는지 설명할 수 없다면, 아마도 그냥 오버헤드
- 사람들이 업무를 하는 것보다 업무 문서화에 더 많은 시간을 쓰고 있다면, 무언가 심각하게 잘못됨
결국 시간은 돈보다 가치가 있게 되며, 그에 따라 행동하라
- 초기 경력에서는 시간을 돈으로 교환하며, 이는 괜찮지만, 어느 시점에서 계산이 역전됨 - 시간이 재생 불가능한 자원임을 깨닫기 시작함
- 다음 승진 레벨을 쫓고, 보상의 몇 퍼센트 포인트를 더 최적화하며 번아웃되는 선임 엔지니어들을 목격함
- 일부는 얻었지만, 대부분은 나중에 포기한 것이 가치가 있었는지 의문을 가짐
- 답은 "열심히 일하지 말라"가 아니라 "무엇을 교환하고 있는지 알고, 의도적으로 교환하라"
지름길은 없지만, 복리는 있음
- 전문성은 의도적 연습에서 나옴 - 현재 기술을 약간 넘어서서 밀어붙이고, 성찰하고, 반복함 - 수년간 - 압축 버전은 없음
- 희망적인 부분: 학습은 새로운 선택지를 창출할 때 복리로 작용하며, 새로운 사소한 지식만이 아님
- 글을 쓰되 - 참여가 아니라 명확성을 위해 - 재사용 가능한 원시 요소를 구축하고, 상처 조직을 플레이북으로 수집함
- 경력을 복리 이자로 취급하는 엔지니어가 복권 티켓으로 취급하는 엔지니어보다 훨씬 앞서 나가는 경향
최종 생각
- 21가지 교훈은 많아 보이지만, 실제로는 몇 가지 핵심 아이디어로 귀결됨: 호기심을 유지하고, 겸손함을 유지하고, 업무는 항상 사람에 관한 것임 - 구축하는 사용자와 함께 구축하는 팀원 - 엔지니어링 경력은 많은 실수를 하고도 앞서 나갈 만큼 충분히 길며, 가장 존경하는 엔지니어들은 모든 것을 올바르게 한 사람이 아니라 잘못된 것에서 배우고, 발견한 것을 공유하고, 계속 나타난 사람들 - 여정 초기라면 시간이 지나면서 더 풍부해진다는 것을 알고, 깊이 있다면 이 중 일부가 공감되기를 희망함
- 조직 내 정보 필터링 구조로 인해 경영진은 엔지니어들의 불만을 퇴사 통보 후에야 알게 되며, 이미 수개월 전에 결정된 퇴사를 되돌리기엔 너무 늦음 - 엔지니어들이 퇴사하는 진짜 이유는 연봉이 아니라 기술적 판단이 무시되는 경험, 갚을 수 없는 기술 부채, 의미 없는 업무에 배치되는 것 - 중간 관리자들은 문제를 자신의 단계에서 해결하려 하며, 이를 전문성으로 인식하지만 실제로는 정보 억압으로 기능함 - 스킵 레벨 대화(경영진이 하위 직급 엔지니어와 직접 대화)는 조직 건강을 해친다는 명목으로 기피되지만, 실제로는 중간 관리자를 책임에서 보호하는 역할임 - 시니어 엔지니어 한 명 교체 비용은 $275,000~$395,000에 달하며, 주 몇 시간의 스킵 레벨 대화 비용($50,000/년)보다 훨씬 큼 - 조직이 초기에 스킵레벨, 외부 진단, 실제 문제 해결에 투자하면 수억 원대 교체 비용을 줄일 수 있고, 그러지 못한 회사는 계속 이유를 모른 채 좋은 엔지니어를 잃게 됨
서론: 한 시니어 엔지니어의 이탈과 1.4M 달러 손실
- 연 4,000만 달러 ARR SaaS 회사에서, 시니어 엔지니어가 확장 불가능한 DB 아키텍처를 6개월간 반대했으나, 제품 조직의 “빨리 출시하고, 나중에 리팩터링 하자”는 결정이 그대로 진행됨 - 엔지니어링 리더십은 그가 옳다고 보면서도 제품 팀에 맞서 밀어붙이지 않았음 - 그는 기술 결정 자체가 아니라, 자신의 판단이 의미 없다는 사실 때문에 그 주에 바로 면접을 보기 시작했음 - 8개월 뒤 시스템은 매일 성능 문제를 겪었고, 18개월 뒤에는 시니어 5명이 회사를 떠났으며, 회사는 왜 이런 일이 벌어지는지 파악하기 위해 fractional CTO를 고용함 - 진단 결과, 임원진은 엔지니어들이 불행하다는 사실을 퇴사 이메일이 오기 전까지 전혀 모르고 있었음 - 퇴사 인터뷰에는 “더 나은 기회”, “더 경쟁력 있는 보상”만 표면적으로 기록됨 - CEO는 남은 엔지니어 연봉을 15% 인상했지만, 그 후에도 이탈은 계속 이어졌음 - 시니어 5명을 교체하는 데 들어간 비용은 채용, 생산성 손실, 지식 유실까지 합쳐 약 140만 달러 수준으로 추산됨 - 이 문제는 보상이 아니라 정보 흐름의 실패에서 비롯되었고, “위로 올라가는 정보가 걸러지는 계층 구조” 가 핵심 원인임
Hierarchies filter bad news out — 계층 구조는 나쁜 소식을 지워버리는 필터
- 조직은 복잡성을 다루기 위해 계층 구조와 관리 레이어를 도입하지만, 그 효과로 정보가 각 레이어에서 걸러지는 구조가 생김 - 주니어가 “문제 있어 보인다”고 말하면, 시니어가 이를 정제해 매니저에게 올리고, 매니저는 “보고할 만한 일인지, 본인에게 불리한지”를 먼저 평가함 - VP→CTO→CEO로 올라갈수록, 원래 문제의 세부 정보와 긴박감이 하나씩 사라짐 - 이 필터링은 악의적이라기보다, 중간관리자가 “자기 레벨에서 문제를 처리하는 것”을 책임이라고 믿는 문화에서 발생함 - “문제를 올리는 것 = 실패”로 간주되고, “해결책만 들고 올라가는 것”이 프로페셔널함으로 인식됨 - 결과적으로, 이는 문제를 숨기는 메커니즘으로 작동함 - 한 120명 규모 엔지니어 조직의 사례에서는, 프론트엔드 팀이 3월에 새 대시보드 성능 문제를 발견해 코드 리뷰에서 공개적으로 우려를 표했음 - 5월에 매니저가 해결 방안을 검토했고, 6월에 VP에게는 “대시보드 성능 최적화 진행 중” 정도로 전달됨 - 7월에 CTO는 “약간의 성능 작업”이 있다는 수준만 들었고, 8월에서야 최대 고객이 대시보드가 못 쓸 정도라고 공식 항의를 하면서 임원진에게 ‘갑작스러운’ 위기처럼 인지됨 - 실제로는 엔지니어들은 5개월간 문제를 알고 있었고, 자원을 배분해야 할 임원진은 항상 수개월 늦은, 희석된 정보로 의사결정을 하고 있었음 - 이 구조에서, 엔지니어는 8월에 DB가 안 버틴다는 걸 알고, 매니저는 10월에 불만을 알고, VP는 12월에 사기 저하를 인지하고, CTO는 2월에 대량 퇴사를 보게 되는 정보 지연 사슬이 반복됨
The convenient fiction of chain of command — ‘보고 라인’이라는 편리한 허구
- 많은 조직이 스킵레벨(임원이 엔지니어와 직접 대화) 을 “체계를 깨는 행동”으로 금기시함 - 중간관리 권위 약화, 불신 신호, 마이크로 매니지먼트라는 이유가 자주 동원됨 - 겉으로는 조직 건강을 위한 고려처럼 보이지만, 실제로는 중간관리층이 책임과 검증에서 자신을 보호하는 장치로 작동함 - CTO가 엔지니어와 직접 이야기하는 경우, 실제로 현장에서 어떤 일이 벌어지는지 알 수 있음 - 반대로, 관리 레이어를 거친 보고서만 보는 CTO는 관리자가 보여주고 싶은 버전의 현실만 보게 됨 - 스킵레벨 금기는 후자를 보장하는 메커니즘이 됨 - “임원 시간은 비싸니, 전략에만 집중해야 한다”는 논리는, 전략이 사실과 다른 정보 위에 세워지기 시작하는 순간 무너짐 - CTO가 매주 몇 시간만 투자해도, 무엇이 실제로 막히고 있는지, 누가 마음이 떠나고 있는지, 어느 기술 베팅이 실패 중인지 직접 들을 수 있음 - 계층을 3–4단계 거친 보고서에 의존하는 편이 시간당 비용은 싸게 보이지만, 잘못된 큰 결정을 반복적으로 낳는 훨씬 비싼 선택이 됨 - 스킵레벨에 쓰는 시간은 많을 필요는 없고, 일관된 패턴과 전체 커버리지만 확보하면 됨 - 조직이 커질수록 한 사람과 대화하는 주기는 길어지지만, CTO가 분기마다 한 번이라도 모든 엔지니어와 직접 이야기하는 구조를 유지할 수 있음 - 이런 직접 대화에서 엔지니어는 매니저에게는 절대 말하지 않을 문제를 이야기하고, 정식 라인보다 3–6개월 빠른 조기 경고가 확보됨 - 한 결제 회사 사례에서, 새로운 CTO가 매주 30분 오피스 아워를 열어 누구나 매니저 허락 없이 예약할 수 있게 했을 때, - 배포 시스템이 불안정해 금요일 배포를 피하는 문화, 거짓 경보가 너무 많아 아무도 믿지 않는 모니터링, API 문서 노후화로 온보딩 한 달이 모두 시행착오로 소비되는 문제가 드러났음 - 각 매니저는 “자기 레벨에서 처리 중”이라며 위로 올리지 않았던 내용이었고, CTO는 분기 안에 세 가지 문제를 모두 해결하도록 예산을 배정했으며, 6개월 뒤 자발적 이직률이 거의 0에 가까워지는 변화가 나타났음
Agency, not salary — 떠나는 이유는 보상이 아니라 ‘에이전시’ 상실
- 엔지니어 이직 사유는 퇴사 인터뷰에서 자주 “보상”으로 포장되지만, 실제 패턴은 더 미묘하고 말하기 난감한 요인에서 출발하는 경우가 많음 1. 첫 번째 패턴은 에이전시 상실임 - 엔지니어가 분명히 실패할 것이라 아는 시스템을 만들도록 요구받고, 비기술적 이유로 판단이 지속적으로 뒤집히는 상태임 - 예측한 실패가 현실이 되었을 때, “왜 막지 않았느냐”는 책임까지 떠안는 구조에서 전문가로서의 판단이 아무 의미 없다는 감각이 누적됨 - 한 핀테크 회사는 이미 검증된 인증 솔루션을 쓰지 않고 직접 구현하기로 했고, 시니어들은 위험과 비핵심 영역이라는 점을 들어 반대했음 - 제품 쪽은 특정 UX 플로우를 위해 커스텀 구현을 강하게 밀었고, 엔지니어링 리더십은 시니어들 의견에 동의했으나 끝내 제동을 걸지 못했음 - 결과적으로 커스텀 인증 시스템은 첫 달에 보안 취약점 3건, 긴급 패치, 6개월 치 개발 리소스를 소모했고, 해당 시니어는 결정이 확정된 주에 바로 이직 준비를 시작했음 - 비용을 숫자로 보면, 커스텀 인증에 18만 달러를 쓰는 동안, 사서 쓸 수 있는 솔루션은 연 1.2만 달러였음 - 그 엔지니어가 남아 있었다면, 로드맵 기준 연 40만 달러 ARR를 창출할 기능에 쓸 수 있었고, - 이 결정으로만 최소 58만 달러가 1년 차에 날아간 셈임 2. 두 번째 패턴은 갚을 수 없는 수준까지 미뤄진 기술적 부채임 - DB 복제, 배포 자동화, 모니터링 개선 같은 핵심 인프라 작업이 매 분기 기능 개발 뒤로 밀리며, - 엔지니어는 언제 어디서, 무엇이 깨질지를 거의 정확히 알고 있음에도 계속 막히는 것을 지켜보는 상황임 - 한 이커머스 회사는 18개월 동안 DB 인프라 작업을 계속 연기했고, 그 사이 트래픽은 연 40%씩 늘어났으나 인프라는 그대로였음 - 19개월 차에 DB가 전체 플랫폼의 병목이 되어, 피크 타임 응답 시간이 200ms에서 4초까지 늘어났고, 전환율 하락으로 120만 달러 수준의 매출 손실과 24만 달러의 긴급 인프라 비용이 발생함 - 인프라 작업을 가장 강하게 요청했던 시니어 3명 중 2명은 이미 떠난 상태였음 3. 세 번째 패턴은 똑똑한 사람에게 멍청한 일을 시키는 구조임 - 연 18만~19만 달러를 받는 시니어에게, 이미 폐기해야 할 시스템 유지보수, 의미 없는 반복 작업, 아무도 믿지 않고 아무도 읽지 않는 문서와 추정 회의를 맡기는 상황임 - 한 SaaS 회사에서는 6년 된 레거시 리포팅 시스템이 1년에 8만 달러 매출을 내고 있었는데, 시니어 한 명(연 19만 달러)이 시간의 60%를 이 시스템 유지에 쓰고 있었음 - 회사는 사실상 연 11.4만 달러를 8만 달러 매출을 위해 태우는 구조였고, 엔지니어는 고객 12명을 신규 플랫폼으로 옮기자고 제안했지만 “전략적 고객”이라는 이유로 거절당했음 - 그녀는 3개월 뒤 퇴사했고, 교체 비용은 리크루팅과 온보딩까지 22만 달러에 달했으며, 고객 마이그레이션은 4만 달러 정도면 끝낼 수 있었던 작업이었음
The early signals executives miss — 임원이 보지 못하는 ‘조기 경고’
- 경영진이 사표를 받기 전까지 못 보는 신호들은 6–12개월 전부터 이미 다른 레벨에서 뚜렷하게 나타남 1. 주니어/미들 엔지니어가 먼저 보는 신호는 시니어의 싸움 포기임 - 시니어가 아키텍처 리뷰에서 더 이상 강하게 의견을 내지 않고, 리뷰는 형식적인 통과 절차가 됨 - 백로그의 기술 작업은 계속 쌓이는데, 배정은 거의 이루어지지 않고, “이건 해봤는데 위에서 안 된다더라”는 말이 빈번해짐 - 한 물류 회사의 주니어 엔지니어는 6개월 동안 이런 변화를 관찰했음 - 과거에는 상세한 코드 리뷰를 하던 아키텍트가 이제 대부분 “LGTM” 한 줄로 승인하기 시작했고, - 비공식 대화에서 “어차피 내 의견은 결과를 못 바꾸니 그냥 시간을 아끼기로 했다”는 말을 들었을 때, 이 시니어가 곧 떠날 거라는 사실을 먼저 깨달았음 - 3개월 뒤 실제로 퇴사가 이뤄졌고, 매니저는 전혀 예상하지 못했다고 느꼈음 2. 시니어 본인이 경험하는 단계는 4–8개월 전부터 나타나는 패턴 인식과 도덕적 피로감임 - “이건 실패할 거고, 리더십은 듣지 않을 거다”라는 확신, 옳지 않은 것을 만들게 되는 도덕적 상처, “내 전문성이 이곳에서는 아무 의미 없다”는 감정임 - 외형상으로는 회의에서 덜 싸우고, 더 협조적으로 보이기 때문에, 리더의 눈에는 오히려 “성숙해진 것처럼” 보일 수 있음 3. 매니저가 보는 신호는 2–4개월 전의 미묘한 행동 변화임 - 1:1에서 참여도가 떨어지고, 팀 토론에서 발언이 줄고, - LinkedIn을 업데이트하고, 업계 행사에 더 자주 나가고, 문서화가 갑자기 매우 꼼꼼해지고, 주니어에게 자신의 시스템을 열심히 가르치기 시작함 - 이때 많은 매니저는 높은 이직률이 본인에게 불리하다고 느껴, 상부 보고 대신 조용히 해결해보려다 이미 오퍼를 받은 뒤에야 사태를 인정하게 됨 - 한 미디어 회사의 매니저는, 어떤 시니어가 갑자기 모든 것을 문서화하기 시작한 것을 “드디어 지식 공유를 실천한다”고 긍정적으로만 봤지만, 실제론 떠나면서 지식 공백에 대한 죄책감 때문에 남기는 기록이었고, 이를 깨달은 건 퇴사 이후였음 4. 임원이 보는 것은 0–1개월 전에야 도착하는 퇴사 통보뿐이고, 그 전 단계에 쌓인 신호들은 계층 구조 속에서 모두 흩어졌던 셈임
Why one departure becomes five — 한 명의 이탈이 다섯 명의 이탈로 번지는 구조
- 한 명의 퇴사는 하나의 데이터 포인트지만, 세 명이 연달아 나가면, 남은 사람들은 “뭔가 있다”고 해석하기 시작함 - 특히 존경받던 동료가 떠나면, 남은 사람은 “저 사람이 보는 뭔가를 나는 못 보고 있는 건 아닐까”를 생각하게 됨 - 외부 리크루터도 이 패턴을 빠르게 감지함 - 같은 팀 출신 엔지니어들이 LinkedIn 검색에서 자주 보이고, 프로필 업데이트가 몰리면, 해당 팀을 집중 공략 대상으로 삼게 됨 - 이직 생각이 없던 엔지니어들도 연락을 받으며 면접을 보게 되고, 그 중 일부는 더 나은 기회를 실제로 발견함 - 한 클라우드 인프라 회사는 시니어 두 명이 3주 간격으로 떠난 뒤, 다음 3개월 동안 추가로 다섯 명을 더 잃었음 - 내부 회고 결과, 첫 두 명의 이탈이 “회사 재무 상태에 이상이 있는 것 아니냐”는 정보 공백에서 오는 불안을 증폭시켰고, - 실제 이유는 앞서 이야기한 에이전시 상실과 기술 부채 문제였지만, 남은 이들이 “내가 모르는 뭔가를 떠난 사람들이 안다”고 추측하는 사이 리크루터가 이 틈을 적극 활용했음 - 지식 유실 비용은 숫자로 잡기 어렵지만, 이후 분기마다 나오는 실수와 지연, 재작업으로 드러남 - 떠난 시니어는 “어떤 3줄의 코드는 건들면 안 되고, 어떤 3,000줄은 없애도 된다”는 감각을 갖고 있었고, - 어떤 고객이 왜 특수한 요구사항을 갖는지, 어떤 기술 부채가 “보기만 나쁜지” vs “실제로 위험한지”를 알고 있었음 - 한 결제 회사 사례에서는, 정산 시스템을 만든 시니어가 퇴사한 뒤, 새 엔지니어가 코드를 수정하면서 어느 결제사 API의 undocumented한 특이 케이스를 몰라 특정 거래 유형이 모두 실패하는 문제가 발생했음 - 이 버그를 찾는 데 2주가 걸렸고, 엔지니어링 비용 약 4.5만 달러, 실패한 거래를 수동으로 맞추는 동안 18만 달러 규모의 문제가 발생했으며, - 원래 시니어는 이 API의 버그를 시행착오로 발견해 머릿속에만 기억하고 있었음
Sometimes it really is the money — 진짜로 보상인 경우와 ‘핑계로서의 보상’ 구분
- 보상이 실제 원인인 경우도 존재하며, 타이밍 패턴이 다름 - 시장 대비 명확히 낮은 연봉, 늘어난 책임에 맞지 않는 보상, 신규 입사자가 본인과 같은 연봉을 받는 구조가 계속될 때, - 이직 전 직접적으로 보상 문제를 먼저 꺼내는 경우는 보상 이슈로 해결 가능한 영역임 - 반대로, 퇴사 인터뷰에서만 “보상”이 등장하고, 이미 몇 달 전부터 조용히 면접을 보고 있던 경우, 보상은 동기가 아니라 정당화 수단인 경우가 많음 - 새로운 오퍼가 30% 높아서 “시장 수준”을 말하지만, 매칭 제안을 해도 “이미 다른 곳을 수락했다”라며 미적지근하게 반응하는 패턴임 - 이런 경우 실제 떠나는 이유는 앞서 말한 에이전시, 기술 부채, 무의미한 업무에 대한 결론임 - 이 글에서 제안하는 간단한 테스트는 “20% 인상으로 붙잡을 수 있는가” 임 - “그 정도면 고민해 보겠다”라면 보상이 주된 이슈일 가능성이 크고, - 그럼에도 이미 마음이 떠난 상태라면, 환경이 망가졌다고 판단한 상태라서 돈만으로는 해결이 안 되는 상황임 - 한 개발자 도구 회사는 보상을 이유로 떠난 8명을 자세히 분석했고, - 이 중 꼭 붙잡고 싶은 5명에게 매칭 이상의 카운터 오퍼를 했지만 3명이 거절했음 - 이후 대화를 통해, 그들이 떠난 이유가 계속 바뀌는 로드맵과 의미 없어진 작업이었고, “회사 방향을 더 이상 믿을 수 없다”는 감각이었음 - 퇴사 인터뷰에서는 “보상”만 언급했지만, 실제 문제는 일 자체의 의미 상실이었음
Prevention beats retention bonuses — 사후 보너스보다 ‘조기 개입’이 훨씬 싸다
- 조기 개입을 위해서는, 계층 필터를 우회하는 정보 채널이 필요하며, 몇 가지 방법이 반복해서 효과를 보이는 패턴임 - 첫 번째는 정기적인 스킵레벨 대화임 - 매주 몇 시간만 엔지니어 전 레벨과 직접 대화에 쓰면, 정식 라인에서는 올라오지 않는 실제 생산성 장애물, 문제되는 기술 결정, 떨어지는 사기 지점을 들을 수 있음 - 조직이 커지면 한 사람과의 빈도는 줄이되, 전체 커버리지를 유지하는 설계가 중요함 - 한 100명 규모 엔지니어 조직의 CTO는 매주 4시간을 스킵레벨에 쓰며, - 30분씩 2주 회전으로 한 달 약 30명, 7개월이면 조직 전체를 한 바퀴 도는 구조를 만들었음 - 일정이 항상 열려 있어 엔지니어가 필요할 때 예약할 수 있었고, 그 결과 자발적 이직률이 연 18%에서 7%로 감소했으며, CTO는 이를 “문제가 작고 고칠 수 있을 때 듣게 된 덕분”이라고 인식함 - 두 번째는 외부 진단 관점임 - 리포트라인에 속하지 않고, 인사 권한이 없는 fractional CTO나 외부 어드바이저가 인터뷰를 하면, 사람들은 훨씬 솔직하게 말하는 경향이 있음 - 내부 임원도 같은 질문을 할 수 있지만, 답이 달라지는 이유는 ‘답변자가 느끼는 위험’ 차이임 - 한 SaaS 회사는 6개월 동안 시니어 4명을 잃은 뒤 fractional CTO를 투입해 전 레벨 인터뷰를 진행했고, - 엔지니어들이 느끼는 핵심 문제는 “아키텍처 리뷰가 실제 결정을 하는 장이 아니라, 나중에 책임을 돌리기 위한 연극처럼 느껴진다”는 점이었음 - 리뷰 요구사항을 다 반영해 통과해도, 몇 주 뒤 제품 결정으로 다시 뒤집히는 일이 반복되었고, - 회사는 이 프로세스를 없애고, 기술 구현에 대해 엔지니어링에 실질적인 거부권을 부여했음 - 세 번째는 적어도 하나는 실제로 고치는 것임 - 이야기만 듣고 아무 변화가 없으면 “말해도 소용없다”는 학습이 이루어지고, - 한 가지라도 눈에 보이게 고치면 “말하면 바뀐다”는 신호가 조직 전체에 퍼짐 - 한 헬스케어 기술 회사에서, 개발자가 CTO와 스킵레벨에서 테스트가 45분 걸려 개발 속도가 느리다고 말했을 때, - CTO는 “왜 아직도 안 고쳤는지”를 물었고, 개발자는 여러 차례 매니저에게 이야기했지만 매번 후순위가 됐다고 답했음 - CTO는 즉시 2주 작업 시간을 배정했고, 테스트 시간을 8분으로 줄이는 데 성공했으며, - 이 경험이 입소문을 타며, 다른 엔지니어들도 스킵레벨에서 문제를 가져오기 시작했음 - 비용은 약 1.2만 달러의 엔지니어 시간이었지만, “말하면 바뀐다”는 신호 가치가 훨씬 컸음
The $1.4m misdiagnosis — 잘못된 진단이 낳는 140만 달러짜리 오판
- 시니어 한 명을 교체하는 데 드는 보수적인 비용 추산은 27.5만~39.5만 달러 수준임 - 리크루팅 비용: 연봉의 20–25% 수준 - 공석 기간 생산성 손실: 3–6개월 동안 연 15만 달러 생산성 기준 4만~7.5만 달러 - 온보딩 기간 반쪽짜리 생산성: 6개월 동안 50% 효율로 일하는 손실분 3.5만~4만 달러 - 여기에 정량화하기 어려운 지식 손실, 의사결정 지연, 재작업이 뒤따름 - 시니어 5명을 잃으면 1.4~2.0M 달러 규모의 손실이 발생하는 셈이며, 앞서 사례 회사의 비용 추산과 맞물림 - 반대로, 실제 문제를 고치는 비용은 훨씬 작지만, 조직 구조와 정치에 손을 대야 한다는 부담이 있음 - 기능 몇 개를 미루고, 불필요한 프로세스를 제거하고, 기술 결정을 엔지니어에게 넘기는 대신, - 많은 조직은 “엔지니어는 원래 비싸고, 시장 경쟁이 치열하다”는 설명을 선호함 - 이 설명은 내부 변화를 요구하지 않기 때문에 편하지만, 실제 원인(정보 구조, 결정 방식)을 가리는 역할을 함 - 한 Series B 회사는 18개월 동안 엔지니어 7명을 잃으면서, CEO는 “경쟁사가 더 많이 준다”고 생각했지만, - 사후 분석 결과, 이들 중 5명은 떠나기 6개월 전 구체적인 기술 결정, 프로세스 부담, 우선순위 문제를 매니저에게 이야기했었음 - 이 이슈들은 1:1 메모에 “모니터링 중” 정도로만 기록되고, 어느 레벨에서도 임원에게 올라가지 않았음 - 그 결과, 임원은 “보상 문제”라고 믿었고, 엔지니어들은 “내 의견은 중요하지 않다”고 결론 내린, 서로 완전히 다른 현실을 살고 있었음
Information is cheaper than replacement — 정보 확보는 교체보다 압도적으로 싸다
- 떠나는 엔지니어들은 임원들이 모르는 사실을 알고 있음 - 어떤 기술 결정이 실패하고 있는지, 어느 프로세스가 시간을 낭비하는지, 어떤 관리 방식이 사람을 지치게 하는지에 대한 구체적인 정보임 - 이 정보는 조직 안에 항상 존재하지만, 계층 필터와 중간관리 인센티브 때문에 임원 레벨까지 올라오지 못함 - 핵심 질문은 “퇴사 전에 이 정보를 들을 것인가, 아니면 그들이 막았을 문제를 사고로 겪고 나서야 배울 것인가”임 - 이를 잘 하는 조직은 정보 흐름을 전략적 자산으로 보고, 스킵레벨 채널을 공식적으로 설계하고, - 필터링된 보고서보다 현장으로부터 직접 얻는 ‘그라운드 트루스’에 더 높은 가치를 두는 구조를 갖춤 - 이런 조직에서는, 임원 시간이 잘못된 전략 회의에 쓰이는 것보다, 매주 몇 시간이라도 현장 이야기를 듣는 데 쓰일 때 ROI가 더 크다는 사실을 인정함 시니어 한 명의 이직만 막아도, 연간 수만~수십만 달러 수준의 임원 시간 투자를 다섯 배 이상 회수하는 계산이 나옴 - 반대로, 이걸 잘못 다루는 조직은 관리자의 편안함을 정보 정확도보다 우선시함 - 스킵레벨을 금기시하고, 나쁜 소식이 제거된 보고서에 의존하며, - 이직 문제를 사표에서야 인지하고, 수백만 달러를 들여 사람을 교체하면서도 “왜 최고의 사람들이 떠나는지”를 끝내 이해하지 못함 - 맨 처음 사례의 시니어 엔지니어는 지금 기술 아키텍처에 대해 엔지니어링에 거부권이 있고, CTO가 정기적으로 스킵레벨을 유지하는 회사에서 일하고 있음 - 그도, 동료들도 이직 준비를 하지 않고 있고, 회사의 자발적 이직률은 같은 단계 회사 평균의 절반 이하인 12% 수준임 - 이 회사 임원들은 “무너질 수 없을 만큼 늦기 전에” 무엇이 망가졌는지 듣고 있고, 이는 단순한 메커니즘, 즉 꾸준히 묻고, 말할 수 있는 구조를 유지하는 것으로 만들어진 결과임
- 시니어 엔지니어 이탈 문제는 정보 흐름이 아닌 경영진 인센티브 구조의 문제이며, 분기별 성과에 최적화된 보상 체계가 장기 투자를 요하는 인재 유지와 근본적으로 충돌 - 시니어 엔지니어 1명 이탈 시 총비용은 50만~100만 달러에 달하며, 채용비, 공석 비용, 온보딩, 부족 지식(tribal knowledge) 손실 등이 여러 예산에 분산되어 보이지 않음 - 14개월 전 경고를 무시한 결제 처리 회사가 블랙프라이데이에 347만 달러 손실을 입은 사례에서, 원래 수정 비용은 8만 달러에 불과했음 - 6가지 구조적 개입(이탈비용 회계, 사고 추적, 경영진 온콜, 보상에 유지율 반영, 기술자문위원회, IC 트랙 동등 보상)이 인센티브를 재정렬하는 해결책으로 제시 - 이러한 개입은 경영진이 유지율을 경제적 문제로 인식하고 구조적 변화를 수용할 의지가 있을 때만 효과적이며, 형식적 시행은 오히려 역효과 초래
정보가 흘러도 행동이 바뀌지 않는 이유
"The constraint is not information flow. It is economics."
- 이 글은 엔지니어 이탈을 다룬 연작의 2편으로, 1편 왜 당신의 최고 엔지니어들이 다른 곳에 면접을 보고 있을까에서 다룬 정보 비대칭 문제 이후의 상황을 이어서 다룸 - 1편에서는 시니어 엔지니어가 왜 떠나는지 설명했으며, 핵심 원인은 문제가 존재해도 경영진에게 도달하지 않는 구조였음 - 하지만 이 글은 그 가정을 한 단계 더 밀어붙임 - 정보 흐름을 실제로 개선했을 때 어떤 일이 벌어지는 지를 다룸 - 결론은 직관과 다르게, 아무것도 바뀌지 않는 경우가 대부분이라는 점임 - 조직은 문제를 인지하기 위해 여러 장치를 도입함 - 스킵 레벨 1:1 미팅 도입 - 익명 피드백 채널 운영 - 외부 컨설턴트를 통한 리텐션 설문 진행 - 그 결과 엔지니어들은 매우 명확하게 문제를 전달함 - 기술 부채가 사기를 갉아먹고 있음 - 아키텍처 결정에서 전문성이 무시되고 있음 - 온콜 부담이 지속 가능하지 않은 수준임 - 경영진은 이를 듣고 고개를 끄덕임 - 문제를 인정함 - 우선순위를 조정하겠다고 말함 - 그러나 분기가 바뀌면 의사결정은 이전과 동일하게 반복됨 - 동일한 방식으로 분기 목표를 달성함 - 그리고 그 방식은 방금 들은 문제들을 다시 무시하는 것임 - 이 지점에서 글은 핵심을 분명히 함 - 문제는 정보 부족이 아님 - 문제는 경제적 구조, 즉 인센티브 설계임
핵심 문제: 임원의 인센티브 구조
- VP of Engineering이 10월에 직면한 의사결정 계산 사례 - 분기 성과 검토 3개월 전이고 엔지니어의 주식 베스팅까지는 6개월 남음 - 한 명의 시니어 플랫폼 엔지니어가 다음과 같이 요청함 - 인증 시스템을 6주간 리팩터링하고 싶다는 것 - 기술 부채가 누적되어 있고 구조가 취약해짐 - 보안 연구자 두 명이 이미 위험 신호를 전달했음 - 하지만 현재 상태는 애매함 - 실제 장애는 없고, 고객 불만도 없고, 매출 영향도 없음 - 존재한다는 것은 “지금 고치지 않으면 위기가 된다”는 엔지니어의 경고뿐임 - VP에게는 두 가지 선택지가 존재함 - 선택지 A: 리팩터링 승인 - 6주간 기능 개발 속도 감소 감수 - 분기 OKR 미달 가능성 발생 - CEO에게 “고객이 보지 못하는 기술 작업” 때문에 로드맵이 지연된 이유를 설명해야 함 - 이미 세일즈 팀이 약속한 기능 출시 일정이 흔들릴 위험 - 결과적으로 연말 보너스에 직접적 악영향 가능성 존재 - 이 선택의 보상은 12~18개월 뒤에 받음 : 해당 시니어 엔지니어가 “기술 판단이 존중된다” 는 이유로 조직에 남는 것 - 선택지 B: 기능 우선 결정 - 기술 부채를 “중요하다”고 인정하되 “다음 분기”로 미룸 - 예정된 로드맵을 그대로 출시하여 OKR 달성하고, 보너스 수령 - 시니어 엔지니어는 당장은 남아 있음. 스톡 옵션이 아직 베스팅되지 않았기 때문 - 인증 시스템이 나중에 터지면 그것은 미래 분기의 문제 - 엔지니어가 6개월 뒤 떠나면 채용으로 대체 가능하다고 판단 - 이 구조에서 선택지 B가 항상 이김 - 결국 실패할 때까지 - 제품 출시 중 핵심 시스템 장애가 발생하고, 18개월 사이 시니어 엔지니어 5명 이탈하며, CFO가 “왜 재채용 비용으로 매년 140만 달러를 쓰고 있는가”를 묻기 시작할때까지 B가 이김 - 근본적 불일치 이기 때문 - 임원 보상 구조는 분기 단위 성과에 최적화되어 있음 - 하지만, 엔지니어 유지와 기술 부채 해소는 장기 투자를 요구함 - 정보 흐름 개선만으로는 이 간극을 메울 수 없음 - 경제적 구조 자체의 재설계가 해결책
Why the Math Favors Dysfunction - 계산해보면 장애가 나는게 당연함
- 숨겨진 비용은 눈에 보이지 않는 방식으로 작용하여 합리적인 행위자들이 비합리적으로 행동하게 만듦 - 연봉 $200,000 수준의 시니어 엔지니어 1명이 떠날 경우 실제 총비용은 $500,000 ~ $1,000,000 이상으로 계산됨 - 대부분의 경영진은 이 수치를 듣고 과장된 것이라고 생각하지만 그렇지 않음. 계산 방법은 다음과 같음 - 직접 대체 비용: $85,000-$100,000 - 채용 수수료: 외부 리크루터 수수료 20-25% 로 20만 달러 엔지니어의 경우 $40,000-$50,000 - 내부 채용(구인 게시판, 소싱 도구, 리크루터 급여) 자체 처리 시 $15,000-$20,000 - 사이닝 보너스: 경쟁 시장에서는 시니어 후보 확보에 $20,000-$40,000 필요 - 특히 그들의 현재 회사에 지분을 남겨두고 옮길 때는 필수 - 이사 비용: 해당 시 국내 이사라면 $10,000-$30,000, 해외는 더 높음 - 공석(Vacancy) 비용: $50,000-$100,000 - 시니어 엔지니어 채용까지 평균 3-6개월 소요 - 공석 기간 동안 해당 엔지니어의 업무는 중단되지 않고 두 가지 비용이 동시에 발생함 - 하나는 업무 재분배로 인해 팀 생산성이 저하되는 것이고, 다른 하나는 업무 포기로 인해 기회비용이 발생하는 것 - 업무 재분배 비용 $25,000-$40,000: - 떠난 엔지니어 업무의 약 60% 가 남은 팀원에게 분산 - 업무 자원의 자유로운 재배치가 아니라 생산성 저하로 이어짐 - 이미 업무량이 포화 상태인 엔지니어들은 이제 익숙하지 않은 영역의 코드 리뷰를 처리하고, 자신이 개발하지 않은 시스템에 대한 질문에 답하며, 완전히 이해하지 못하는 서비스를 유지 관리해야함 - 엔지니어 3명이 각각 20% 추가 업무 흡수 시 단순히 20% 더 일하는 것이 아니라 컨텍스트 전환으로 전체 효율 감소 - 공석 기간 동안 엔지니어당 10-15% 생산성 손실을 초래 - 업무 재분배 비용 계산 - 업무를 흡수하는 엔지니어 수 × 생산성 감소율 × 공석 기간(개월) × (평균 연봉 / 12) - 일반적인 시나리오에서는 3명의 엔지니어 × 12% 생산성 감소 × 4개월 × ($180,000 / 12) = $21,600 - 이탈한 엔지니어가 인프라·보안·플랫폼처럼 전문성이 높은 영역을 담당했을 경우 $30,000–$40,000 수준까지 상승 - 업무 포기 비용 $25,000-$60,000: - 나머지 40%는 재분배되지 않고 이연 또는 완전 포기 - 플랫폼 개선, 기술 부채 감소, 아키텍처 진화, 문서화, 멘토링 등 기능 출시와 무관하지만 미래 위기 예방 업무인데 조용히 로드맵에서 제외됨 - 업무 포기(Work Abandonment)의 즉각적인 비용은 수행되지 않은 작업의 급여 환산 가치로 계산됨 - 이탈한 엔지니어 업무의 40% 가 공석 기간 동안 수행되지 않음 - 계산식은 40% × 4개월 × ($200,000 / 12) = $26,667 - 하지만 진짜 비용은 즉각적으로 끝나지 않음 - 미뤄진 작업은 이후 분기들에 걸쳐 누적 비용을 만들어냄 - 예를 들어 - 시니어 인프라 엔지니어가 계획했던 데이터베이스 최적화가 연기되면 - 쿼리 성능이 점진적으로 저하되고 - 결국 원래 작업 범위를 훨씬 넘는 긴급 대응이 필요해짐 - 해당 엔지니어가 담당하던 아키텍처 리뷰가 중단되면 - 비용이 큰 실수를 사전에 걸러낼 수 있는 전문성이 사라진 상태에서 - 기술적 의사결정이 진행됨 - 측정 가능한 업무 포기 비용은 - “원래 했어야 했지만 하지 않은 작업”의 가치임 - 보수적인 계산식은 다음과 같음 - (포기된 업무 비율 × 연봉 / 12) × 공석 개월 수 (40% × $200,000 / 12) × 4개월 = $26,667 - 현실적인 업무 포기 비용 범위는 $25,000–$60,000 - 포기된 작업이 예방적인지 기능 중심적인지 비중에 따라 달라짐 - 총 공석 비용(Combined Vacancy Cost): $50,000–$100,000 - 업무 재분배 비용 $25,000–$40,000 + 업무 포기 비용 $25,000–$60,000 두 항목을 합산한 결과임 - 이는 4개월간 자리가 비어 있는 상태에서 발생하는 직접적이고 측정 가능한 영향만을 반영한 수치임 - 계산 자체는 보수적으로 이루어짐 - 온보딩 및 적응 비용: $100,000-$125,000 - 새 시니어 엔지니어 생산성: 1개월차 약 25%, 2-3개월차 50%, 4-5개월차 75%, 6개월차 전체 생산성 도달 - 1개월 차: 생산성 75% 손실 = (200,000달러 / 12개월) × 0.75 = 12,500달러 - 2~3개월 차: 생산성 50% 손실 = (200,000달러 / 12개월) × 0.50 × 2 = 16,667달러 - 4~5개월 차: 생산성 25% 손실 = (200,000달러 / 12개월) × 0.25 × 2 = 8,333달러 - 첫 6개월 생산성 격차 총합: $37,500 - 온보딩 인력 비용: 새 시니어 엔지니어가 첫 달 주당 10-15시간, 2-3개월차 주당 5-8시간의 다른 엔지니어 시간 소비 - 1개월 차: 주 12시간 × 4주 × 시간당 90달러 = 4,320달러 - 2~3개월 차: 주 6시간 × 8주 × 시간당 90달러 = 4,320달러 - 시간당 $90 기준 온보딩 인력 비용: $8,640 - 즉 첫 6개월 동안 $46,140의 손실 이 발생함 - 하지만 대부분의 시니어 엔지니어가 이전 엔지니어 수준의 도메인 전문성에 도달하는 데 약 1년 소요되므로 $92,000-$125,000 예상 - 부족 지식(Tribal Knowledge) 손실: $100,000-$300,000 - 가장 정량화하기 어렵지만 이후 분기에 실수로 나타남 - 이탈 엔지니어가 알고 있던 것들: - 코드베이스의 어느 부분이 취약하고 신중한 변경이 필요한지 - 어떤 고객이 특별 요구사항을 가졌고 그 이유 - 어떤 아키텍처 결정이 의도적 트레이드오프인지 vs 기술 부채인지 - 10,000줄 서비스에서 실제로 중요한 3줄의 코드 - 특정 데이터베이스 쿼리가 비효율적으로 보이지만 그렇게 작성된 이유(3년 전 발견된 특정 조건에서 "명백한" 최적화가 데이터 손상 유발) - 맥락 부재로 인한 실수: 새 엔지니어가 "느린" 쿼리 최적화 시 회사 2대 고객의 핵심 워크플로 중단 - 문제 파악 2일($4,615), 적절한 수정 구현 1주($7,692), 고객 관계 복구 - 단일 사고 비용 약 $12,000-$15,000, 이탈 시니어 엔지니어당 첫해 3-5회 발생 - 의사결정 지연: 이탈 엔지니어가 30초에 답했을 질문이 이제 3시간의 코드 고고학, Slack 히스토리 검색, "왜 이렇게 했는지 아는 사람?" 대화 필요 - 주 2회, 6개월간 발생 시: $14,040 - 이연 또는 포기된 프로젝트: 이탈 엔지니어만이 인증 시스템을 충분히 이해해 SSO 통합을 안전하게 구현 가능 - 해당 프로젝트 6-9개월 지연, SSO가 50만 달러 기업 계약에 필요했다면 지연 비용 측정 가능 - 이런 내부 지식 손실에 대한 보수적인 추정치: 퇴사 후 12개월 동안 10만 달러에서 30만 달러까지 - 엔지니어 이탈당 총비용 - 직접 대체: $85,000-$100,000 - 공석 비용: $50,000-$100,000 - 적응 및 온보딩: $92,000-$125,000 - 내부 지식 손실: $100,000-$300,000 - 보수적 총계: $327,000-$625,000 - 프로젝트 지연 및 기회비용 포함 현실적 총계: $500,000-$1,000,000 - 이러한 비용은 예산 전체에 분산되고 노이즈에 숨겨짐: 채용비는 HR 예산, 생산성 손실은 추적 안 됨, 내부 지식 증발은 분기 보고서에 미표시 - 기술 부채 이연 및 기능 우선 결정은 즉각적이고 가시적인 성과 창출: 영업팀 데모, 마케팅 출시 발표, CEO의 이사회 보고 등 - 경제학자들이 "끓는 개구리" 문제라 부르는 현상임: - 개별 직원의 퇴사는 감당할 수 있는 것처럼 보이고, 기술 업무 연기는 합리적으로 보이며, 분기별 절충안도 개별적으로는 정당해 보임 - 패턴이 명백해질 때(연간 시니어 엔지니어 이탈률 18%, 누적 기술 부채, 연쇄 시스템 장애)에는 조직은 이미 기능 장애를 정상적인 것으로 받아들이게 됨
회복(Recovery)은 어떤 모습으로 보이는가
- 블랙프라이데이 재앙 14개월 전, 중견 결제 처리 회사의 시니어 플랫폼 엔지니어가 구체적 우려를 제기 - "트랜잭션 처리 시스템이 예상 홀리데이 트래픽을 감당하지 못합니다" - 데이터베이스 샤딩 및 큐 최적화가 필요하다는 상세 제안 제출: 엔지니어링 시간 6주, 인프라 비용 $80,000 추정 - VP of Product에 의해 우선순위가 밀림: - 다른 두 개의 기능 출시가 더 중요하다고 판단됨 - 분기 리뷰에서는 "잠재적 문제를 사전에 파악한 능력"을 칭찬했지만, 아키텍처 제안서는 Jira에 방치함 - 해당 엔지니어는 4개월 후 15% 인상 받고 경쟁사로 이직, 3개월 탐색과 $47,000 채용비 소요 후 대체 인력 채용, 생산성 도달에 5개월 추가 소요 - 그 사이 시니어 엔지니어 2명 추가 이탈: 1명은 기술 부채 좌절감, 1명은 사내에 없던 Principal Engineer 역할을 외부에서 수락 - 그 최초 경고가 다시 논의된 시점은 9개월 후 아키텍처 리뷰 - 당시에는 이미 제안의 맥락과 해결 방법에 대한 조직적 기억이 사라진 상태 - 주니어 엔지니어에게 “대안을 조사”하라는 임무가 할당됨 - 블랙프라이데이 당일, 오전 9시 47분 트랜잭션 급증하며 재앙이 시작 - 오전 10시 23분부터 데이터베이스가 쓰기 요청을 거부 - 병목은 14개월 전 지적된 바로 그 지점이며, 해당 장애로 인해 $2.5M 규모의 트랜잭션 처리 실패 - 복구에는 5시간이 소요됨 - 긴급 인프라 확장 비용 $180,000 과 영구적 아키텍처 변경을 위해 엔지니어 3명이 휴일 내내 초과 근무 - 12월 3일, CTO 주도로 새로운 항목이 포함된 포스트모템이 경영진에 제출됨 - “Previously Raised Concerns” 섹션 추가되어 그 엔지니어의 최초 경고, 우선순위 배제 결정, 이후의 인력 이탈을 모두 기록 - CFO가 총비용을 계산해 봄 - 엔지니어 이탈 비용(시니어 3명) : 1인당 $235,000의 측정 가능한 비용 발생 - 리크루팅 $47,000 + 사이닝 보너스 $30,000 + 공석 비용 $83,000 (평균 4개월) + 온보딩·램프업 $75,000 - 총합 $705,000 - 트라이벌 지식 손실 비용: $2.2M - 데이터베이스 구조, 실패 모드, 기존 해결책에 대한 이해가 조직에서 사라짐 - 문제를 다시 발견하고, 해결책을 재조사하고, 긴급 상황에서 구현해야 했음 - 이러한 지식 격차는 계획된 마이그레이션을 위기 대응으로 바꿔 버림 - 조사 비용, 잘못된 시도, 긴급 벤더 투입, 가맹점 대응 비용이 누적됨 - 실패한 트랜잭션 비용: - 결제 처리 실패 금액 $2.5M - 수수료율이 2.9%였으므로 직접 매출 손실은 $72,500 이지만, 계약상 모든 거래를 처리해야할 의무가 있음 - 그래서 처리 실패로 인한 SLA 위반 벌금 $180,000 및 가맹점 지원 및 이탈 방지 비용 $45,000 발생 - 긴급 인프라 비용: $180,000 - 긴급 데이터베이스 확장(추가 읽기 복제본, 업그레이드 된 인스턴스, Expedited 벤더 서포트 비용) - 로드밸런서 재설정 및 CDN 최적화로 14개월 전에 예상했던 트래픽을 처리 가능하게 함 - 복구 및 사후 조치 비용: $87,000 - 시니어 엔지니어 3명 휴일 주말 72시간 2.5배 초과근무율 근무: $51,923 - 더 넓은 엔지니어링 팀 2주 후속 작업: $38,462 - 총 사고 비용: $3.47M - 원래 제안된 예방 비용: $80,000 (선임 엔지니어 1명의 6주 엔지니어링 작업 시간과 인프라 비용 포함) - 포스트모템 첫 페이지에는 $3.47M vs $80,000 라고 적혀있는데 이 숫자가 대화의 방향을 바꿈 - CEO가 이사회 질문에 대응해 유지율 분석을 지시 - 시니어 엔지니어 이탈률 연간 34%(수익성 있는 회사 업계 평균의 2배 이상) - 이전에 경영진 검토 없이 보관된 퇴사 인터뷰에서 일관된 패턴이 나타남 - 재능 있는 엔지니어들이 기술적 우려가 인정되었지만 실행되지 않을 때 이탈 - 18개월간 4가지 개선조치 시행: - CFO가 분기 보고서에 고객 획득 비용과 함께 이탈 비용 추적 시작 — 갑자기 $235,000 평균 이탈 비용이 마케팅 지출 결정같은 문서에 등장 - 모든 경영진 분기별 온콜 로테이션에 참여 — 데이터베이스 작업 우선순위 하향한 VP of Product는 첫 주 23페이지 분량의 보고서를 수신했는데, 19건이 이전 6개월간 지적된 기술 부채 관련 - 보상위원회가 임원 변동 급여에 인재 유지 요소를 추가: 시니어 엔지니어 90% 연간 유지하는 것은 보너스 계산의 25% 가치 - 디렉터 및 VP 수준과 보상 일치하는 Staff 및 Principal IC 트랙 신설 - 18개월 후, 이 결제회사는 시니어 엔지니어 이탈률이 연간 9%로 감소 - 더 중요한 것은 아키텍처 리뷰 프로세스 변화: - 기술 부채 제안에 이제 계산된 장애 비용이 포함 - 경영진은 일상적으로 "이것을 이연하면 엔지니어 이탈 위험은 얼마나 되나요?"라고 질문 - 원래 데이터베이스 우려 제기했던 플랫폼 엔지니어가 Principal Engineer로 복귀 - 퇴사 당시 대비 연봉 40% 인상 — 특별히 인프라 확장 리드로 채용 해당 엔지니어의 복귀는 숫자가 보여준 변화와 함께 조직의 경제적 계산이 실제로 바뀌었음을 상징함
실제로 효과가 있었던 여섯 가지 개입(Intervention)
- 인센티브를 재정렬하는 구조적 개입, 정보 수집이나 공감 활동이 아니라 경제적 재설계 - 영향력의 계층 구조 - 6가지 개입이 부담스러워 보일 수 있으나 구현 난이도와 가치 창출 시간이 동일하지 않음, 순서가 중요 - 가장 빠른 성과를 내는 방법: 조직의 최소한의 동의만 필요한 개입 - 이탈비용 회계(#1): CFO 승인과 재무 분석가 시간만 필요 - 무시된 경고로 인한 사고 추적(#2): SRE 프로세스 변경만 필요. 예산이나 구조 조정이 필요 없고, 체계적인 사후 분석 문서화만 있으면 됨 - 둘 다 30일 내 시작 가능, 더 어려운 싸움을 위한 정량화된 증거 제공 - 중기 개입: 문화 변화 필요하지만 보상 구조조정 불필요 - 경영진 온콜 로테이션(#3): 한 경영진이 인프라 개선 작업 연기의 결과를 직접 경험할 때 성공하며, 그 정책은 자연스럽게 자리 잡음 - 권한 있는 기술자문위원회(#5): 경영진이 자신의 결정이 번복될 가능성을 진정으로 받아들일 때 효과를 발휘하며, 소규모로 시범 운영되는 방식은 몇 분기 내에 실패 - 구현 일정 3-6개월 : 단순한 정책 변경뿐 아니라 신뢰 구축을 필요로 하기 때문 - 구조적 개입: 이사회 또는 보상위원회 승인 필요, 6-12개월 소요하지만 가장 깊은 변화 제공 - 보상 체계 내 인재 유지 지표 포함(#4): 경영진 보너스가 시니어 엔지니어 유지에 의존 시 기술 부채가 하룻밤 사이 전략적으로 중요해짐 - IC 트랙의 동등성 확보(#6): Staff 엔지니어가 팀 관리 없이 수석급 급여 시 기술 전문성 유지가 구조적으로 가능해짐 - 최소 실행 가능 개입: 다른 계층의 두 요소 결합 - 이탈비용 회계(빠른 성과) + 보상에 유지 지표(구조적 변화) - 첫 번째가 비즈니스 케이스 구축, 두 번째가 경영진에게 행동을 합리적으로 만듦 - 위기 상황 회사: 빠른 성과 즉시 시행 + 구조적 변화 병행 설계 - 조기 경고 징후 회사: 측정(비용 회계, 사고 추적)으로 시작 + 결과 데이터로 더 깊은 개입 정당화 1. 이탈 비용 회계 (Cost-of-Attrition Accounting) - 보이지 않는 것을 보이게 만들기: 모든 시니어 엔지니어 이탈의 전체 비용 계산 - 평균 리크루팅 비용 $35,000 - 완전한 생산성 도달까지 약 6개월(시니어 엔지니어 연봉의 50%) - 지식 손실로 인한 프로젝트 지연 - 해당 엔지니어만 이해했던 아키텍처 결정의 기회비용 - 이 수치를 월별로 추적하고 CAC, 매출 지표와 같은 임원 대시보드에 포함시킴 - 한 금융 서비스 회사는 분기별 이탈 비용을 추적한 결과 - Q1: 시니어 2명 이탈, $400,000 - Q3: 연간 예상 비용 $900,000 - CFO가 이를 연간 엔지니어링 예산 $3M과 함께 제시하자 - CEO의 질문이 “왜 떠났나”에서 “막으려면 얼마가 필요한가” 로 바뀜 - 결과적으로 기술 부채 정리와 보상 조정에 $400,000 투자하자 - 시니어 이탈률 43% 감소하고 투자 비용은 두 분기 만에 모두 회수 2. 무시된 경고로 인해 발생한 사건을 추적하기 - 사후분석 템플릿을 수정하여 필수 섹션인 "사전 경고(Prior Warnings)" 추가 - 담당자가 Jira, Slack, 아키텍처 리뷰 노트, 이메일에서 이 장애 모드에 대한 과거 경고를 확인하도록 요구 - 문서화 항목: 경고 제기 시점, 제기자, 제안된 조치, 우선순위 하향 이유 - 사고 비용 계산: 다운타임 수익 영향, 고객 지원 부담, 복구에 소요된 엔지니어 시간 - 한 헬스케어 기술 회사는 이 방식을 도입한 뒤 - 6개월 내 프로덕션 사고의 70%가 사전 예측되었음을 발견 - 엔지니어들이 우려 제기했지만 경영진이 기능 개발에 집중하느라 문제 해결 우선순위 하향 - 1년간 총 비용: 예방 가능한 사고에 180만 달러의 비용이 발생 함 - 16건 주요 장애 중 14건에서 기술 경고가 정확했음을 경영진이 확인 시 패턴의 심각성을 깨달음 - 예측이 일관되게 정확함이 입증되자 행동 변화 3. 경영진 온콜 로테이션 - 모든 임원(프로덕트, VP, 디렉터 포함)이 분기당 1주씩 온콜 수행 - 에스컬레이션 정책: - 온콜 엔지니어가 알림이 이전에 우선순위가 낮았던 수정 사항이나 연기된 기술 작업과 관련이 있다고 판단할 경우 - 시간이나 요일에 관계없이 해당 결정을 내린 책임자에게 직접 보고 - 이는 어떤 대시보드보다 강력한 체험 학습을 제공함 - 사례: 한 VP of Product가 7개월 전 엔지니어들이 "있으면 좋은" 수정으로 플래그한 동일한 데이터베이스 연결 풀 이슈로 5일간 17건의 호출을 경험 - 해당 이슈는 P3로 표시되었고, VP는 대신 3개 기능 출시 우선 - 5번 연속 새벽 3시 호출 후 P0으로 변경, 8일 내 수정 - 나중에 해당 VP는 "엔지니어들이 알림 피로에 대해 과장한다고 생각했음. 아니었음" 이라고 인정함 4. 임원 보상에 인재 리텐션 지표 반영 - 경영진 변동 보상의 25%가 시니어 엔지니어 유지율에 의존하도록 구조 개편 - "시니어" 정의: 재직 기간 2년 이상, 성과 평가에서 기대치를 뛰어넘는 경우, 또는 핵심 시스템 담당 - 목표 설정: 시니어 엔지니어 연간 90% 유지 - 목표 미달 시 보너스 비례적으로 삭감 - 목표 초과 시 보너스가 배율로 지급 - 사례: Series B SaaS 회사가 2021년 이 구조 시행 - 시니어 엔지니어 이탈 연간 28% - 경영진 초기 저항: "누군가가 더 나은 제안을 받는 것을 우리가 통제할 수는 없다"라며 반대함 - CEO 응답: "그러면 우리가 연봉 외에는 경쟁력이 없다는 것을 인정하는 셈. 개선하거나 보상 영향 수용하라" - 1년 내 이탈률 11%로 감소 - 퇴사 인터뷰 패턴 전환: 떠나는 엔지니어들이 기능장애 기반 이탈(무시된 기술 우려, 성장 부재, 문화 독성)이 아닌 기회 기반 이탈(더 큰 회사 수석 승진, 스타트업 창업, 이전) 언급 - 경영진이 이제 인재 유지에 대한 책임감을 갖게 되면서, 보너스 목표 달성은 가장 쉬운 부분이 되어버림 5. 실질 권한을 가진 기술 자문 위원회(TAB) - 엔지니어링 조직이 선출한(경영진 임명 아닌) 시니어 엔지니어 5명으로 위원회 구성 - C 레벨들과 분기별 미팅 - 하나의 권한: 분기당 경영진 결정 1건 거부 가능 - 요구사항: 거부 시 기술적 정당화, 예상 비용, 위험 분석 포함 서면 대안 제안 필수 - 경영진은 CEO 승인과 문서화된 이유로만 거부권 무효화 가능 - 사례: 블록체인 인프라 회사가 2020년 초 TAB 구성 - 2년간 거부권 2회 행사 - 첫 번째 거부: 독점 합의 프레임워크 구축 결정 차단, 대신 기존 오픈소스 프로토콜 확장 제안. 추정 18개월 개발 시간 절약 - 두 번째 거부: 포괄적 롤백 테스트 없이 데이터베이스 마이그레이션 출시 방지. 사후 구현 분석에서 TAB이 200만 달러 데이터 손상 사고 예방 추정 - 진짜 영향은 더 미묘: 경영진이 기술 결정 최종화 전 "TAB이 이것 승인할까?" 묻기 시작 - 거부 위협이 TAB 도달 전 제안 품질 변화 - 엔지니어들이 기술적 판단이 마침내 경영진 결정에 중요해졌다고 보고 6. 보상 동등성을 갖춘 IC(개인 기여) 트랙 - IC 경력 발전 경로를 명확하게 설정 : Staff Engineer, Principal Engineer, Distinguished Engineer - 보상 밴드가 각각 Director, VP, SVP 수준과 일치해야 함 - 승진 기준: 팀 규모나 보고 체계보다는 기술적 영향력, 아키텍처에 대한 주도권, 다른 엔지니어들의 업무 효율성을 높이는 파급 효과 - 사례: 핀테크 회사가 6개월 내 Staff급 엔지니어 3명 이탈 - 퇴사 인터뷰에서 동일 패턴: "매니저가 되지 않고는 L7 보상에 도달 불가. 관리하고 싶지 않고 개발자가 되고 싶음" - 회사가 보상 동등성 있는 IC 트랙 시행 - 1년 내: 이전에 면접 보던 엔지니어 2명 Principal로 승진, 유사 경력 경로 없는 경쟁사에서 시니어 IC 3명 채용, 시니어 기술 이탈 62% 감소 - 더 중요하게, 회사에 남은 엔지니어들이 추정 300만 달러에 달하는 아키텍처 실수 예방 이는 주니어 또는 미드 레벨 엔지니어들이 전문성이나 권한 부족으로 이의를 제기할 수 없었던 결정들
실행 경로 (Implementation Paths)
- 실행 일정은 조직이 처한 심각도에 따라 달라짐 - 위기 상황 회사 (시니어 이탈률 >20%, 최근 중대 장애 발생) - 1-2주차: 실제 12개월 이탈 비용 계산(채용비, 생산성 적응 시간, 프로젝트 지연, 부족 지식 손실 포함), 퇴사 인터뷰 패턴 분석, 프로덕션 사고를 이전에 무시된 경고에 매핑 - 3-4주차: CFO와 CEO에게 발견 사항 제시, 패턴 표시(기술 우려 제기 → 우선순위 하향 → 엔지니어 이탈 → 사고 또는 비용), 총 손해 정량화, 즉각 개입 제안 - 5-8주차: 경영진 온콜 로테이션 시작(가장 빠른 문화 전환), 이탈비용 추적 시작(지속적 변화 케이스 구축), 엔지니어 3명으로 TAB 파일럿 생성, 경영진 대시보드에 월별 이탈 비용 추적 시작 - 9-12주차: 이사회에 보상 구조 변경 제시, 경영진 보너스를 유지율에 연계, IC 경력 트랙 공개 발표, 무엇이 왜 바뀌었는지 투명하게 소통 - 조기 경고 징후 회사 (이탈률 12-18%, 엔지니어들이 1:1에서 우려 언급) - 1-2개월차: 이탈 비용 추적 및 경제적 케이스 구축 시작, 유지 위험과 무엇이 머물게 할지 엔지니어 설문, 가장 자주 언급된 3가지 우려 식별 - 3-4개월차: 자원 경영진과 경영진 온콜 로테이션 파일럿, TAB 파일럿 시작, 둘 다 기술 부채와 조직 마찰 표면화에 사용, 이연된 작업 비용 문서화 - 5-6개월차: 영구 보상 구조 변경 시행, TAB 권한 공식화, IC 경력 트랙 기준 및 보상 밴드 공개, 시니어 엔지니어 유지를 명시적 경영진 목표로 설정
이것이 효과 없는 경우
이러한 개입은 3가지 시나리오에서 예측 가능하게 실패함, 이를 인정하지 않으면 시간만 낭비하게 됨
1. 애초에 이탈을 전제로 설계된 비즈니스 모델 - 컨설팅 회사와 계약 업체는 연간 20-40% 이직률 예상 - 비즈니스 모델이 인력 대체 비용을 가격에 반영하고, 청구 요율은 조직 내 전문 지식이 제한적이라는 전제하에 책정 - 제품 회사용으로 설계된 인력 유지 전략은 클라이언트 로테이션이 자연스러운 이탈을 유도하고 파트너 트랙이 의도적으로 업앤아웃 압력 생성하는 곳에서 의미 없음 - 유사하게 제품-시장 적합성 이전 초기 스타트업은 유지 실패가 아닌 필요한 피벗을 신호하는 엔지니어 이탈 경험 가능 - 회사가 6개월마다 근본적으로 방향을 전환하고 있다면, 낮은 유지율은 체계적 역기능이 아닌 적절한 인재 재배치를 의미 2. 실행하는 척만 하는 경우 (Implementation Theater) - 형식만 있는 개입은 무개입보다 더 나쁜 결과를 낳음 - 실제 거부 권한 없는 TAB은 엔지니어 우려를 분산시키는 배출구가 됨 - 체계적으로 무시되는 제안에 시간 투자 시 분노만 더 커짐 - 근본적인 원인 해결과 연결되지 않은 임원진의 온콜 로테이션은 책임감 없는 보여주기식 공감 생성 - 자신이 우선순위를 정해 해결할 수 없는 문제로 호출을 받는 VP는 엔지니어들이 자주 불평한다는 것만 학습 - 계산되지만 경영진 대시보드나 보상 논의에 절대 등장하지 않는 이탈비용 회계는 이론적인 논의로 남음 절반 시행된 개입은 리더십이 구조적 변화에 대한 진정한 의지 없이 관심을 보이는 척만 한다는 것을 보여줌 3. 문화적 전제조건 부재 - 이러한 개입은 많은 조직에 부재한 문화적 전제조건을 필요로 함: 리더십이 평판 관리가 아닌 진정한 행동 변화를 원해야 함 - 경영진이 엔지니어 유지를 경제적 문제가 아닌 PR 문제로 보면 가장 가시적인 개입(자문위원회, 청취 투어)만 시행하면서 비용 많이 드는 것(보상 구조조정, 실제 거부 권한)은 회피 - 진단 테스트: 경영진 변동 보상의 25%를 시니어 엔지니어 유지에 연계를 제안해 볼 것 - 리더십이 즉시 "우리 회사에서 안 되는 이유"를 제시한다면 해답을 찾은 것 - 그들은 개인적 비용 없는 솔루션을 원하는 것임 - 엔지니어에게 거부 권한 부여, 경영진 급여를 유지에 연계, 분기 재무 검토에 이탈 비용 반영할 준비가 안 된 회사는 구조적 변화 준비 안 됨 - 우려를 인정하고 "추가 연구" 권장하며 시니어 엔지니어 계속 이탈하는 동안 먼지 쌓이는 컨설팅 보고서에 만족할 뿐 - 개입은 리더십이 연간 140만 달러 이직 비용이 이를 막기 위해 필요한 조치보다 더 크다는 사실을 인식할 때 작동 - 그 인식 없으면 아무리 많은 자문위원회도 경제적 정렬을 대체 불가
새로운 경제적 계산
- 저자가 이끈 블록체인 인프라 회사가 3년간 10명에서 187명 엔지니어로 확장하면서도 연간 시니어 엔지니어 이탈률을 평균 6% 로 유지했는데, 초고속 성장 기업의 일반적인 이직률인 35~40%를 훨씬 웃도는 수치 - 성과의 원인은 복지나 문화적 장치가 아니라 인센티브 구조의 재설계에 있었음 - 중간 관리자가 모든 것이 통제 하에 있는 것처럼 보이는 것이 아닌 기술 위험 조기 표면화로 보상을 받음 - 사후분석에 이전 경고 문서화 요구; 무시된 경고는 우선순위를 낮춘 담당자의 성과 평가 대상이 됨 - 기술 리더십이 아키텍처 결정에 거부 권한 보유. 우리는 2회 사용했는데, 거부권 행사 가능성만으로도 전반적인 제안서 품질이 향상 - 창립 때부터 IC 경력 트랙 존재; 가장 시니어 비매니저가 대부분의 디렉터보다 더 많은 급여를 수령 - 시스템 비용: 보상 조정, 거버넌스 오버헤드, 일부 기능 지연한 기술 부채 우선순위 지정에 연간 약 $400,000 - 절감액: - 예방된 이탈 비용 210만 달러 (업계 표준 35% 이탈을 시니어 엔지니어 인원에 적용) - 추가로 시니어 엔지니어가 중단 권한이 있어 수백만 달러 사고를 만들지 않은 아키텍처 결정에서 측정 불가하지만 상당한 절감효과가 있음
불편한 진실
- 대부분의 회사는 어쩔 수 없이 강제적인 상황이 닥치기 전까지 이러한 개입 시행 안 함 - 강제 기능은 보통 재앙적인 상황임: 수백만 달러 비용 프로덕션 사고, 핵심 팀을 마비시키는 대규모 인력 이탈, 또는 경쟁사가 당신이 거부했던 것, 즉 기술적 판단에 대한 존중을 제시하며 당신의 핵심 엔지니어 인력의 절반을 빼앗아 가는 경우 - 그때쯤이면 예방이 아닌 피해 복구에 매달리게 됨 - 회복은 비용이 많이듬. 다음 위기 예방할 수 있는 최고 엔지니어들이 이미 떠났기 때문 - 그들의 후임자들은 재능은 있지만 조직에 대한 지식이 부족해서 어떤 경고를 해야 할지 모르며, 파멸 루프 가속화 - 문제는 이러한 개입이 효과 있는지가 아님, 증거는 명확함 - 경영진의 인센티브를 직원 유지에 맞춰 조정하, 엔지니어에게 의미 있는 권한 부여하고, 이직을 경제적 문제로 다루는 회사가 직원 유지율, 사고 발생율, 장기적인 기술 건전성 측면에서 일관되게 우수 - 숙련된 엔지니어들이 이탈하고 있고 일반적인 해결책이 효과가 없다면, 문제는 소통이 아니라 경제적인 측면일 수 있음
소프트웨어 공학의 법칙들 (lawsofsoftwareengineering.com)
- 소프트웨어 시스템, 팀, 의사결정에 영향을 미치는 56가지 원칙과 패턴을 한곳에 모은 컬렉션으로, 팀 운영부터 아키텍처, 품질, 설계, 의사결정까지 폭넓은 영역을 포괄 - Conway의 법칙, Brooks의 법칙, Dunbar의 수 등 팀 관련 법칙들은 조직 구조가 시스템 설계와 생산성에 직접적으로 영향을 미침 - 아키텍처 영역에서는 Hyrum의 법칙, CAP 정리, Gall의 법칙 등 복잡한 시스템 설계 시 반드시 고려해야 할 제약과 원칙을 정리 - 품질 관련 법칙들은 기술 부채, 테스팅 피라미드, Kernighan의 법칙 등 코드 품질 유지와 디버깅의 현실적 어려움을 다룸 - 의사결정 영역에서는 Dunning-Kruger 효과, 매몰 비용 오류, 파레토 원칙 등 개발 과정에서 빠지기 쉬운 인지 편향과 판단 기준을 포괄
팀(Teams)
Conway의 법칙 (Conway's Law)
- 조직은 자신의 커뮤니케이션 구조를 그대로 반영하는 시스템을 설계한다
- 소프트웨어 아키텍처는 그것을 만든 조직의 소통 구조를 자연스럽게 따라가는 현상
- 팀이 3개로 나뉘어 있으면 시스템도 3개의 큰 모듈로 나뉘는 경향이 있음
- 이를 역으로 활용하는 "역 Conway 전략"(Inverse Conway Maneuver)도 존재: 원하는 아키텍처에 맞춰 팀 구조를 먼저 재편하는 접근
- 마이크로서비스 도입 시 팀 경계와 서비스 경계를 일치시키는 것이 효과적
Brooks의 법칙 (Brooks's Law)
- 지연된 소프트웨어 프로젝트에 인력을 추가하면 오히려 더 늦어진다
- 신규 인력이 합류하면 기존 팀원이 교육과 조율에 시간을 소모하여 전체 생산성이 일시 저하
- 팀원이 늘어나면 커뮤니케이션 경로가 기하급수적으로 증가 (n명일 때 n(n-1)/2개)
- Frederick Brooks가 IBM OS/360 프로젝트 경험을 바탕으로 1975년 저서 The Mythical Man-Month에서 정립
- Little의 법칙(L = λ × W)으로 정량적 설명 가능: 인력 추가 시 WIP(작업 중인 항목)는 증가하지만 처리량(throughput)은 정체되어 리드 타임이 오히려 증가
- 해결책은 인력 추가가 아닌 범위 조정 또는 일정 변경
Dunbar의 수 (Dunbar's Number)
- 한 사람이 안정적으로 유지할 수 있는 관계의 인지적 한계는 약 150명
- Robin Dunbar가 영장류 뇌 크기와 사회 집단 규모의 상관관계에서 도출한 수치
- Dunbar의 사회적 계층 구조: ~5명(친밀한 관계), ~15명(신뢰할 수 있는 협력자), ~50명(가까운 업무 관계), ~150명(안정적 사회적 연결)
- 엔지니어링 조직이 150명을 넘으면 비공식적 소통이 한계에 도달하여 공식적 계층과 프로세스 필요
- Amazon의 "Two-Pizza Team"(5~10명)은 150명 내에서도 실질적 협업은 더 작은 단위에서 일어남을 반영
Ringelmann 효과 (The Ringelmann Effect)
- 그룹 규모가 커질수록 개인의 생산성은 감소한다
- 그룹 구성원이 많아질수록 각 개인의 기여도가 줄어드는 "사회적 태만"(social loafing) 현상
- 소프트웨어 팀에서도 팀 크기가 커지면 개별 책임감이 희석되고 조율 비용이 증가
- 소규모 팀이 1인당 더 높은 산출물을 내는 이유를 설명
Price의 법칙 (Price's Law)
- 전체 참여자 수의 제곱근에 해당하는 인원이 전체 작업의 50%를 수행한다
- 100명의 조직에서는 약 10명이 전체 작업의 절반을 담당
- 조직이 커질수록 소수의 고성과자에 대한 의존도가 심화
- 팀 확장 시 생산성이 선형으로 증가하지 않는 이유를 설명
Putt의 법칙 (Putt's Law)
- 기술을 이해하는 사람은 관리하지 않고, 관리하는 사람은 기술을 이해하지 못한다
- 기술 조직에서 관리 역할과 기술 전문성의 괴리를 풍자적으로 표현
- 기술 리더십 구조를 설계할 때 이 간극을 인식하고 보완 장치를 마련해야 함
Peter 원칙 (Peter Principle)
- 조직 내에서 모든 직원은 자신의 무능력 수준까지 승진하는 경향이 있다
- 특정 역할에서 유능한 사람이 승진하여 새로운 역할에서는 무능력해지는 패턴
- 뛰어난 개발자가 반드시 좋은 매니저가 되지는 않는 현실을 반영
- IC(Individual Contributor) 트랙과 매니지먼트 트랙을 분리하는 듀얼 래더 체계의 필요성
Bus Factor
- 프로젝트가 심각한 위험에 처할 수 있는 최소 팀원 이탈 수
- Bus Factor가 1이면 단일 장애점(Single Point of Failure)이 존재하는 상태
- 지식 공유, 페어 프로그래밍, 문서화를 통해 Bus Factor를 높이는 것이 중요
- 코드 리뷰와 크로스 트레이닝이 Bus Factor를 개선하는 실질적 방법
Dilbert 원칙 (Dilbert Principle)
- 기업은 무능한 직원을 관리직으로 승진시켜 피해를 제한하는 경향이 있다
- Scott Adams가 제안한 풍자적 관찰로, Peter 원칙의 변형
- 관리직이 실무에서 가장 적은 피해를 주는 자리로 여겨지는 역설적 조직 현상
계획(Planning)
조기 최적화 / Knuth의 최적화 원칙 (Premature Optimization)
- 조기 최적화는 모든 악의 근원이다
- Donald Knuth가 1974년 논문에서 제시: "약 97%의 경우에서 작은 효율성은 무시해야 한다"
- 코드의 약 20%가 실행 시간의 80%를 차지하므로, 나머지 80% 코드를 최적화하는 것은 낭비
- 올바른 순서: 먼저 동작하게 만들고 → 올바르게 만들고 → 필요하면 빠르게 만들 것
- 최적화된 코드는 복잡성이 높아지므로, 프로파일링을 통해 실제 병목 지점을 확인한 후 수행해야 함
Parkinson의 법칙 (Parkinson's Law)
- 업무는 주어진 시간을 모두 채울 때까지 확장한다
- 데드라인이 2주면 2주, 4주면 4주 동안 일이 늘어나는 현상
- 소프트웨어 프로젝트에서 짧고 명확한 마일스톤 설정이 중요한 이유
- 스프린트 기반 애자일이 이 법칙에 대한 실질적 대응 방법
90-90 법칙 (The Ninety-Ninety Rule)
- 코드의 처음 90%가 개발 시간의 90%를 차지하고, 나머지 10%가 또 다른 90%의 시간을 차지한다
- 소프트웨어 프로젝트의 마지막 10%(엣지 케이스, 폴리싱, 버그 수정)가 예상보다 훨씬 오래 걸림을 경고
- "거의 완성"이라는 말이 실제로는 전체 일정의 절반 지점일 수 있음
Hofstadter의 법칙 (Hofstadter's Law)
- Hofstadter의 법칙을 고려하더라도 항상 예상보다 오래 걸린다
- 재귀적 자기 참조 구조를 가진 법칙으로, 소프트웨어 일정 추정의 본질적 어려움을 표현
- 버퍼를 추가해도 여전히 일정이 초과되는 현실
- Douglas Hofstadter가 1979년 저서 Gödel, Escher, Bach에서 소개
Goodhart의 법칙 (Goodhart's Law)
- 측정 지표가 목표가 되면 더 이상 좋은 측정 지표가 아니다
- 코드 커버리지를 KPI로 설정하면 의미 없는 테스트를 양산하는 현상이 대표적 사례
- 코드 라인 수(LOC)로 생산성을 측정하면 불필요하게 장황한 코드가 생산됨
- 지표 최적화가 아닌 본질적 가치 달성에 집중해야 함
Gilb의 법칙 (Gilb's Law)
- 정량화가 필요한 것은 측정하지 않는 것보다 어떤 방식으로든 측정하는 것이 나다
- 완벽한 측정이 불가능하더라도 대략적 측정이 무측정보다 항상 유익
- 소프트웨어 품질, 사용자 만족도 등 정량화가 어려운 항목에도 적용
아키텍처(Architecture)
Hyrum의 법칙 (Hyrum's Law)
- API 사용자가 충분히 많으면, 시스템의 모든 관찰 가능한 동작에 누군가 의존한다
- 공식 API 명세뿐 아니라 타이밍, 에러 메시지 형식, 정렬 순서 등 비공식적 동작도 의존 대상이 됨
- Microsoft Windows가 과거 문서화되지 않은 동작과 버그에 의존하는 서드파티 앱 호환을 위해 구버전 동작을 유지한 사례
- Google의 Hyrum Wright가 2011-2012년경 Google 내부 라이브러리 변경 경험에서 관찰
- 동료 Titus Winters가 "Hyrum's Law"라는 이름을 붙임 (Software Engineering at Google 수록)
- 실질적 계약은 공식 API가 아니라 실제 관찰되는 동작 전체
Gall의 법칙 (Gall's Law)
- 작동하는 복잡한 시스템은 반드시 작동하는 단순한 시스템에서 진화한 결과이다
- 처음부터 복잡한 시스템을 설계하면 검증되지 않은 미지의 변수가 너무 많아 실패 확률이 높음
- MVP(Minimum Viable Product) 접근의 이론적 근거
- Facebook이 2004년 Harvard 학생용 단순 프로필 시스템에서 시작하여 점진적으로 확장한 사례
- 마이크로서비스 전환 시에도 모놀리스에서 시작하여 점진적으로 분리하는 것이 유리
- John Gall이 1975년 저서 Systemantics에서 제시 (30개 출판사가 거절 후 출간된 컬트 클래식)
누수 추상화의 법칙 (The Law of Leaky Abstractions)
- 모든 비자명(non-trivial) 추상화는 어느 정도 누수가 발생한다
- ORM이 SQL을 숨기지만 성능 문제가 발생하면 결국 생성되는 쿼리를 확인해야 하는 상황이 대표 사례
- Java/Python의 가비지 컬렉션도 추상화이지만 GC 일시정지 같은 내부 동작이 성능에 영향을 미침
- 추상화 자체가 나쁜 것이 아니라, 추상화가 깨질 때를 대비해야 한다는 교훈
- Joel Spolsky가 2002년 블로그 포스트에서 TCP, 가상 메모리 등의 사례와 함께 소개
- George Box의 "모든 모델은 틀렸지만, 일부는 유용하다"와도 맥락 연결
Tesler의 법칙 / 복잡성 보존 법칙 (Tesler's Law)
- 모든 애플리케이션에는 제거할 수 없는 고유 복잡성이 있으며, 이동만 가능하고 제거는 불가능하다
- 핵심 질문: 복잡성을 누가 감당할 것인가 (사용자 vs 시스템)
- Calendly는 일정 조율의 복잡성을 시스템이 흡수하고, 이메일 스레드는 사용자에게 전가하는 차이
- 좋은 설계는 복잡성을 사용자 경험에서 시스템 내부로 이동시킴
- Larry Tesler가 Apple Lisa 및 초기 GUI 작업 중 1980년대에 정립
CAP 정리 (CAP Theorem)
- 분산 시스템은 일관성©, 가용성(A), 분할 내성℗ 중 두 가지만 보장 가능하다
- 네트워크 파티션은 현실에서 불가피하므로, 실질적 선택은 일관성 vs 가용성
- CP 시스템 (예: MongoDB): 파티션 발생 시 쓰기를 차단하여 모든 레플리카 동기화 유지
- AP 시스템 (예: Cassandra, DNS): 파티션 중에도 요청 응답 유지, 레플리카 간 일시적 불일치 허용
- Eric Brewer가 2000년에 웹 서비스 맥락에서 제안, Gilbert & Lynch가 2002년에 공식 증명
Second-System 효과 (Second-System Effect)
- 작고 성공적인 시스템 다음에는 과도하게 설계된 비대한 후속 시스템이 뒤따르는 경향
- 첫 번째 시스템의 성공에 자신감을 얻어 두 번째 시스템에 모든 아이디어를 쏟아붓는 패턴
- 기능 과잉(feature creep)과 과도한 일반화(over-generalization)가 주된 원인
- Frederick Brooks가 The Mythical Man-Month에서 식별
분산 컴퓨팅의 오류 (Fallacies of Distributed Computing)
- 분산 시스템을 처음 설계하는 사람들이 흔히 갖는 8가지 잘못된 가정
- 8가지 오류: (1) 네트워크는 신뢰할 수 있다, (2) 지연 시간은 0이다, (3) 대역폭은 무한하다, (4) 네트워크는 안전하다, (5) 토폴로지는 변하지 않는다, (6) 관리자가 한 명이다, (7) 전송 비용은 0이다, (8) 네트워크는 균일하다
- 이 가정들을 기반으로 설계하면 프로덕션에서 예기치 않은 장애와 성능 문제가 발생
의도하지 않은 결과의 법칙 (Law of Unintended Consequences)
- 복잡한 시스템을 변경하면 예기치 않은 결과를 예상해야 한다
- 시스템 하나의 컴포넌트를 변경하면 예측하지 못한 곳에서 부작용이 발생
- 카오스 엔지니어링과 포괄적 테스팅의 필요성을 뒷받침하는 원칙
Zawinski의 법칙 (Zawinski's Law)
- 모든 프로그램은 메일을 읽을 수 있을 때까지 확장을 시도한다
- 소프트웨어가 성공하면 점점 더 많은 기능을 추가하려는 기능 팽창(feature bloat) 현상을 풍자
- Jamie Zawinski(Netscape 초기 개발자)가 관찰
- 단순한 도구가 시간이 지나면 만능 플랫폼이 되려 하는 경향에 대한 경고
품질(Quality)
Boy Scout 규칙 (The Boy Scout Rule)
- 코드를 발견한 것보다 더 나은 상태로 남겨야 한다
- 대규모 리팩토링이 아닌 지속적이고 점진적인 개선이 핵심
- 혼란스러운 함수명 수정, 중복 코드 제거, 누락된 테스트 추가 등 매번 작은 개선을 실천
- Robert C. Martin(Uncle Bob)이 Clean Code(2008)에서 소프트웨어 개발에 적용
- Google 엔지니어들의 원칙 "If you touch it, you own it" — 코드를 수정하면 그 품질에 대한 책임도 함께 가져감
- 이 규칙을 실천하면 깨진 유리창 효과(Broken Windows)를 예방하고 기술 부채 축적을 방지
Murphy의 법칙 (Murphy's Law)
- 잘못될 수 있는 것은 반드시 잘못된다
- 방어적 프로그래밍, 예외 처리, 장애 대비 설계의 근거
- 소프트웨어에서는 "일어날 수 있는 에러는 반드시 일어난다"는 자세로 에러 핸들링과 폴백을 설계해야 함
Postel의 법칙 / 견고성 원칙 (Postel's Law)
- 자신이 하는 일에는 보수적으로, 타인으로부터 받는 것에는 관대하게
- API 설계 시 출력은 엄격하게 스펙을 준수하되, 입력은 다양한 형식을 유연하게 수용하는 원칙
- Jon Postel이 TCP/IP 프로토콜 설계 시 수립한 견고성 원칙(Robustness Principle)
- 시스템 간 상호운용성을 높이는 실질적 가이드라인
깨진 유리창 이론 (Broken Windows Theory)
- 나쁜 설계, 잘못된 결정, 저품질 코드를 방치하지 말 것
- 하나의 "깨진 유리창"(나쁜 코드)이 방치되면 추가적인 품질 저하를 유발
- 코드베이스에 TODO 주석, 죽은 코드, 미해결 경고가 쌓이면 새로운 코드도 낮은 수준으로 작성되는 경향
- 발견 즉시 작은 문제라도 수정하는 문화가 중요
기술 부채 (Technical Debt)
- 소프트웨어 개발 속도를 저하시키는 모든 요소
- Ward Cunningham이 1992년 OOPSLA에서 금융 메타포로 처음 사용: 코드 지름길을 택하면 미래에서 시간을 빌리는 것
- 원금(수정 비용) + 이자(지저분한 코드로 인한 지속적 생산성 저하)
- 의도적 기술 부채는 때로 합리적 (시장 출시 타이밍, 프로토타이핑)이지만 상환 계획이 필수
- 자동화 테스트 생략이 대표적 사례: 릴리스는 성공하지만 이후 변경 시마다 예상치 못한 버그 발생
- 해결 방법: 리팩토링, 누락 테스트 추가, 설계 개선
Linus의 법칙 (Linus's Law)
- 충분한 수의 검토자가 있으면 모든 버그는 쉽게 발견된다
- 오픈소스 개발의 핵심 원리: 다수의 눈이 코드를 검토하면 버그가 사소한 문제가 됨
- Eric Raymond가 The Cathedral and the Bazaar에서 Linus Torvalds의 이름을 따 명명
- 코드 리뷰 문화의 중요성을 뒷받침
Kernighan의 법칙 (Kernighan's Law)
- 디버깅은 코드를 처음 작성하는 것보다 두 배 어렵다
- 따라서 최대한 영리하게 코드를 작성하면, 디버깅할 때 충분히 영리하지 못하게 됨
- 가독성 높은 단순한 코드를 작성해야 하는 이유
- Brian Kernighan이 The Elements of Programming Style에서 제시
테스팅 피라미드 (Testing Pyramid)
- 프로젝트는 빠른 단위 테스트를 많이, 통합 테스트는 적게, UI 테스트는 소수만 보유해야 한다
- 단위 테스트(하단): 빠르고 저비용, 가장 많이 작성
- 통합 테스트(중간): 컴포넌트 간 상호작용 검증
- UI/E2E 테스트(상단): 느리고 깨지기 쉬우므로 최소화
- Mike Cohn이 Succeeding with Agile에서 소개한 테스트 전략 모델
살충제 역설 (Pesticide Paradox)
- 동일한 테스트를 반복 실행하면 시간이 지남에 따라 효과가 감소한다
- 기존 테스트가 이미 잡을 수 있는 버그는 다 잡았으므로, 새로운 테스트 케이스를 지속적으로 추가해야 함
- 테스트 세트를 정기적으로 검토하고 업데이트하는 것이 필수
Lehman의 소프트웨어 진화 법칙 (Lehman's Laws of Software Evolution)
- 현실 세계를 반영하는 소프트웨어는 반드시 진화해야 하며, 그 진화에는 예측 가능한 한계가 존재한다
- E-type(현실 세계를 반영하는) 소프트웨어는 사용되려면 지속적 변경이 불가피
- 변경 시마다 복잡성이 증가하며, 이를 적극적으로 관리하지 않으면 품질이 저하
Sturgeon의 법칙 (Sturgeon's Law)
- 모든 것의 90%는 쓸모없다
- Theodore Sturgeon이 SF 문학 비평에 대응하여 제시
- 소프트웨어에도 적용: 대부분의 코드, 도구, 프레임워크 중 진정으로 훌륭한 것은 소수
- 품질에 대한 높은 기준을 유지하고, 가치 있는 10%에 집중하는 자세 필요
스케일(Scale)
Amdahl의 법칙 (Amdahl's Law)
- 병렬화로 인한 속도 향상은 병렬화할 수 없는 작업 비율에 의해 제한된다
- 프로그램의 5%가 순차적이면 아무리 많은 프로세서를 투입해도 이론적 최대 속도 향상은 20배
- 병렬화의 한계를 인식하고 순차적 병목 구간을 줄이는 것이 더 효과적
- Gene Amdahl이 1967년에 제시
Gustafson의 법칙 (Gustafson's Law)
- 문제 크기를 늘림으로써 병렬 처리에서 상당한 속도 향상을 달성할 수 있다
- Amdahl의 법칙에 대한 보완적 관점: 고정된 문제가 아닌 확장 가능한 문제에서는 프로세서 추가가 효과적
- 빅데이터 처리, 과학 시뮬레이션 등에서 더 많은 리소스로 더 큰 문제를 풀 수 있음
Metcalfe의 법칙 (Metcalfe's Law)
- 네트워크의 가치는 사용자 수의 제곱에 비례한다
- 사용자가 10명이면 가치는 100 단위, 100명이면 10,000 단위로 증가
- 소셜 네트워크, 메신저, 마켓플레이스 등 네트워크 효과의 이론적 기반
- Robert Metcalfe가 이더넷 기술의 가치를 설명하기 위해 제시
설계(Design)
DRY 원칙 (Don't Repeat Yourself)
- 모든 지식은 단일하고 명확하며 권위 있는 하나의 표현만 가져야 한다
- 코드 중복뿐 아니라 지식, 로직, 데이터의 중복도 포함
- 중복은 변경 시 여러 곳을 동시에 수정해야 하므로 버그와 불일치의 원인
- Andy Hunt와 Dave Thomas가 The Pragmatic Programmer에서 정립
KISS 원칙 (Keep It Simple, Stupid)
- 설계와 시스템은 가능한 한 단순해야 한다
- 복잡성은 이해, 유지보수, 디버깅의 비용을 증가시킴
- 단순한 해결책이 대부분의 경우 더 효과적이며 결함 가능성도 낮음
- 미국 해군이 1960년대에 제시한 설계 원칙에서 유래
SOLID 원칙 (SOLID Principles)
- 소프트웨어 설계를 향상시키는 5가지 핵심 가이드라인
- S — 단일 책임 원칙(Single Responsibility): 클래스는 하나의 이유로만 변경
- O — 개방-폐쇄 원칙(Open-Closed): 확장에 열려 있고 수정에 닫혀 있어야 함
- L — Liskov 치환 원칙: 하위 타입은 상위 타입을 대체할 수 있어야 함
- I — 인터페이스 분리 원칙: 클라이언트는 사용하지 않는 인터페이스에 의존하지 않아야 함
- D — 의존성 역전 원칙: 상위 모듈이 하위 모듈에 의존하지 않고 추상화에 의존
- Robert C. Martin이 정립하고 Michael Feathers가 SOLID라는 약어를 명명
디미터 법칙 (Law of Demeter)
- 객체는 직접적인 친구와만 상호작용해야 하며, 낯선 객체와의 직접 소통은 지양해야 한다
- a.getB().getC().doSomething() 같은 체인 호출을 피해야 한다는 원칙
- 결합도를 낮추고 캡슐화를 강화하여 변경 영향 범위를 줄임
- "최소 지식의 원칙"이라고도 불림
최소 놀라움의 원칙 (Principle of Least Astonishment)
- 소프트웨어와 인터페이스는 사용자와 다른 개발자를 가장 적게 놀라게 하는 방식으로 동작해야 한다
- 함수, API, UI가 이름과 컨벤션에서 예측 가능한 동작을 해야 함
- delete() 함수가 실제로는 아카이브만 한다면 놀라움을 유발 → 설계 결함
- 직관적이지 않은 동작은 버그와 사용자 실수를 초래
YAGNI (You Aren't Gonna Need It)
- 필요하기 전까지 기능을 추가하지 말 것
- Extreme Programming(XP)의 핵심 원칙으로 1990년대 후반 Ron Jeffries가 제시
- "미래에 필요할지 모른다"는 이유로 코드를 작성하면 과잉 설계와 유지보수 부담 발생
- 리팩토링에 대한 자신감(좋은 테스트 커버리지, CI)이 있어야 YAGNI를 실천 가능
- 현재 JSON 내보내기만 필요하면 JSON만 구현, XML/YAML 등은 요구될 때 추가
의사결정(Decisions)
Dunning-Kruger 효과 (Dunning-Kruger Effect)
- 어떤 것에 대해 적게 알수록 더 자신감을 갖는 경향이 있다
- 초보 개발자가 복잡한 시스템의 난이도를 과소평가하거나, 전문가가 오히려 자신의 지식에 겸손한 현상
- 코드 리뷰, 멘토링, 지속 학습을 통해 자기 인식의 정확성을 높이는 것이 중요
Hanlon의 면도날 (Hanlon's Razor)
- 어리석음이나 부주의로 충분히 설명되는 것을 악의로 돌리지 말 것
- 동료의 나쁜 코드나 잘못된 결정을 의도적 방해로 해석하기 전에 무지, 실수, 시간 부족을 먼저 고려
- 팀 내 신뢰와 건설적 커뮤니케이션의 기반
Occam의 면도날 (Occam's Razor)
- 가장 단순한 설명이 가장 정확한 경우가 많다
- 디버깅 시 복잡한 원인보다 가장 단순한 가능성부터 먼저 확인
- 아키텍처 설계에서도 불필요한 추상화 레이어를 추가하기 전에 단순한 해결책을 우선 탐색
매몰 비용 오류 (Sunk Cost Fallacy)
- 시간이나 에너지를 투자했다는 이유만으로 손해가 되는 선택을 계속 유지하는 현상
- 6개월 동안 개발한 기능이 잘못된 방향이었더라도 투자한 시간 때문에 버리지 못하는 심리
- 올바른 결정은 과거 투자가 아닌 미래 가치를 기준으로 해야 함
지도는 영토가 아니다 (The Map Is Not the Territory)
- 현실에 대한 표현(모델)은 현실 자체와 동일하지 않다
- UML 다이어그램, 아키텍처 문서, 데이터 모델 등은 현실의 근사치일 뿐
- 모델을 맹신하지 말고, 실제 시스템의 동작을 관찰하며 모델을 갱신해야 함
확증 편향 (Confirmation Bias)
- 기존 믿음이나 아이디어를 지지하는 정보를 선호하는 경향
- 자신이 선택한 기술 스택이나 설계 결정에 유리한 정보만 선별적으로 수집하는 함정
- 반대 증거를 적극적으로 탐색하고 다양한 관점을 수용하는 것이 균형 잡힌 의사결정의 핵심
Hype Cycle과 Amara의 법칙 (The Hype Cycle & Amara's Law)
- 기술의 단기 효과는 과대평가하고, 장기 영향은 과소평가하는 경향이 있다
- Gartner의 Hype Cycle: 기술 촉발 → 과도한 기대의 정점 → 환멸의 골짜기 → 계몽의 경사 → 생산성 안정기
- 새 기술(블록체인, AI 등)을 도입할 때 단기 과열에 휩쓸리지 말고 장기적 실용성을 평가해야 함
Lindy 효과 (The Lindy Effect)
- 오래 사용된 것일수록 앞으로도 계속 사용될 가능성이 높다
- UNIX, SQL, C 언어처럼 수십 년간 사용된 기술은 앞으로도 오래 생존할 가능성이 높음
- 새로운 프레임워크보다 검증된 기술을 선택할 때의 이론적 근거
- Nassim Nicholas Taleb이 Antifragile에서 대중화
제1원리 사고 (First Principles Thinking)
- 복잡한 문제를 가장 기본적인 구성 요소로 분해한 후 그로부터 재구축하는 사고법
- 기존 관행과 가정을 제거하고 근본적 진실에서 출발하여 해결책을 도출
- Elon Musk가 SpaceX 로켓 비용 절감에 적용한 사례로 유명
- 복잡한 시스템 설계 시 "원래 다 그렇게 하니까"라는 사고를 경계
역전 사고 (Inversion)
- 반대 결과를 상정하고 거꾸로 추론하여 문제를 해결하는 방법
- "어떻게 성공할까" 대신 "어떻게 하면 실패할까" 를 먼저 생각하여 위험 요소를 식별
- 장애 모드 분석(Failure Mode Analysis)과 프리모템(Pre-mortem)의 이론적 근거
- Charlie Munger가 자주 활용하는 멘탈 모델
파레토 원칙 / 80/20 법칙 (Pareto Principle)
- 문제의 80%는 원인의 20%에서 발생한다
- 전체 버그의 80%가 코드의 20%에 집중되어 있는 경향
- 가장 영향력이 큰 20%에 리소스를 집중하는 것이 효율적 자원 배분 전략
- Vilfredo Pareto가 이탈리아 토지 소유 분포에서 관찰한 원리에서 유래
Cunningham의 법칙 (Cunningham's Law)
- 인터넷에서 정확한 답을 얻는 가장 좋은 방법은 질문이 아니라 틀린 답을 게시하는 것이다
- 사람들은 질문에 답하는 것보다 잘못된 정보를 교정하는 데 더 적극적으로 참여
- Ward Cunningham(Wiki 발명자)의 이름을 딴 법칙이지만, 실제로는 Steven McGeady가 이 이름을 붙임
- 오픈소스 커뮤니티에서 문서화나 지식 공유에 활용 가능한 통찰
AI 코딩 시대, 성장이 멈추는 개발자의 뇌에서 일어나는 일
- https://evan-moon.github.io/2026/04/18/developers-who-stopped-growing-in-ai-era/
TL;DR;
- AI를 잘 쓰는 핵심 역량은 출력물의 품질을 판단하고 교정하는 능력이며, 이 능력은 AI에 의존할수록 오히려 약화됨 - Bjork의 "바람직한 어려움" 이론에 따르면, 쉽게 처리한 정보는 장기 기억에 남지 않음 - Roediger & Karpicke(2006) 연구에서 인출 연습 그룹의 일주일 후 기억 보존율이 반복 읽기 그룹보다 약 50% 높았음 - AI가 코드를 대신 작성하면 본질적 인지 부하(germane load) 까지 제거되어 스키마 형성 기회 자체가 사라짐 - 숙련된 개발자일수록 신경 효율성으로 인해 AI 출력을 읽는 것만으로는 뇌에 걸리는 부하가 거의 없음 - AI 이전에도 성장이 멈추는 경로는 존재했지만, AI는 그 경로의 마찰을 극적으로 제거함
상세 요약
AI를 잘 쓰려면 코드를 알아야 하는 역설
- "이걸 만들어줘"라고 말할 수 있는 사람은 많지만, AI 결과물을 보고 "이 구조는 변경에 취약하다", "이 인터페이스는 두 가지 책임을 가지고 있다"고 구체적으로 교정할 수 있는 사람은 훨씬 적음 - 이 능력은 수많은 실패와 디버깅과 리팩토링 경험에서 형성된 직감에 가까움 - AI 사용법 학습과 코드 패턴 학습은 양자택일 관계가 아니라, 후자가 전자의 토대인 관계임 "AI를 가장 잘 활용할 수 있는 개발자는 AI 없이도 코드를 판단할 수 있는 개발자"
뇌는 편하면 기억하지 않는다
- Bjork의 "바람직한 어려움": 학습 과정에 적절한 난이도와 저항이 존재할 때 단기 수행은 느려지지만 장기 기억 보존과 전이는 향상됨 - Roediger & Karpicke(2006): 반복 읽기 vs 인출 연습 실험 - 5분 후 테스트: 반복 읽기 그룹 성적이 더 높음 - 일주일 후 재테스트: 인출 연습 그룹의 기억 보존율이 약 50% 더 높음 - 능동적 인출 그룹은 해마–전두엽 피질 연결성이 강화되고 감각운동 네트워크 활성도 증가 - 수동 학습 상태의 뇌는 해마–방추상회 연결만 활성화 — "정보를 보고 있을 뿐 처리하지 않는 것"에 가까움 - 생성 효과 (Slamecka & Graf, 1978): "뜨거운-차___" 처럼 직접 완성한 그룹이 완성된 쌍을 읽은 그룹보다 기억 보존율이 유의미하게 높음 - 유창성의 착각: 정보를 쉽게 처리할 수 있다는 느낌이 잘 기억할 것이라는 착각으로 이어짐
코딩 실력은 절차 기억이다
- 코딩 실력의 상당 부분은 절차 기억 — 자전거 타기처럼 한번 체화되면 의식하지 않아도 자동 실행됨 - Anderson의 적응적 사고 통제(ACT) 모델: 절차 기억 형성 3단계 - 인지 단계: 모든 것을 의식적으로 한 단계씩 실행, 작업 기억 대부분 소모 - 연합 단계: 개별 절차들이 통합되어 하나의 흐름으로 실행 가능 - 자동화 단계: 작업 기억 거의 차지하지 않고 자동 실행 — 남은 여유를 설계 판단에 활용 가능 - 단계 전환은 반복적인 직접 수행을 통해서만 진행됨 - 청킹 (Chase & Simon 체스 연구): 전문가와 초보자의 차이는 작업 기억 슬롯 수가 아니라, 하나의 청크에 담을 수 있는 정보의 양 체스 고수는 말의 개별 위치가 아닌 "시실리안 디펜스의 전형적인 중반 배치" 같은 의미 있는 패턴을 하나의 청크로 인식 무작위 배치 실험에서 고수와 초보자 차이가 사라짐으로써 입증됨
AI는 이 과정을 방해한다
- AI에게 구현을 맡기면 본질적 인지 부하(germane load) 까지 AI가 대신 처리 — 스키마 구축 기회 자체가 사라짐 - 절차 기억 관점: 인지 단계에서 끙끙대는 시간이 줄어 연합 단계 전환이 지연되고 자동화 단계 도달이 어려워짐 - AI 출력 코드를 읽는 것은 생성 효과 실험의 "완성된 단어 쌍을 읽는 것"에 해당 — 이해한 것 같지만 깊이 각인되지 않음 - 숙련된 개발자일수록 신경 효율성으로 코드를 더 적은 자원으로 처리 → AI 출력 읽기는 생각보다 뇌에 부하를 거의 걸지 않음 - 직접 코드를 짤 때는 예측–피드백 루프로 시냅스가 수정되지만, 완성된 AI 코드 읽기는 예측 과정이 생략된 사후 해석에 불과함 - 주니어에게 특히 심각: 인지 단계에 있는 패턴이 많은 상태에서 AI가 그 단계를 건너뛰게 하면 절차 기억 형성 없이 경력만 쌓임
뇌에 부하를 거는 방법
- AI에게 맡기기 전에 먼저 자신의 설계안 작성: 생성 효과를 의도적으로 활용 — AI 출력과 비교·평가하는 과정에서 뇌의 의미 처리와 실행 - 제어 영역이 동시 활성화 - 진지한 코드 리뷰: "왜 이 구조인가", "6개월 뒤에 수정한다면 어디가 문제가 될까"를 의식적으로 묻는 것 — 귀찮음 자체가 바람직한 - 어려움 - 직접 코드를 짜보는 시간 확보: 절차 기억 형성에 대체 불가능 — 막혔을 때는 전체 답이 아닌 최소한의 힌트만 AI에게 요청 - 생산과 학습의 최적 전략은 다름: AI는 생산 도구로는 탁월하지만, 학습 도구로는 한계가 있음 - 결국 뇌에 남은 것들이 코드 리뷰의 질, 설계 판단의 정확도, 역설적으로 AI 활용 능력을 결정함
Why 2026 Seniors are just highly-paid Code Editors, on Addy Osmani
Google Cloud AI 디렉터이자 전 Chrome 엔지니어링 리더인 Addy Osmani가 2026년 JS Nation US(뉴욕) 컨퍼런스 인터뷰에서 밝힌, AI 시대 시니어 개발자 역할의 본질적 변화에 대한 대담입니다. Osmani는 Learning JavaScript Design Patterns, Leading Effective Engineering Teams 등 14~15권의 기술서를 저술한 인물로, 2025년 "The AI-Native Software Engineer" 강연과 Substack의 "70% 문제", "80% 문제" 시리즈를 통해 AI 코딩의 현실적 한계를 꾸준히 짚어왔습니다. 이번 인터뷰는 그 연장선에서, 시니어 엔지니어가 코드 작성자에서 코드 편집자(Editor)로 전환되고 있는 현상을 다각도로 풀어냅니다.
AI 코딩 1년 후의 풍경
- 개발자 90%가 AI를 코딩에 활용하고 있으나, 신뢰도는 오히려 하락 추세에 있습니다 - 새 프로젝트나 프로토타입(MVP)에는 효과적이지만, 대규모 코드베이스나 엔터프라이즈 환경에서는 여전히 격차가 뚜렷합니다 - PR(풀 리퀘스트) 크기가 크게 증가하고 있으며, AI가 필요 이상의 파일을 건드리거나 기존 유틸리티 함수를 재활용하지 않고 새로 구현하는 경우가 빈번합니다 - Osmani가 이전 글에서 "70% 문제"로 명명한 현상은 여전히 유효합니다. AI가 70%까지 데려다 주지만 나머지 30%의 품질, 정합성, 라스트 마일(최종 마무리 작업)은 사람의 몫입니다
바이브 코딩 vs AI 보조 엔지니어링
- 바이브 코딩(Vibe Coding)은 아이디어의 실현 가능성을 빠르게 탐색하는 자유로운 방식으로, 코드 리뷰에 크게 신경 쓰지 않는 접근입니다 - AI 보조 엔지니어링은 아키텍처, 보안, 성능, 품질 등 전통적 엔지니어링 원칙을 유지하면서 AI를 도구로 활용하는 방식입니다 - 프로덕션 코드에는 후자가 필수이며, 이때 "컨텍스트 엔지니어링"(모델에 문서, 예시, 대화 이력, 코드베이스 구조 등 풍부한 맥락을 제공하는 기법)이 결과물 품질을 좌우합니다
시니어 엔지니어의 새 역할: 코드 에디터
- 개발자의 핵심 역할이 코드를 작성하는 사람에서 코드를 평가하고 편집하는 사람으로 이동하고 있습니다. 제목이 시사하는 "highly-paid Code Editors"의 의미가 여기에 있습니다 - 코드 리뷰가 주니어 교육의 핵심 현장이 되고 있으며, "AI가 왜 이 접근법을 선택했는가"를 따져 묻는 비판적 사고가 그 어느 때보다 중요합니다 - 한 연구에 따르면, 엔지니어들이 "겉보기엔 맞지만 실제로는 틀린" AI 코드를 디버깅하는 데 상당한 시간을 소모하고 있다고 합니다. Osmani는 이를 "이해도 부채(comprehension debt)"라는 개념으로 후속 글에서 확장한 바 있습니다
백그라운드 에이전트의 실전 활용
- Osmani는 산책 중 GitHub 앱으로 서너 개의 작업을 에이전트에 맡기고, 돌아올 때쯤 PR을 받는 방식을 쓰고 있습니다. "이슈가 아니라 PR을 원한다"는 표현이 인상적입니다 - 소규모~중규모 프로젝트에 한정하며, 엔터프라이즈에는 아직 권하지 않습니다 - 에이전트를 하나만 쓰는 "지휘자(conductor)" 단계에서 여러 에이전트를 동시에 관리하는 "오케스트레이터(orchestrator)" 단계로 전환되고 있다는 비유를 사용합니다
Chrome DevTools MCP와 Figma MCP
- 2025년 말 출시된 Chrome DevTools MCP(Model Context Protocol)는 코딩 에이전트에 "눈"을 부여합니다. 에이전트가 실제 렌더링 결과를 확인하고, 콘솔 로그와 네트워크 정보까지 활용할 수 있게 됩니다 - Figma MCP와 조합하면 디자인 파일을 구현한 뒤 실제 화면을 검증하는 흐름이 가능합니다. 다만 기존 UI 컴포넌트 라이브러리를 자동으로 재활용하는 수준에는 아직 도달하지 못했습니다
브라우저 AI의 미래와 신뢰 문제
- 브라우저가 보유한 풍부한 컨텍스트(로그인 정보, 캘린더, 검색 이력 등)를 활용한 사용자 여정 자동화가 다음 단계이지만, 결제나 개인정보가 관여되는 지점에서 사람의 확인을 유지하는 신뢰 설계가 관건입니다 - Osmani는 "100% 자동화가 아니라, 사용자가 눈썹을 치켜올릴 만한 단계에서 반드시 멈춰야 한다"고 강조합니다
주니어 개발자에 대한 조언
- AI가 아직 해결하지 못하는 영역에서 깊은 전문성을 쌓을 수 있다면 오히려 차별화의 기회입니다 - 프로그래밍 언어나 스택이 무의미해진다는 극단적 견해에 대해 Osmani는 "기초와 펀더멘탈을 이해하는 것이 여전히 초능력(superpower)"이라고 반박합니다
시사점
- 이 대담의 핵심 메시지는 명확합니다. AI가 코드를 대신 써주는 시대에, 시니어 엔지니어의 가치는 코드를 작성하는 속도가 아니라 코드를 읽고, 판단하고, 맥락을 부여하는 능력에 있습니다. "고연봉 코드 편집자"라는 다소 도발적인 제목은, 그것이 폄하가 아니라 오히려 이 시대가 요구하는 핵심 역량이라는 역설을 담고 있습니다 - Osmani가 70%에서 80%로 숫자를 올린 것처럼, 에이전트의 완성도는 분명 높아지고 있습니다. 그러나 나머지 20~30%를 메우는 "이해도 부채"의 관리 비용은 줄지 않았고, 이 격차를 줄이는 것이 앞으로 도구와 엔지니어 양쪽 모두의 과제로 남아 있습니다
컴퓨터공학 교육에서 빠진 학기 – 2026년 개정판 (missing.csail.mit.edu)
- 대학의 전통적인 컴퓨터공학 과정에서 다루지 않는 도구 활용 능력을 집중적으로 가르치는 MIT의 실습 중심 강의 - 명령줄, 텍스트 편집기, 버전 관리 시스템 등 개발자가 매일 사용하는 핵심 도구를 효율적으로 다루는 방법을 교육 - 2026년판에서는 AI 기반 개발 도구와 워크플로우를 각 강의에 통합해, 최신 실무 환경에 맞춘 학습 구조를 제공 - 강의는 YouTube 영상으로 공개되어 있으며, OSSU Discord에서 학생과 강사진 간 토론이 가능 - MIT 외부에서도 자유롭게 활용할 수 있도록 오픈소스와 다국어 번역을 지원, 전 세계 개발자 교육에 기여
강의 개요
- 컴퓨터공학 수업이 운영체제나 머신러닝 같은 고급 주제를 다루는 반면, 개발 도구 숙련도는 학생 스스로 익혀야 하는 영역으로 남아 있음 - 본 강의는 명령줄, 강력한 텍스트 편집기, 버전 관리 시스템의 고급 기능 등 실무 필수 기술을 체계적으로 다룸 - 학생들이 학업과 경력 전반에서 수백~수천 시간을 사용하는 도구를 더 효율적이고 매끄럽게 활용하도록 돕는 목적 - 이러한 도구 숙련은 문제 해결 속도를 높이고, 복잡한 문제를 다룰 수 있는 능력을 확장함
AI 통합 학습
- 2026년판에서는 AI 지원 개발 도구와 워크플로우가 소프트웨어 엔지니어링 전반에 확산되고 있음을 반영 - AI의 한계와 적절한 활용법을 인식한 상태에서 사용할 경우, CS 실무자에게 큰 이점을 제공 - 별도의 AI 강의는 없으며, 각 주제별 강의에 최신 AI 도구와 기법을 직접 통합
강의 일정
- 2026년 1월 12일부터 1월 23일까지 총 9회차로 구성 - 주요 주제: Shell 소개, 명령줄 환경, 개발 환경 및 도구, 디버깅과 프로파일링, Git 버전 관리, 코드 배포, Agentic Coding, 코드 품질 등 - 모든 강의는 YouTube 재생목록을 통해 시청 가능
참여 및 커뮤니티
- 수강생은 OSSU Discord의 #missing-semester-forum 채널에서 질문과 토론 가능 - 강의는 Anish, Jon, Jose가 공동 진행하며, 문의는 이메일(missing-semester@mit.edu)로 가능
MIT 외부 확산
- 강의 자료는 MIT 외부에도 공개되어 있으며, Hacker News, Lobsters, Reddit, X, Bluesky, Mastodon, LinkedIn 등 다양한 플랫폼에서 논의됨 - 2019, 2020, 2026년판 모두 온라인에서 활발히 공유되어 있음
번역 및 오픈소스
- 아랍어, 중국어, 독일어, 일본어, 한국어 등 15개 이상 언어로 커뮤니티 번역본이 존재 - 번역본은 외부 커뮤니티가 제작했으며, 공식 검수는 거치지 않음 - 새로운 번역본은 GitHub Pull Request를 통해 추가 가능 - 강의 자료는 CC BY-NC-SA 라이선스로 공개되어 있으며, 소스코드는 GitHub에서 확인 가능
감사의 말
- MIT Open Learning과 SIPB의 지원으로 강의 영상 제작 및 IAP 2026 프로그램 운영이 가능했음
- https://kr.themodernsoftware.dev/
- https://missing.csail.mit.edu/
시니어 엔지니어로서 배운 것들 (2021)
- 10년 경력의 데이터 엔지니어가 술에 취한 상태에서 커리어, 기술, 동료, 삶에 대해 솔직하게 적은 글로, Reddit r/ExperiencedDevs에 원래 게시되었던 글의 보존본
- 기술 스택 자체보다 각 분야의 10~20가지 핵심 원칙이 중요하며, 스택은 그것을 쉽게 만드는 도구에 불과
- 커리어 성장의 가장 효과적인 방법은 이직이며, 불만족스러운 직장에 머무를 이유가 없음
- 좋은 코드란 주니어 엔지니어도 이해할 수 있는 코드이고, 최고의 코드는 코드가 없는 것
- 자기 가치를 보상이나 직급에 연결하지 말 것, 친절함과 노력이 장기적으로 커리어와 삶 모두를 바꿔줌
나는 술에 취해 있고 아마 후회하겠지만, 지난 10년간 엔지니어로서 배운 것들의 취중 랭킹을 적어본다.
- 커리어를 발전시킨 가장 좋은 방법은 회사를 옮기는 것
- 기술 스택은 크게 중요하지 않음 — 데이터 분야에는 약 15가지 기본 패턴이 존재하고, 모든 분야에 10~20개의 핵심 원칙이 있으며, 기술 스택은 그것을 쉽게 만드는 도구일 뿐이니 너무 걱정하지 말 것
- 사람들이 이직을 추천하는 데는 이유가 있음 — 직장에 불만이 있다면 떠날 때
- 회사에서 좋은 평생 친구를 만들기도 했지만, 그것이 모든 직장의 요건이 될 필요는 없음 — 친구 없이도 행복했던 직장, 좋은 친구가 있어도 불행했던 직장 모두 경험
- 매니저에게 적당히 솔직해지는 법을 배움 — 너무 솔직하진 않되, 직장에서 진정성을 유지할 정도로. 최악의 경우? 해고? 2주면 새 직장을 구함
- 분기에 한 번 이상 새벽 2시에 온콜로 깨는 상황이면, 심각한 문제가 있는 것이므로 고치든지 그만두든지 해야 함
한 잔 더 따르며
- 좋은 매니저의 자질은 좋은 엔지니어의 자질과 많이 겹침
- 처음 시작했을 때는 기술과 프로그래밍과 컴퓨터 과학에 매료되었지만, 이제는 그 시절이 지남
- 좋은 코드는 주니어 엔지니어가 이해할 수 있는 코드, 훌륭한 코드는 CS 1학년도 이해 가능, 최고의 코드는 코드가 아예 없는 것
- 엔지니어로서 가장 과소평가된 스킬은 문서화 — 좋은 문서 작성법을 알려주는 사람이 있다면 진심으로 돈을 내겠음, 1천 달러짜리 강좌라도 좋은 문서를 쓸 수 있게 보장해 준다면 지불 의향
- 위와 관련하여, 변경 사항에 대한 좋은 프로포절 작성도 훌륭한 스킬
- 거의 모든 종교 전쟁 (vim vs emacs, mac vs linux 등)은 중요하지 않음… 하나만 빼고. 아래 참조
- 나이가 들수록 동적 언어에 대한 감사함이 커짐. 맞다, 내가 말했다. 덤벼라
- 방에서 가장 똑똑한 사람이라고 느끼는 순간이 있다면, 떠날 시기
- 풀스택 웹 개발자가 왜 이렇게 적게 받는지 이해 불가 — 프런트엔드, 백엔드, 브라우저 호환성, 네트워킹, 데이터베이스, 캐싱, 웹과 모바일 차이, 끊임없이 나오는 새 프레임워크까지 전부 이해해야 함. 기본 연봉 50만 달러는 받아야 함
- 인턴을 더 많이 채용해야 함 — 에너지 넘치고 아이디어 가득한 녀석들. 질문하고 비판할 줄 아는 인턴이 최고
한 모금
- 영웅을 만나지 말 것 — 영웅의 5천 달러 강좌를 들었는데, 그는 훌륭한 사람이지만 결국 나머지 사람들처럼 즉흥으로 하고 있었음
- 기술 스택이 중요하기도 함 — Python 개발자 vs C++ 개발자를 떠올리면 전혀 다른 이미지, 특정 도구가 특정 작업에 특화되어 있기 때문. 뭘 해야 할지 모르겠으면 Java를 하면 됨 — 별로인 언어지만 거의 모든 것에 괜찮음
- 최고의 프로그래밍 언어는 Lisp. Lisp를 배워야 함
- 초보자에게 가장 수익성 높은 언어는 SQL — 다른 언어 다 필요 없음. SQL만 알면 돈을 벌 수 있음. 급여 담당자 50k → SQL 아는 급여 담당자 90k. 조직력 있는 평범한 직장인 40k → SQL까지 아는 사람은 PM이라 부르고 150k
- 테스트는 중요하지만 TDD는 컬트
- 안정적인 공무원 직장은 기대만큼 좋지 않음 (초중반 경력 기준) — 120k + 복지 + 연금은 좋아 보이지만 독점적 기술에 영혼을 팔게 됨. 엔지니어 평균 연령이 50+인 이유가 있음. 정부 계약직에는 해당 안 됨
- 서드파티 리크루터는 기생충 — 그러나 좋은 리크루터를 찾으면 관계를 키울 것. 3년 이상 서드파티 리크루터를 한 사람은 보통 별로, 좋은 사람들은 대기업 리크루터로 전환
- 스톡옵션은 무가치하거나 백만장자를 만들어 줌 — 엔지니어링 인원이 100명 이상이 아니면 보통 무가치
- 재택근무는 최고. 그러나 화이트보드 부재가 아쉬움
- FAANG에서 일해본 적 없음 — 뭘 놓치는지 모르겠지만, FAANG 출신을 면접하고 채용해 봤는데 그들도 뭘 하는지 모르긴 마찬가지
- 자기 가치는 총 보상과 상관없고 상관있어서도 안 됨 — 자본주의는 자기 가치를 판단하는 좋은 기준이 아님
- 매니저는 생각보다 권한이 훨씬 적음 — 누군가를 해고하지 않는 이유는 못하기 때문
- 직급은 대부분 중요하지 않음 — 어느 회사의 Principal Distinguished Staff Lead Engineer든 상관없음. 중요한 것은 무엇을 했고 무엇을 달성했는가
- 직급 관련 추가: 커리어 초기(10년 미만)에는 직급 상승이 좋음 — 스킬과 책임 성장. 커리어 후반에는 직급 하향이 유리 — 같은 보상을 받으면서 승진 시 급여 인상 가능
- 401k를 최대한 채울 것
- 모든 사람에게 친절할 것 — 커리어에 도움이 되기 때문이 아니라(도움 되긴 하지만), 친절함 자체가 보상이기 때문
- 지난 한 달간 주니어 엔지니어나 인턴에게서 배운 것이 없다면, 주의를 기울이지 않은 것
이런, 와인이 다 떨어졌다.
- 수업, 책, 컨퍼런스에 돈을 쓸 가치 있음 — 여러 컨퍼런스, 1.5k짜리 강좌, 많은 책, 구독에 투자했고 가치 있었음. 이렇게 하면 뭘 하는 척 더 잘할 수 있음
- 진심으로, 웹 개발자들은 왜 더 못 받는 건지? 그들은 모든 걸 알잖아!!!
- 손목터널과 허리 문제는 농담이 아님 — 지금 1천 달러 써서 좋은 장비를 구할 것
- 함께 일했던 가장 똑똑한 사람은 수학 박사 — 그에게서 정말 많이 배움. 잘 지내고 있길 바람
- 고등학교 때 절친이었던 여자 친구 이야기 — 사귄다는 소문에 그녀가 무시하기 시작. 기분이 좋지 않았지만 악감정은 없으며, 그때 더 잘 대처했어야 함
- 8학년 때 여자친구와 헤어지고 싶었지만 말하지 못하고 무시하기 시작 — 정말 나쁜 행동이었음. Lena에게 미안함
- 소프트웨어 엔지니어의 가장 좋은 점은 같은 방식으로 문제를 생각하는 사람들을 만나고 대화할 수 있다는 것. 같은 취미가 아니라 같은 사고방식
- 기술 업계에 여성이 충분하지 않음 — 조직 내 여성 엔지니어를 격려하고 돕고 있지만 더 무엇을 해야 할지 모름
- 흑인 엔지니어도 마찬가지
- 기술을 깊이 알게 되기 전에는 싫어한 적이 없음 — 싫어하면서도 동시에 클라이언트에게 추천할 수 있다면 좋은 기술. Jenkins은 끔찍하지만 추천해도 소프트웨어 과실은 아님
- git은 끔찍하지만 선택의 여지가 없음 — GUI 도구는 지옥이고, 커맨드 라인이 나음. 외울 명령어는 7개 정도, 나머지는 구글 검색
- 데이터 엔지니어니까 데이터 관련 교훈도 하나. Pandas 쓰지 마라
- 팀에 반기술적(semi-technical) 애널리스트가 있어 일이 더 쉬움 — 프로그래밍은 알지만 소프트웨어 엔지니어링은 모르는 사람들. 그들이 이해 못하면 설계가 잘못된 것. 가장 뛰어난 엔지니어보다 애널리스트들에게서 더 많이 성장
- 다크 모드는 라이트 모드 강제 전환 시 고통 — 그래서 라이트 모드 사용
- 보안에 대해 아는 것은 보안을 잘 모른다는 것을 아는 정도
이런, 와인이 다 떨어졌다.
- 좋은 엔지니어는 베스트 프랙티스를 아는 것, 시니어 엔지니어는 베스트 프랙티스를 언제 깨야 하는지 아는 것
- 버그나 장애에 책임을 돌리려는 환경이면 떠날 시기
- 진보적 회사, 특히 스타트업은 "진짜 자신을 가져오라"고 하지만 — 진짜 자신이 포르노 시청이 전부라면? 일과 사생활 사이에 건강한 경계를 유지하는 것이 중요
- 동료와 해피아워에서 술 마시는 건 좋아하지만, 차라리 아이들, 가족, 친구와 시간을 보내겠음
- 최고의 리더십 사례: 리더가 100% 본인 잘못인 실수의 책임을 대신 짐 — 그 리더를 위해서라면 불 속이라도 뛰어들 것
- 같은 맥락에서, 최고의 리더들은 본인의 의견을 대변하는 동시에, 충돌하는 다른 의견도 설명해 줌. 그들처럼 되려고 노력 중
- 사이드 프로젝트는 집어치워라 — 좋아한다면 해도 됨! 시간이 있어도 Reddit에 취중 글 쓰느라 너무 바쁨
- 알고리듬과 자료구조는 중요 — 하지만 한도가 있음. 약사 면접에서 유기화학 퀴즈를 내지 않듯, 업계의 면접 프로세스에 문제가 있음
- DevOps 엔지니어들은 정말 똑똑함. 최소한 그 사람들은 제대로 보상받는 편
- 좋아하는 일을 하는 것보다 싫지 않은 일을 하는 것이 더 중요
- 제품에 가까이 있을수록, 매출에 가까울수록 가치를 인정받는 느낌이 강함 — 기술적 수준과 무관, 가장 진보적인 회사에서도 마찬가지
- Linux는 중요 — Windows 환경에서도. 왜? 결국 Linux를 쓰게 되기 때문. 주말에 Arch 설치하며 놀았던 시간에 감사
- "빅 데이터" 같은 모호한 버즈워드를 경계해야 함 — Spark/Kafka에서 10분마다 1만 행 스트리밍도, Python/MySQL에서 시간당 10억 행 배치도 경험했는데, 라벨은 의미 없음
- 실리콘밸리 밖에도 좋은 직장은 있지만, 많은 좋은 직장이 실리콘밸리에 있음
맥주를 찾았다. 계속 가자.
프로그래밍 언어에 대해
- 한때 싫어했던 언어(C#)를 쓰기 시작하니, 여전히 싫지만 유용함을 인정
- 싫어했던 언어(C#)를 떠났다 돌아오니 크게 발전해 있었음
- 함수형 언어의 가장 큰 장점은 함수가 일급 객체라는 것, 그리고 모든 프로그래머가 그걸 안다는 것
- 아무리 뛰어나거나 우월한 언어라도 사람들이 안 쓰면 의미 없음
- 언어를 배우는 것은 어렵지 않음 — 어려운 것은 에코시스템을 배우는 것
동료에 대해
- 페어 프로그래밍은 훌륭하지만, 시간이 많이 들고 — 회사는 보통 그 시간을 쓰고 싶어하지 않음
- 똑똑한 엔지니어와 일하면 더 나은 코더가 됨. 똑똑한 비기술 동료와 일하면 더 나은 엔지니어가 됨
- 9시-5시 이외에 일하지 말 것 — 단, 멋진 프로젝트가 진행 중이고 몰입 상태라면 예외. 그건 최고
- 팀 간 해피아워와 소셜 타임의 99%는 그냥 수다. 하지만 1%는 중요한 프로젝트의 중요한 코드에 대한 이야기이고, 사교 자리에서 일 이야기를 꺼낸 덕에 큰일을 막은 경험 있음. 다른 팀과 어울려야 한다는 뜻이 아니라 그냥 유대감을 원하는 것이고, 부수 효과가 있을 뿐
재택근무에 대해
- 반 원격/반 사무실 환경에서 원격 직원이 이등 시민 취급받는지 확인 필요 — 주요 결정이 "물 마시러 가서" 이루어지면, 회사 문화를 바꾸거나(어려움) 원격 직원을 일급 시민으로 대우하는 다른 회사로 이동
- 재택의 두 번째 최악의 단점은 화이트보드 없음
- 재택의 최악의 단점은 동료에게서 배우기 어려운 것 — 자신감 있게 질문할 수 있고, 원격 직원이 현장 직원과 동등한 문화가 아니라면, 커리어 초반 5년은 사무실 근무가 나았음
기술에 대해
- 기술은 변한다는 것은 모두 알지만, 지난 10년간 극적으로 변했어도 기본 원칙은 크게 변하지 않음 — 특히 해당 분야에 적용되는 기본 원칙
- Hacker News와 r/programming은 전반적인 아이디어와 최신 동향 파악에만 유용, 댓글은 거의 쓸모없음
- 강한 의견을 가진 아마추어가 많고, "존경받는" 저널과 블로그에 실린 글도 마찬가지 — 소문은 파악하되 스스로 판단해야 함
- 최첨단 스타트업에서 일하지만 ABC 최첨단 기업이 발표한 최신 XYZ 기술은 안 씀 — 그들이 발표하는 것은 엔지니어링의 극히 일부이고, 대부분은 우리와 같은 기술 사용
- 그러나 징후를 읽어야 함 — 모던 기술을 쓰고 싶은데 회사가 여전히 jQuery 위주로 개발 중이라면 재평가할 시기
데이터 엔지니어링에 대해
- 데이터 엔지니어니까 데이터 특화 조언/경험을 추가
- SQL이 왕 — MySQL, Postgres, Oracle, SQL Server, SQLite 모두 여전히 최강. 새 기술을 써도 대부분 전이 가능
- 대부분의 회사는 스트리밍을 하지 않음 — 어렵고 복잡함. 10년 경력에 초당 1만 건 처리를 못해도 일자리는 있음
- Airflow는 별로, 그렇다. 다른 제품도 있지만 Airflow가 가장 널리 사용됨
- 머신러닝 프로젝트는 실패 가능성이 높음 — 복잡하고 구현이 어려움. 안 믿긴다고? ML 모델의 유닛 테스트 작성이 얼마나 쉬운지 생각해 볼 것
- 이 분야는 아직 새로움 — 데이터 엔지니어링에 좋은 책이 없음, 그냥 직접 해봐야 함. 부트캠프로는 안 됨. 10년 후에는 바뀔 가능성
삶에 대해
- 사람은 죽음 — 코드가 레거시가 되길 원한다면 시간을 쏟을 것. 하지만 나처럼 레거시가 가족, 친구, 주변 사람이라면 코드에 너무 집착하지 말 것
- 좋은 사람도, 똑똑한 사람도, 좋은 코더도 나쁜 코드를 작성함 — 코드 품질을 자기 가치의 종속 변수로 만들지 말 것
- 취미로 시작한 기술이 직업이 되면서 취미가 사라짐 — 기술이 더 이상 취미가 아님을 받아들이고 새 취미를 찾거나, 즐기려면 직장을 그만둬야 함
- 프로그래밍과 CS는 약 80년 된 학문 — 다른 공학 분야에 비하면 우리 모두 뭘 하는지 모르는 상태
- 꽤 괜찮은 돈을 벌고 있음 — 감사하고 아끼며 저축할 것
기타
- 여러 팀이 수년간 쓰는 대규모 플랫폼과 라이브러리를 만들었지만, 가장 뿌듯했던 코드는 자신만 쓰는 작은 스크립트
- 커리어에서 가장 자랑스러운 성취는 다른 사람들이 일을 더 잘하도록 도운 것 — 아마 피플 매니저가 될 운명이라 그런 것이고, 다른 사람에게는 도움이 안 될 수도 있음
- 구직 시 LinkedIn을 만들고 업데이트했지만 별로인 답변만 받고 삭제. 지금은 LinkedIn으로 채용 후보를 찾음 — LinkedIn은 노이즈가 많고, 그 노이즈에 기여하는 것이 업무의 일부이기에 가치가 있을 뿐
- 대학 때 자신을 좋아하는 여자를 알게 됨 — 낮은 자존감 때문에 안 믿었지만 데이트 신청을 받음. 정중히 거절했고, 19살에 성숙하게 "아니오"를 말할 수 있었던 것이 인생에서 가장 자랑스러운 순간 중 하나
- r/cscareerquestions는 에고와 잘못된 정보의 늪 — 그 사람들을 흔들어 세상이 진짜 어떤지 설명하고 싶지만 믿지 않을 것
지금 느끼는 감정들
- 술에 취해 있고 평소에 안 마시는 편이라, 하는 말이 전부 민망하거나 끔찍할 것 같음
- 사람들이 저축하고 투자해야 한다고 강하게 느낌 — 6자리 연봉이면 401k를 최대한 채울 것
- 항상 싫어했던 것이 되어 버림 — 기술 업계에서 일하지만 실생활에서는 기술을 피하는 사람. 나이가 들면 그런 건지도
- r/ExperiencedDevs는 꽤 괜찮은 커뮤니티. 모더레이터들에게 감사. 받는 것보다 훨씬 적은 감사를 받고 있음
- 커리어, 연봉, 인생을 Reddit에 빚지고 있음 — 주유소에서 최저임금을 받던 상태에서 Linux, SQL, Python, C# 등을 배워 현재 위치에 도달. Reddit은 욕을 많이 먹지만 커뮤니티들이 빈곤에서 벗어나게 해줌
- 아이는 좋음 — 선택으로 아이가 없음. 아이를 사랑하지만 어떤 아버지가 될지 두렵기 때문. 이 글에서 너무 개인적인 이야기인가?
- 누군가 누구를 존경하냐고 물었을 때 Conan O'Brien이라고 답했더니 비웃음. 하지만 진심이었음 — Tonight Show 마지막 방송에서 "친절하고 열심히 일하라"고 한 그 말이 인생의 어려운 시기에 들렸고, 잃을 것도 없으니 그대로 실천. 10년 넘게 친절했기에 훌륭한 사람들을 만났고, 열심히 일하고 새로운 것을 시도해서 인생이 무한히 나아짐. 심야 토크쇼 덕분에 인생의 충만함을 얻었다는 게 우스울 수 있지만, 내 인생이고 어떤 성공이든 심야 TV의 코미디언 덕분이라고 당당히 말할 것
만취 상태이니 제가 한 말은 무시하세요. 장광설 죄송합니다.
스타트업에서 데이터 팀 만들기 (erikbern.com)
- 연 매출 100억 규모 Mid-Stage 스타트업에 4명 정도 소규모 데이터 팀을 키우기 위해 합류한 사람의 이야기
- 몇 번의 경험에 의한 비유적인 글이며, 편향적*일 수 있으니 고려하고 읽을 것
7월 1일 : 아침
데이터팀 책임자로 출근 첫날
CMO와 인사 ㅤ(CMO는 내가 왔다는 사실에 매우 흥분하고 있음, 자기 친구네 회사가 AI를 이용해서 고객 세그멘테이션을 하고 있는데 멋져 보인다고 얘기함) ㅤ(간단한 얘기 후 마케팅팀의 데이터 프랙티스를 조사) ㅤDATA: "고객 확보 비용 (CAC)은 어떤가요 ?" ㅤCMO: "음.. 실제로 아주 훌륭해요. 우리 데이터 사이언티스트가 수치를 측정해보니 클릭당 비용이 점점 줄고 있어요" ㅤDATA: (모든 데이터 사이언티스트는 데이터 팀에 보고한다고 들었는데, 다른 조직에 데이터 사이언티스트가 있다고?) ㅤCMO: "진짜 문제는 Growth 팀이 우리가 사이트로 가져오는 트래픽을 다 전환시키지 못한다는 거에요" ㅤDATA: "컨버전 퍼널을 볼수 있는 대시보드가 있나요 ?" ㅤCMO: "리드를 전환하는 건 Growth 팀의 일이잖아요."
Product Manager 중의 한명과 대화 ㅤ시작 페이지를 전체 재설계한 PM은 사용자 등록수가 14%나 증가했다고 흥분했음 ㅤDATA: "그 숫자의 차이가 통계적으로 유의미 한가요 ?" ㅤPM: "그건 내 일이 아니고 당신의 팀이 할 일이죠" ㅤPM: "우리가 전에 물었을 때는, 데이터 팀에서 데이터가 없다고 얘기했고, 데이터를 얻는데 몇달이 걸릴 거라고 했어요" ㅤPM: "놀라운 건 이걸 인크리멘털하게 변경하지 않았다는 거에요. 우린 이 변경에 대해서는 A/B테스트를 하지 않기로 했어요. 가끔은 극값(Local Maxima) 를 벗어 나기 위해선 큰 베팅을 해야해요." ㅤPM: "스티브 잡스는 iPhone 런칭할때 A/B 테스트를 하지 않았어요. 우리 팀은 마감 2일전에 이걸 런칭했고, 그게 중요한거죠!" ㅤDATA: (바빠 보이는 척 노트에 끄적인다)
새로운 팀 멤버들과 대화 ㅤ→ 3명 팀이지만 연말까지 10명으로 늘릴수 있는 예산을 받았음 ㅤ→ 내가 와서 팀원들은 흥분한 듯 ㅤ→ 기존에 만든 것들을 보여줌. 꽤 많은 것들이 있고 그 중 일부는 멋짐 ㅤㅤ✓ 사용자 이탈 예측(Churn Prediction)을 위한 신경망 ㅤㅤ✓ 관련 상품 추천 시스템이 구현된 노트북 ㅤ→ 많은 코드가 다양한 시스템에서 데이터를 가져와야 하는 매우 복잡한 전처리 단계로 시작 ㅤㅤ✓ 이 작업중 일부를 수행하려면 올바른 순서로 수동으로 실행해야 하는 여러 스크립트가 있는 것 같음 ㅤ→ 팀원들에게 왜 프로덕션에 도입하지 않았는 지를 묻자 ㅤㅤ✓ 엔지니어들이 이걸 프로덕션 레벨로 하려면 매우 큰 프로젝트라고 얘기함 ㅤㅤ✓ Product Manager 가 백로그에 넣기는 했지만, 다른 일이 계속 발생해서 미뤄지는 중 ㅤㅤ✓ 이를 위한 경영진의 지원이 필요하다고 얘기함
7월 1일 : 오후
- 공급망 책임자(Head of Supply Chain)와의 대화 ( 그는 CMO 만큼은 흥분하진 않는듯 ) ㅤ"솔직히 데이터 팀의 도움이 필요한지 모르겠어요" ㅤ"우린 그런 종류의 문제가 없거든요. 우리에게 필요한 건 비즈니스 분석가에요" ㅤ"저에게는 전체 팀이 있고, 그들은 매우 복잡한 모델에 작업하는데 매일 몇시간씩 쓰고 있어요" ㅤ"그들은 내가 가진 기본적인 질문에 대답할 시간조차 없어요." ㅤ"전 답변을 구하고 싶은 질문들로 가득 찬 스프레드 시트가 있어요"
ㅤ(스프레드 시트를 보니 이런 것들이 있다) ㅤ"고객이 티켓을 발행하고 1시간 내에 해결된 고객과, 1시간 이후에 해결된 고객의 전환율 비교를 주문 금액 $100 달러 간격으로 분류하기"
ㅤ(모델에 대해 물어보니) ㅤ- 수많은 VLOOKUP 들로 구성된 구글시트에 올바른 형식으로 알맞는 탭에 복사 해야하는 것 같음 ㅤ- 데이터는 매일 업데이트 되고, 모델의 출력에 따라 팀의 그날 우선순위가 결정 ㅤ- 공급업체(벤더)들에게 나가는 비용도 스프레드 시트로 계산하고 있음
(집에 가서 위스키 한잔을 가득 따른다.. )
[ 무슨 일이 있었던 걸까 ?]
이건 기본적으로 데이터 성숙 단계에 있는 초기의 많은 회사에서 일어나는 일에 대한 (다소 냉소적인) 묘사임
데이터 부족 및 조각난 데이터 ㅤ→ 제품이 제대로 계측(Instrumented) 되지 않아서 데이터가 처음부터 존재하지 않는 경우가 많음 ㅤ→ 데이터가 여러 시스템에 분산되어 있는 데이터 시스템 단편화 ㅤ→ 데이터 드리븐으로 실행은 되지만 자동화가 거의 또는 전혀 없는 취약한 비즈니스 프로세스
데이터 팀의 업무가 무엇 인지에 대한 불명확한 기대 ㅤ→ R&D를 하고 AI를 배포하기 위해 고용된 데이터 사이언티스트 - 결과적으로 명확한 비즈니스 목표가 없음 ㅤ→ 데이터팀은 ML을 프로덕션화하기 어렵다고 불평하지만, 정작 제품팀은 그 기능에 별로 신경을 쓰지 않음 ㅤ→ "English-to-SQL 번역기"가 필요한 사람들
데이터 드리븐 트레이닝이 되지 않은 제품팀 ㅤ→ 프로덕트 매니저는 데이터를 더 좋은 기능을 구축하기 위한 도구로 생각하지 않음 ㅤ→ 제품팀이 구축하고자 하는 것과 데이터팀이 가진것 사이의 얼라인이 부족
근본적으로 데이터 중심 문화와 상충하는 문화 ㅤ→ 측정 가능한 발전과 학습을 축하하는게 아닌 배포(Shipping)를 축하하는 문화 ㅤ→ 실제로 메트릭을 사용하는 팀들도 일관되지 않고, 측정이 제대로 이루어지지 않으며, 경우에 따라선 다른 팀과 충돌함
데이터 리더십 없음 ㅤ→ 다양한 데이터 인력들이 여러 다른 부서(기능)들에 보고하는 분열된 데이터 조직 ㅤ→ 다른 부서들은 필요한 도움을 받지 못하므로 데이터 팀을 둘러싸고 많은 분석가를 고용 ㅤ→ 툴체인 및 모범사례의 표준화 부족
(와 이건 우울하다. 이 문제를 해결하기 위해선 어떤 일을 해야할까)
7월 8일
다음주 부터 데이터팀의 새로운 방향을 세우기 시작
한명이 인프라에 경험이 있는 것 같으니 그에게 Centralized 데이터 웨어하우스 구축하게 함
당장은 데이터를 한 곳으로 모으기 위한 가장 빠른 경로만 있으면 됨
계획은 기본적으로 매시간 마다 프로덕션 DB를 데이터 웨어하우스에 덤프 하는 것
프론트엔드에서 광고 추적 트래킹에 사용하는 프레임워크에서도 방대한 이벤트 로그를 보낼수 있지만 그건 기술부채로 담아두기
채용팀과 함께 Generalist Data Role 정의 ㅤ→ 핵심 소프트웨어 기술을 강조하지만, Generalist(모든 것을 다 하는) 적인 태도와 비즈니스 요구사항에 대해 깊이 공감할 수 있는 사람 ㅤ→ 당장은 인공지능 및 머신러닝에 대한 모든 언급은 제거함
데이터팀에 보고하지 않는 다른 데이터 인력들과 시간을 보냄 ㅤ→ 마케팅 팀에 있다는 데이터 과학자는 젊은 사람이었음. "저는 항상 데이터 사이언티스트가 되고 싶었어요. 당신에게 많이 배우고 싶어요"
코딩 부트캠프를 운영하는 친구에게 좋은 "SQL 교육 강의"가 있는지 물어봤고, 있다고 해서 이달 말에 도입하기로
제품팀을 위해서 A/B 테스트 가 무엇이고 어떻게 동작하는지를 설명하는 발표자료 작성 ㅤ→ 예상치 못한 결과가 나온 테스트의 많은 예를 보여주고, ㅤ→ 어떤 것이 이겼는지 추측해 볼 수 있게 인터랙티브 하게 작성
CEO의 비서를 만나서 "매주 자동 발송되는 이메일을 통해서 보고 되었으면 하는 지표들"을 알아내기
Supply Chain 팀의 비즈니스 분석가들과 얘기해보니, 합리적인 사람들인데 이전에 데이터팀과 얘기하면서 상처를 입었음
그들중 한명은 과거에 SQL을 사용한 경험이 있었음. 그가 전환율에 대해 질문하는 걸 보고 데이터 웨어하우스 접근권한을 줌
데이터를 필요로 하는 조직 전체의 사람들과 주간 1:1 미팅을 셋업 ㅤ→ 요점은 데이터 격차(Gap)와 기회들을 찾아서 데이터 사이언티스트에게 보내는 것 ㅤ→ 데이터 사이언티스트 들은 연구 우선순위가 밀리므로 실망할 수 있음 ㅤ→ "가능한 한 빨리 비즈니스 가치를 제공하는데 집중" 이라고 말하면서도 "곧 머신러닝관련 작업으로 돌아갈 수도 있어요. 일단 보시죠" 라고 얘기함
9월 1일 : 아침
3개월이 지나고, 이제 조금씩 일이 되어가는 것 같은 느낌
다양한 이해관계자들과 매주 1:1로 미팅하면서 데이터가 변화를 일으킬수 있는 사각지대와 기회를 계속 찾음
찾은 것들을 핵심 플랫폼 작업에 강제하도록 이용
"파생된" 데이터 세트를 만들려면 많은 파이프라인을 구축해야함. 초기 비용이 많이 들지만 올바른 데이터셋이 만들어지면 후속 분석이 훨씬 쉬움
다른 부서들에 데이터 웨어하우스 액세스를 개방 시작
직접 SQL을 사용해서 기본 분석을 하기 시작 ㅤ→ 훌륭했던 일 : 쥬니어 프로덕트 매니저가 iOS Safari 의 전환율이 엄청 나쁘다는 것을 발견. 로컬스토리지 관련 프론트엔드 버그였고 한줄로 수정되었음
공급망 책임자가 화난 이메일을 보냄 ㅤ→ 데이터베이스가 변경되어서 500줄짜리 쿼리가 실패한다는 것.. ㅤ→ 투덜대는 데이터 사이언티스트에게 수정을 맡기고 다른 당근을 매달아줌 "이번 달 말에 멋진 머신러닝 문제를 찾아줄께요"
9월 1일 : 오후
- 아직 체크아웃팀의 제품 관리자는 메트릭 분석은 하지 않고 있음
- 마케팅팀의 데이터 과학자가 매니저와 얘기해서 나에게 직접 보고하기로 함
[ 무슨 일이 일어나고 있을까 ? ]
- 가장 시급한 것들의 기본 토대를 마련 하는 중 ㅤ→ 중요한 데이터를 한 곳에서 쿼리가능하게 함 ㅤ→ SQL 접근을 개방하고 다른팀에서 사용하도록 해서 많은 "SQL 번역" 일들을 없앰
- 반대로 다른 팀은 이런 자유 때문에 더 멀리가려고 할 수도 있음. 데이터 접근에 권한을 설정해서 방지할수는 있지만 단점이 더 많음
- 체크아웃팀이 데이터 분석을 못한것은 누구에게 물어봐야 할 지를 몰랐기 때문
- 이건 주로 조직의 문제임 ㅤ→ 팀들은 데이터 팀과 협력하는 방법을 모름 ㅤ→ 깨닫지 못하지만 데이터팀이 병목일 수도 있음
- 가장 합리적인 것은 "보고는 중앙 집중화 하고, 작업 관리는 분산화 하는 것" ㅤ→ 데이터와 결정이 더 긴밀한 피드백 루프를 생성하기 때문 ㅤ→ 데이터 팀 멤버들이 각각의 팀에서 협업하고 보고만 나(데이터팀 리드)에게 할 수 있도록
9월 2일
- 데이터 팀이 6명으로 늘어남 ㅤ→ 1명 데이터 웨어하우스 인프라 ㅤ→ 5명은 각각 팀에 할당 : 온보딩, 공급망, 체크아웃, 마케팅, CEO 지원및 투자자/이사회용 발표자료 작성
- 전사에 변경을 설명하고, 데이터 요구 사항을 위해서는 누구와 일해야 하는 지를 명확히 함
- 앞으로 데이터 인력은 뽑더라도 다른 팀에 할당할 계획
1월 3일
- 데이터 사이언티스트 한명이 떠나기로 함. 그가 즐거워할 일도 많지 않기 때문에 잡지 않기로 함
- 팀에는 새로운 사람들이 많음. 약간의 소프트웨어 엔지니어링 지식과 SQL, 그리고 데이터에서 흥미로운 것들을 찾고자 하는 사람들 ㅤ→ 데이터에서 "특종"을 찾는 사람들이니 "데이터 저널리스트" 라고 생각
- 온보딩 팀과 작업하는 멤버의 경우 ㅤ→ 온보딩 흐름에서 고객 주소가 필요하지 않아도 주소를 묻는 것을 발견 ㅤ→ 이걸 제거하면 A/B 테스트에서 전환율이 21% 증가 ㅤ→ 데이터를 쿼리하기 쉽게 하기 위해 ETL 작업이 필요해서 쉽지는 않았지만, Python 이 살짝 도와서 가능해졌음
- CEO 와 분기 보고 ㅤ→ 성장 이니셔티브 에서 PM이 새로 런칭한 랜딩페이지 재 설계를 소개 ㅤ→ PM은 20명의 엔지니어 들이 마감을 맞추기 위해서 초과 근무를 하고 있다고 강조 ㅤ→ CMO도 이 재설계의 일환으로 Direct Mail 에 큰 기대를 걸었기 때문에 깊게 관여하고 있음 ㅤ→ CEO의 질문 "현재 지표는 어떻습니까? 고객 확보 비용이 줄어들었습니까 ?" ㅤㅤ(당신은 CEO가 이런 질문을 하길 기대했는데 딱 나와서 미소 지음) ㅤ→ PM은 실제로 A/B 테스트를 진행했다고 부록에 있는 숫자들을 보여줌 ㅤ→ 일부 지표는 상승하고, 일부는 하락해서 유의미한 결과를 보여주는 결과가 없음, 고객 확보 비용 수치는 안 좋아 보임 ㅤ→ CMO는 아직 숫자는 만들어 가는 중이며, 이런 캠페인은 몇 달이 걸릴 수 있다고 강조
[ 무슨 일이 일어나고 있을까 ? ]
좋은 소식은 제품 팀이 A/B 테스트를 하기 시작했다는 것
나쁜 소식은 결과를 무시하고 프로젝트가 대부분 마일스톤과 인위적인 데드라인에 맞추도록 진행된다 는 것
최고의 소식은 CEO가 각 팀들이 데이터가 진실(truth)로 사용되도록 푸시하고 있다는 것
조직이 더 데이터 드리븐이 되도록 압력을 받게 되면, 데이터 팀이 다른 팀과 협력하는 방식을 가속화 해야 함
특히 최고 경영진들은 더 지표에 집중하게 되고, 데이터 팀이 이런 지표들을 작업하도록 하는게 당신의 일
가장 간단한 방법 하나는 각 팀들이 중요시 하는 지표에 대한 대시보드가 있는지 확인 하는 것
4월 1일
데이터 팀에서 수행했던 예전 머신 러닝 작업들은 아직 그대로 있음
인벤토리 제품 팀에서 일하는 데이터 사이언티스트가 예전에 만든 추천 시스템 작업들에 관심을 가지고 있음
새로 뽑은 멤버중 한명으로 Generalist 인 사람이어서, 추천 시스템 노트북을 작은 Flask 앱으로 만들어서 내부에 배포했음
인벤팀의 제품 관리자가 보고 좋아함 "이거 어떻게 배포하죠?"
인벤팀의 주요 지표중 하나는 "평균 주문 금액" 이고 이 추천이 그걸 크게 개선 할수 있을 것으로 봄
짧은 추정으로도 크게 배포하는 건 어려울 것 같지만, "고객중 1%에만 배포해보면 어떨까요?" 라는 아이디어를 냄
"멍청하지만 Cron Job으로 추천 제품들을 미리 생성해두면 되고, 며칠 안에 만들수 있을 것 같아요"
공급망 팀과 일하면서 더 많은 거대한 SQL 쿼리들을 발견
계속 깨지고 있지만, 데이터 팀이 이걸 적절한 파이프라인으로 변환 작업중
공급망 팀 헤드가 더 많은 데이터 사이언티스트를 고용해 달라고 요청
[ OK, 무슨 일이 일어나고 있는건가요 ? ]
먼저, 멋진 기계 학습 작업에 대한 희망이 생겼음
제품팀이 드디어 추천 시스템을 작은 테스트로 런칭 하는 것에 흥분해 있음
예전에는 제품 엔지니어링팀이 작업을 예측하기 힘들고, 직접 기여하기 원치 않았고, 데이터팀이 프로덕션화할 스킬이 없었으므로 진행할 수가 없었던 일
이 문제를 해결 한 것은 데이터팀이 실제로 데모를 구축했기에 가능한 것. 이렇게 하면 프로덕션에 가까워 질 뿐 아니라 가능성을 명확하게 보여줌
또 하나는 공급망 팀에 일어나는 일 ㅤ→ 자체 "비즈니스 분석가" 로 시작했지만, 데이터를 얻기 위해서는 데이타 팀이 쿼리를 실행해줘야 했음 ㅤ→ 분석가들이 데이터팀의 도움을 받아서 직접 쿼리를 실행하기 시작 ㅤ→ 먼저는 데이터팀과 마찰이 생겼던 "그림자 기술 부채"(괴물 같은 크기의 SQL 쿼리)를 없애기 시작 ㅤ→ 데이터 팀이 공급망 팀에 붙어서 돕기 시작 ㅤ→ 데이터 팀 멤버가 임베딩 되면서 비즈니스 분석가의 필요성은 줄어들고 데이터 과학자들이 증가함
처음에 프로덕션 DB를 데이터 웨어하우스에 직접 덤핑하기 시작할때 "기술 부채"을 떠맡았음을 기억할 것
처음에는 많은 것들이 깨지지만 안정적으로 쿼리하도록 하는 레이어를 추가 해야함. 굉장히 많은 일이 될수 있음
7월 1일
- 3분기 기획회의 ㅤ→ 에전에는 다음 분기에 회사가 뭐에 베팅할 지를 논쟁했음 ㅤ→ 이번에는 당신이 회사의 최상위 지표들을 발표하고, 각 팀들이 서브 지표들을 통해서 최상위 지표들을 세분화 해서 발표
- 제품관리 팀 작업이 성과를 내었음 ㅤ→ PM이 테스트를 실행하면서 배운 내용이나 데이터에서 발견한 내용에 대해 이야기 하면서 프로젝트에 대한 투자를 정당화
- 큰 성과는 체크아웃 팀과 일하는 데이터 과학자가 사용자가 확인페이지에서 뒤로 가기 버튼을 눌렀을 때 장바구니 개체가 이상하게 되는 것을 발견했다는 것 ㅤ→ 이 문제를 해결하자 전환율이 크게 상승 되었음
- 또 다른 인사이트는 서로 다른 광고 캠페인을 통해서 온 트래픽들이 매우 다른 전환 프로필을 가진 다는 것 ㅤ→ 일부 캠페인은 클릭 가격이 쌌지만 전환율이 끔찍했고, 다른 캠페인은 비용이 많이 들었지만 전환율이 매우 높았음
- UTM 변수를 추적하고 계정 생성에 연결해서, 광고 클릭에서 구매까지의 전환율 측정이 가능해졌음 ㅤ→ 모든 데이터를 같은 데이터 웨어하우스로 가져와서 쉽게 쿼리할 수 있도록 정규화 하기 전에는 불가능 했음 ㅤ→ 마케팅과 협력을 통해 주요 KPI는 클릭당 비용이 아닌 End-to-End 고객 확보 비용임
- 또 다른 재미난 소식은 1% 추천 시스템 테스트가 이례적으로 성공했다는 것 ㅤ→ 사용자의 100%까지 확장하는 것은 매우 큰 프로젝트이지만 CEO가 프로젝트를 승인했음
- 모든 결과물이 긍정적인 것은 아니고, 많은 테스트는 실패했음. ㅤ→ 슬라이드중 하나는 배송비가 별도로 청구되지 않고 가격에 포함된 테스트에 대한 설명이었음 ㅤ→ CEO가 이렇게 말함 "여기서 무엇을 배웠습니까?" ㅤ→ 이건 다시 일련의 후속 실험을 계획하는 대화로 이어짐
(집에 가서 샴페인을 터뜨림)
[ 무슨 일이 일어난거지 ?]
- 당신이 해냈습니다.
- 조직을 진정한 데이터 네이티브로 변화 시켰습니다.
- 데이터 팀은 다양한 이해 관계자와 교차 기능적으로 작업합니다.
- 데이터와 인사이트가 계획에 이용되고, 데이터는 목표가 불분명한 연구가 아닌 비즈니스 가치를 창출하는데 사용됩니다.
- 회사는 빠른 데이터 기반 피드백 주기를 이용해서 대규모 "워터폴" 스타일 계획 대신 반복적인 방식으로 작업 합니다.
- 지표들은 비즈니스 가치를 만들고 그에 대한 책임감을 가질 수 있는 방식으로 정의됩니다.
- 데이터 문화는 위(CEO가 추진하고)와 아래(직원들)로부터 양쪽이 함께 주도 합니다.
- 적어도 무언가를 배웠다면 실패해도 괜찮습니다.
(축하합니다. 당신은 샴페인을 들 자격이 있어요)