끄적끄적/Book Review

[구글엔지니어] Ch01 ~ Ch02 요약 및 토론

DevOwen 2022. 10. 15. 09:00

Part I. 전제

Chapter 1. 소프트웨어 엔지니어링이란?

해당 챕터에서는 소프트웨어 엔지니어링과 프로그래밍의 차이에 대하여 다룬다.

  • 소프트웨어 엔지니어는 시간의 흐름과 언젠가 변경될 가능성에 더 신경써야 한다.
    • 소프트웨어 엔지니어링은 흐르는 시간 위에서 순간순간의 프로그래밍을 모두 합산한 것이다. (Software Engineering is programming integrated over time)
    • 시간이 프로그램에 미칠 영향 알 수 있는 방법 → ‘이 코드의 예상 수명은?’
  • 소프트웨어 기대 생애 동안 요구되는 모든 가치 있는 변경에 대응할 수 있다면 그 프로젝트는 지속 가능하다. 라고 할 수 있다.
  • 소프트웨어 엔지니어링이란 여러 버전의 프로그램을 여러 사람이 참여해 개발하는 것이다.
  • 소프트웨어 프로젝트의 팀 조직, 프로젝트 구성, 정책과 관례는 모두 소프트웨어 엔지니어링의 복잡성을 좌우한다.
    • 조직이 성장하고 프로젝트가 확장될 수록 소프트웨어 생산 효율도 높아지는가?
    • 개발 워크플로의 효율도 우리의 성장에 발맞춰 개선되는가?
    • 우리가 따른 버전 관리 정책과 테스트 전략이 조직 규모가 확장되면 비례하여 비용을 증가시키는가

1.1 시간과 변경

동작한다유지보수 가능하다를 구분 짓는 가장 중요한 요인

→ 하이럼의 법칙은 최선의 의도, 최고의 엔지니어, 꼼꼼한 코드 리뷰가 뒷받침 되더라도 공표한 계약(명세)이나 모범 사례를 완벽하게 구현해 냈다고 단정할 수 없는 현실을 표현

  • API 소유자는 인터페이스를 명확하게 설명해놓으면 어느 정도의 유연성과 자유를 얻을 수 있다.
  • 하지만 현실에서는 API 사용자가 (명세에는 없는) 기능을 찾아 활용하기도 하며, 그 기능이 유용해 널리 쓰이면 추후 API를 변경하기 어렵게 된다.

해시 반복 순서 예시

>>> for i in {"apple", "banana", "carrot", "durian", "eggplant"}: print(i)
...
durian
carrot
apple
eggplant
banana

해시 테이블의 원소 순서가 겉으로 밝히지 않은 나름의 알고리즘에 의해 정해짐

→ 그 알고리즘이 언제까지 유지되는지 아는 사람은 별로 없음.

→ “제 해시 컨테이너가 정해진 순서대로 결과를 낸다고 가정해도 될까요?”

→ “아니오”

→ “하드웨어, 언어 런타임, 데이터 구조를 변경할 일 없이 단명할 코드라면 그렇게 가정해도 괜찮아요. 하지만 코드가 얼마나 생존할지 모르거나 당신 코드가 의존하는 대상이 아무것도 바뀌지 않으리라 확신할 수 없다면 그런 가정은 옳지 않아요”

동작한다(it works)옳다(it is correct) 의 차이

  • 이용하는 API의 명세에 명시되지 않은, 즉 언제든 변할 수 있는 기능을 사용하는 코드는 임시 방편적인(hacky) 또는 기발한(clever) 코드
  • 반대로 모범 사례를 따르고 미래에 대비한 코드는 클린 하고 유지보수 가능한 코드
  • “기발한”이 칭찬으로 느껴지면 프로그래밍이라 하고, 질책으로 느껴진다면 소프트웨어 엔지니어링이라고 한다.

1.2 규모 확장과 효율성

  • 소프트웨어 조직에서 가장 중요한 자산인 코드베이스 자체도 확장 가능해야 한다.
  • 코드가 많아지고 변경 이력이 쌓이는 등의 이유로 빌드 시스템이나 버전 관리 시스템이 점점 느려진다면 어느 순간 더는 정상 운영할 수 없는 시점이 온다.
  • ‘전체 빌드에 걸리는 시간’, ‘리포지토리에서 전체를 새로 내려받는 시간', ‘프로그래밍 언어 버전을 업그레이드 하는 비용’ 같은 지표는 적극적으로 관리하지 않으면 천천히 악화된다.
  • 끓는 물 속 개구리가 되지 않도록 주의하자
  • 엔지니어 한 명에게 할당한 작업이 있고, 조직이 10배 혹은 100배로 커졌다고 상상
    • 조직이 10배로 커지면 이 작업도 10배로 많아지는가?
    • 엔지니어가 해야 할 일의 양이 조직이 커질수록 늘어나는가?
    • 코드베이스가 커질수록 작업량도 늘어나는가?
    • 이 중 하나에 해당할 경우 작업을 자동화하거나 최적화 할 수단이 있는가?
    • → 마지막 질문의 답이 아니오라면 확장성에 문제가 있는 것.

→ 공통 CI 시스템에 추가해 두지 않은 테스트는 인프라팀이 책임지지 않는다.

여담

Cause if you liked it, then you shoulda put a ring on it
(네가 나를 좋았했다면 프러포즈를 해줬어야지)

  • 이걸 테스트와 연결시켜 표현한 것 같습니다.
  • 왜 이름이 비욘세 규칙인지 궁금해서 찾아보았더니, 비욘세의 노래 중 Single Ladies에 이런 가사가 있다고 하네요
  • 100명의 자바 엔지니어가 있는 조직에서 질문에 기꺼이 답해줄 전문가가 한 명만 있어도 곧 더 나은 자바 코드를 작성하는 100명의 엔지니어가 생겨난다.

1.3 트레이드 오프와 비용

  • 원점 회귀(왼쪽으로 옮기기)
    • 개발 과정에서 문제를 일찍 발견할수록 비용이 적게 든다.
    • 타임라인에서 문제 발견 시점을 왼쪽으로 이동시킬수록 수정 비용이 줄어든다.
      • 개념잡기 → 설계 → 구현 → 리뷰 → 테스트 → 커밋 → 카나리 → 배포
       

  • 비용이란? 다음의 요소들을 모두 포함
    • 경제적 비용 (돈)
    • 리소스 비용 (하드웨어)
    • 인적 비용 (엔지니어링)
    • 거래 비용 (실행에 옮기는 비용)
    • 기회 비용 (실행에 옮기지 않는 비용)
    • 사회적 비용 (선택이 사회 전체에 미치는 영향에 대한 비용)
    • 현상 유지 편향(status quo bias)과 손실 회피(loss aversion) 같은 치우침(bias)
  • 구글은 사무용품과 일상적인 개발 시 드는 경비부터 글로벌 규모의 서비스를 준비하고 운영하는 방법에 이르기까지, 우리가 하는 모든 일과 관련한 비용/이윤 트레이드오프에 동일한 수준의 관심을 두고 명확히 계량하려 한다.
  • 좋은 엔지니어링 결정이란 가용한 모든 근거 자료에 적절한 가중치를 부여하고 이러한 지식을 바탕으로 균형점을 잡는 일.
    • 반드시 해야 하는 일 (법적 요구사항, 고객 요구사항)
    • 근거에 기반하여 내릴 수 있는 최선의 선택
  • 사례 : 분산 빌드 (p61)
  • 정량화 된 상황과 정량화 되지 않은 상황.
  • 제번스의 역설 : 효율이 늘어나면 자원 소비가 늘어난다. (p63)
  • 비평하고 비평받는 법 배우기

Thoughts

  • A. 우리는 코드를 짤 때 비용을 고민하면서 작성하고 있는가?
  • A. 우리 코드가 오랫동안 지속가능하려면 어떠한 고민을 해야 할까?
  • S. 코드를 최소화 하려는 노력
    • YAGNI
    • 코드를 반이나 지웠는데, 문제없이 작동한다?
    • 정리를 그 때 그 때 해줬으면 참 좋았을 텐데
  • Q. 내 코드는 내가 퇴사하는 날까지 돌아가야 한다.
  • H. 히스토리를 어떻게 관리하는게 맞는가?
  • A. 프론트엔드 코드는 오래가지 못한다?
    • 프레임워크, 구조는 오래 가지만 컴포넌트는 오래 가지 못한다.
    • backend → horizontal, frontend → vertical
    • business logic / view layer 분리
    • 리팩토링 할 이유가 있는가?
    • 플랫폼 스쿼드의 존재 이유??
    • 스쿼드에서 니즈가 있어서 개선을 하려고 하는데, 이렇게 하는게 맞는가?
  • S. 구조가 구린데, 비즈니스가 동작한다? → 레거시다.
  • A. 데이터 기반의 의사결정을 해야 하는데.. 할 수 없는 것들도 있다. 어떻게 해야 하나?
  • H. 내가 하는 액션이 저 지표에 어떻게 기여할 수 있지?
    • 어떻게 회사에 align 할 수 있지?
  • S. 설계의 개선은 정량화를 할 수 있는 방법이 있다.
    • 다만 이걸 깊게 연구하고 그런 것이 비즈니스에서는 중요하지 않다.
  • G. HR 등 다른 직무에서도 성과를 정량적으로 측정하는 것에 관심이 많다.
    • 측정할 수 없으면 개선할 수 없다. - 피터 드러커
  • H. 비평하고 비평받는 법 배우기
    • 이 둘을 나누는 것이 정말 애매하다.
    • 협력적인가? 돕기 위해서 하는 건가?
  • S. 엔지니어 : 엔진을 다루는 사람. 기계를 다룰 줄 아는 사람.
    • 코드만 다룰 줄 알면 할 수 있는 일이 많지가 않다.
    • 엔지니어의 평가 요소 Hard Skill ← 주니어 — 시니어→ Soft Skill
    • 엔지니어 : 제한된 자원을 가지고 문제를 해결하는 사람.
      • 우리는 마에스트로를 지향하는 것이 아님.
    • 하이럼의 법칙 → 이 피드백 주기는 스타트업의 경우 시리즈 단계에 따라 진행
      • 라운드 단계마다 해야 할 일들이 정해져 있다.

Action Items

  1. 코드를 최대한 쉽게 짜자. 어느 누가 보더라도 이해할 수 있도록.

 

Part II. 문화

Chapter 2. 팀 워크 이끌어내기

  • 인간은 간헐적 버그들의 집합에 가깝다.

2.1 내 코드를 숨기고 싶어요

사람들은 자신이 진행 중인 작업물을 다른 사람이 보고 판단하는 걸 두려워 한다.

2.2 천재 신화

  • 리누스 : 유닉스와 유사한 커널의 시제품을 만들어 메일링 리스트로 뿌린 것
    • 현재의 리눅스는 초기 커널보다 수백 배는 크고 수천 명의 인재들이 함께 개발했다.
    • 리누스의 진짜 업적은 이 사람들을 협업하도록 이끈 것
    • 리눅스는 리누스만의 아이디어가 아니라 커뮤니티가 함께 노력해 이룬 결실
  • 귀도 반 로섬 : 파이선의 첫 번째 버전을 작성
    • 그 후 버전들은 수천 명의 사람이 아이디어를 모으고 기능을 개발하고 버그를 수정하며 만듦
  • 스티브 잡스(매킨토시 제작팀), 빌 게이츠(마이크로소프트) 비슷함. 커뮤니티를 이끌어 집단적 성과물의 상징

2.3 숨기는 건 해롭다

  • 혼자 일하려 한다면 실패할 위험성을 불필요하게 키우고 자신의 성장 잠재력을 속이는 것이다.
  • 조기 공유?
    • 이미 구현된 선례가 있는 것은 아닌지 파악할 수 있다.
    • 초기 설계에 숨겨져 있는 근본적인 실수를 방지할 수 있다.
    • 혼자하는 것보다 아무튼 더 빠르게 할 수 있다.
    • 프로젝트의 버스 지수(Bus factor)를 높일 수 있다.

2.4 모든 건 팀에 달렸다

  • 위대한 팀은 슈퍼스타를 잘 활용하지만 전체가 항상 개인의 합보다 크다.
  • 사회적 상호작용의 세 기둥
    • 겸손(Humility)
      • 당신은 모든 것을 알지도 완벽하지도 않습니다. 겸손한 사람은 배움에 열려 있습니다.
    • 존중
      • 함께 일하는 동료를 진심으로 생각합니다. 친절하게 대하고 그들의 능력과 성취에 감사해합니다.
    • 신뢰
      • 동료들이 유능하고 올바른 일을 하리라 믿습니다. 필요하면 그들에게 스스로 방향을 정하게 해도 좋습니다.
  • 우리 자존감을 우리가 작성한 코드와 동일시해서는 안 됩니다. 나는 내 코드가 아님을 명심하세요.
  • 자신과 만든 것을 구분짓고 자신을 믿고 동료를 믿으세요.
  • 포스트모템(postmortem)
    • 실패한 근본 원인을 분석하여 문서를 남기는 것이 실수로부터 배우는 핵심
    • 포스트모템 문서가 쓸모없는 사죄, 변명, 지적으로 채워지지 않도록 주의
    • 제대로 된 포스트모템에는 무엇을 배웠는지앞으로 무엇을 바꿀지가 담겨야 함
    • 포스트모템에 담겨야 하는 것
      • 사건의 개요
      • 사건을 인지하고 해결에 이르기까지의 타임라인
      • 사건의 근본 원인
      • 영향과 피해 평가
      • 문제를 즉시 해결하기 위한 조치 항목(소유자 명시)
      • 재발 방지를 위한 조치 항목
      • 해당 경험에서 얻은 교훈
  • 구글다움(Googleyness)
    • 모호함을 뚫고 번창한다.
      • 끊임없이 변화하는 환경 속에서도 상충하는 메시지와 방향에 잘 대처하고, 합의를 이끌어내고, 문제에 대한 진전을 이룰 수 있다.
    • 피드백을 소중히 한다.
      • 피드백을 주고 받을 때 품위와 겸손을 유지하고 개인과 팀의 발전에 피드백이 주는 가치를 이해한다.
    • 저항(항상성)을 극복한다.
      • 다른 이들이 저항하거나 관성 때문에 움직이지 않으려 하더라도 야심 찬 목표를 세우고 밀고 나아간다.
    • 사용자를 우선한다.
      • 구글 제품의 사용자 입장에서 생각하고 존중하며 그들에게 가장 도움이 되는 행동을 추구한다.
    • 팀에 관심을 기울인다.
      • 동료들의 입장에서 생각하고 존중하며 팀의 결집을 위해 누가 시키지 않더라도 적극적으로 돕는다.
    • 옳은 일을 한다.
      • 모든 일에 강한 윤리 의식을 갖고 임한다. 팀과 제품의 진정성을 지키기 위해서라면 어렵거나 불편한 결정을 내릴 수 있어야 한다.

Thoughts

  • H. 히스토리가 사람에게 디펜던시를 가지는 순간 문제가 생긴다.
  • Q. 노션은 검색이 너무 불편하다.
  • S. 주석이 도움이 될 때도 있지만, 주석과 완전히 다르게 작성이 된 코드도 있다.
    • 주석이랑 문서는 엔지니어링 레벨에서는 커플링(coupling)이다.
  • S. 한 사람이 다 만들고, 나머지가 다 따라가는 건 옳지 않다.
    • 같이 만들어나가면서 개선하는 게 중요. 물론 쉽지는 않다.
  • A. 회고에서 실패에 대한 액션 아이템을 제대로 정하고 제대로 지키고 있는가?
    • 데이터 기반의 회고를 하고 있는가?
    • 사람이 많아질 수록 회고에 대한 동작률이 급격하게 떨어진다.
    • 결국 인사. 나와 비슷한 생각을 하는 사람을 채용해야 한다. 그렇지 않으면 뒤가 다 무너진다.
    • 비평에 열려 있고 좋은 의사결정을 할 수 있는 사람들을 인사 단계에서 잘 찾아야 한다.
  • Q. 인간은 실패에서 배운다. 내가 한 결정에 대해 후회하지 않는다.
    • 회고가 없다면 길게 갈 수 없다.
  • A. 회고에서 잘 한 것보다, 아쉬운 것들을 더 많이 쓴다.
    • 비평인지 비난인지 판단하는 것은 듣는 사람의 몫이다.
    • 이게 없는게 좋은 회고의 방향.
  • Q. 대안이 없으면 반대하지 않는다.
    • 1:1이 참 좋다.
  • G. 퍼실리테이션 기법 : 어떤 말을 듣고 0.1초 안에 떠오르는 감정을 표현해 보시오.
    • 대안이 없으면 반대하지 않는다. → 회사 입장에서는 OK지만, 개개인의 입장에서는 다를 수 있다.
  • S. 내가 뭔가 문제를 발견했을 때 리포트 하는 것은 책임이다.
    • 나쁜 예 : 세월호, F1, 새만금

Action Items

  1. 가능하면 하나의 프로젝트를 두 사람 이상이 작업하게 하자. (bus factor를 높이자)
  2. API와 문서간의 커플링을 줄이자 → e.g. GraphQL, code as document 를 많이 사용하자.
  3. good case : haylee의 프론트엔드 설계 개선 👍 → 이러한 case가 많아지게 하자.
  4. 회고 잘하자!
  5. 비평과 비난 차이는 동료간의 믿음, 유대감이 영향을 많이 끼치므로 이를 높일 수 있는 노력을 하자. (방법은 사람마다 case by case)