<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hyeonz.log</title>
        <link>https://velog.io/</link>
        <description>software engineer</description>
        <lastBuildDate>Thu, 13 Feb 2025 06:25:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hyeonz.log</title>
            <url>https://velog.velcdn.com/images/hyeonz_kang/profile/62b2e8b6-c998-47ae-93fa-bb219750e84e/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hyeonz.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyeonz_kang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[GO] Optional Pattern 대신 Generic 깔끔하게 쓰기]]></title>
            <link>https://velog.io/@hyeonz_kang/GO-Optional-Pattern-%EB%8C%80%EC%8B%A0-Generic-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%93%B0%EA%B8%B0</link>
            <guid>https://velog.io/@hyeonz_kang/GO-Optional-Pattern-%EB%8C%80%EC%8B%A0-Generic-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%93%B0%EA%B8%B0</guid>
            <pubDate>Thu, 13 Feb 2025 06:25:31 GMT</pubDate>
            <description><![CDATA[<p>Optional Pattern 을 사용하던 것을 어떻게 Generic으로 바꾸어 표현할 수 있는지 알아보자</p>
<h1 id="optional-pattern">Optional Pattern</h1>
<p>Optional Pattern은 함수에 선택적 인자(optional arguments)를 전달하는 방법을 나타내는 디자인 패턴이다. Go는 기본적으로 선택적 인자를 직접적으로 지원하지 않기 때문에, Option 함수 타입을 정의하고 이를 인자로 받는 방식으로 선택적 인자 패턴을 구현한다. 이 패턴으로 구조체의 속성이나 함수의 동작을 유연하게 설정할 수 있다.</p>
<p>예를 들어 나는 repository 에서 GetAll 함수 작성 시 optional pattern을 사용하곤 했다.</p>
<pre><code class="language-go">type FaqRepository interface {
    GetAll(ctx context.Context, options ...FaqQueryOption) (int64, []domain.Faq, error)
    GetById(ctx context.Context, id int64) (domain.Faq, error)
}

type FaqQueryOption = func(*FaqQueryOptionFields)

func FaqQueryOptionFunc() FaqQueryOptionFields {
    return FaqQueryOptionFields{}
}

type FaqQueryOptionFields struct {
    title        *string
    categoryType *string
}

func (qo FaqQueryOptionFields) WithTitle(title *string) FaqQueryOption {
    return func(q *FaqQueryOptionFields) {
        q.title = title
    }
}

func (qo FaqQueryOptionFields) WithCategoryType(categoryType *string) FaqQueryOption {
    return func(q *FaqQueryOptionFields) {
        q.categoryType = categoryType
    }
}

func (qo FaqQueryOptionFields) Title() *string {
    return qo.title
}

func (qo FaqQueryOptionFields) CategoryType() *string {
    return qo.categoryType
}</code></pre>
<p>호출부 예시</p>
<pre><code class="language-go">count, items, err := f.faqRepository.GetAll(ctx,
        cdomain.FaqQueryOptionFunc().WithTitle(request.Title),
        cdomain.FaqQueryOptionFunc().WithCategoryType(request.CategoryType),
    )
if err != nil {
    // 예외 처리
}</code></pre>
<p>유연성, 코드 유지보수 용이, 가변적인 인자처리 등에서 장점을 갖고 있다. 남발할 경우 함수가 여러 번 호출되고, 함수 내에서 값이 수정되기 때문에 약간의 런타임 성능 비용이 발생할 수 있음에 유의해야한다.</p>
<h1 id="generic">Generic</h1>
<p>Go의 제네릭(Generic) 기능은 타입을 매개변수로 사용할 수 있도록 해주는 기능으로, Go 1.18에서 처음 도입되었다. 특징은 다음과 같다.</p>
<ol>
<li><strong>컴파일 타임 타입 체크</strong><ul>
<li>제네릭은 <strong>컴파일 타임에 타입을 체크</strong>하므로, 실행 중에 타입 관련 오류가 발생할 가능성이 줄어듦.</li>
</ul>
</li>
<li><strong>런타임 성능 오버헤드 없음</strong><ul>
<li>제네릭은 <strong>컴파일 시점에 타입별로 구체화(monomorphization)</strong> 되므로, 실행 중 성능 저하 없이 최적화.</li>
</ul>
</li>
<li><strong>메모리 사용 증가 가능성</strong><ul>
<li>여러 타입별로 별도의 코드가 생성되므로, 코드 크기가 증가할 수 있다.</li>
</ul>
</li>
<li><strong>코드 재사용성</strong> 극대화    </li>
</ol>
<p>위에서 언급한 optional pattern 의 예제코드를 generic 으로 바꾸면 다음과 같아진다.</p>
<pre><code class="language-go">type QueryOption[T any] func(*T)

type FaqQueryOptionFields struct {
    title        *string
    categoryType *string
}

func NewFaqQueryOptionFields() FaqQueryOptionFields {
    return FaqQueryOptionFields{}
}

func (qo FaqQueryOptionFields) WithTitle(title *string) QueryOption[FaqQueryOptionFields] {
    return func(q *FaqQueryOptionFields) {
        q.title = title
    }
}

func (qo FaqQueryOptionFields) WithCategoryType(categoryType *string) QueryOption[FaqQueryOptionFields] {
    return func(q *FaqQueryOptionFields) {
        q.categoryType = categoryType
    }
}</code></pre>
<h1 id="정리">정리</h1>
<p><strong>옵셔널 패턴(Functional Options Pattern)</strong></p>
<ul>
<li>장점: 단순하고 명확하게 옵션을 적용할 수 있으며, 확장이 용이.</li>
<li>단점: 옵션 함수가 많아지면 보일러플레이트 코드와 디버깅 복잡성이 증가할 수 있다.</li>
</ul>
<p><strong>제네릭을 활용한 옵셔널 패턴</strong></p>
<ul>
<li>장점: 여러 도메인에서 재사용 가능하고, 타입 안전성을 높이며, 코드 중복을 줄일 수 있다.</li>
<li>단점: 너무 범용화하면 코드가 복잡해지고, 단일 도메인에 대해서는 오히려 불필요하게 &quot;못생긴&quot; 코드가 될 위험이 있다.</li>
</ul>
<p>결국, 상황에 맞게 선택하는 것이 중요하다.
단일 도메인이나 제한된 옵션이 필요한 경우에는 전통적인 옵셔널 패턴이 더 직관적일 수 있고,
여러 도메인에서 공통으로 사용하거나 복잡한 옵션 로직이 필요한 경우에는 제네릭을 적절히 활용해 재사용성과 타입 안전성을 높이는 것이 좋다</p>
<h3 id="추천-읽어보면-좋은-글">(추천) 읽어보면 좋은 글</h3>
<p><a href="https://medium.com/@johnsiilver/go-optional-arguments-in-the-age-of-generics-f8eba23103ad">https://medium.com/@johnsiilver/go-optional-arguments-in-the-age-of-generics-f8eba23103ad</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[12. 단위 테스트]]></title>
            <link>https://velog.io/@hyeonz_kang/12.-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@hyeonz_kang/12.-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Mon, 06 Feb 2023 16:02:14 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/d41ac14e-a5ff-458e-a8b5-550c160f4790/image.jpg" alt=""></p>
<h2 id="12-단위-테스트">12. 단위 테스트</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>변하지 않는 테스트를 만들자</li>
<li>공개 API를 통해 테스트하자</li>
<li>상호작용이 아닌 상태를 테스트하자</li>
<li>테스트는 완전하고 명확하게</li>
<li>메서드가 아닌 행위를 테스트하자</li>
<li>행위가 부각되게 테스트 하자</li>
<li>테스트의 이름은 검사하는 행위가 잘 드러나도록 짓자</li>
<li>테스트에는 로직을 포함하지 말자</li>
<li>실패 메시지를 명확하게</li>
</ul>
<p><a href="https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-11">[11장. 테스트 개요]</a>에서는 테스트를 분류하는 주요 축인 크기와 범위를 소개했습니다. 크기란 테스트가 소비하는 자원과 수행할 수 있는 작업을 뜻하고, 범위는 테스트가 검증하고자 하는 코드의 양을 의미합니다.
구글은 작은 범위의 테스트인 단위 테스트를 선호합니다. 이는 <strong>버그를 예방할 뿐만 아니라 엔지니어의 생산성 개선에도 도움</strong>을 줍니다. 왜냐하면 작성하기 쉽고, 빠르고 결정적이어서 개발자들이 수시로 피드백 할 수 있으며, 실패시 원인 파악이 빠르기 때문입니다. 또한 단위 테스트는 문서자료나 예제 코드의 역할까지 수행합니다.
구글에서는 수없이 작성되고 실행되는 단위 테스트의 <strong>테스트 유지보수성(test maintainability)</strong>을 중시합니다. 이번 장에서는 이것이 무엇인지 알아보고 높은 유지보수성을 달성하는 기법들을 배워봅시다.</p>
<h3 id="1-유지보수하기-쉬워야-한다">1. 유지보수하기 쉬워야 한다</h3>
<blockquote>
<p><strong>깨지기 쉬운(bittle) 테스트</strong>
실제로 버그가 없음에도, 심지어 검증 대상과 관련 없는 변경 때문에 실패하는 테스트
<strong>불명확한(unclear) 테스트</strong>
무엇이 잘못되어 실패했는지, 어떻게 고쳐야 하는지를 파악하기 어려운 테스트</p>
</blockquote>
<p>위와 같은 테스트를 작성했다면 아주 간단한 기능을 수정했을 뿐인데 자동 테스트 시스템이 오류를 뱉어내며 소위 말하는 억까를 시전할 수 있습니다. 이런 테스트는 원래의 의도와는 정반대의 효과를 내며 생산성을 저하시킵니다. 어떻게 하면 깨지기 쉬운 테스트를 예방하고 명확한 테스트를 작성할 수 있는지 다음에서 설명하겠습니다. </p>
<h3 id="2-깨지기-쉬운-테스트-예방">2. 깨지기 쉬운 테스트 예방</h3>
<p><strong>1) 변하지 않는 테스트로 만들기</strong>
이상적인 테스트라면 변하지 않아야 합니다. 한 번 작성한 후로 대상 시스템의 요구사항이 바뀌지 않는 한 절대 수정할 일이 없어야 합니다. 코드 변경 유형에는 다음의 네가지 유형들이 있는데, 각 유형별로 테스트가 어떻게 대응해야 하는지 따져보겠습니다.</p>
<ul>
<li><p><strong>순수 리팩토링</strong>
성능 최적화, 코드 가독성 개선 등 내부만 리팩토링하는 코드 변경입니다. 이 때는 테스트에 변경이 있으면 안됩니다. 만약 테스트 변경이 필요하다면 이는 순수 리팩토링을 한 것이 아니거나, 테스트의 추상화 수준이 적절하지 않았다는 뜻입니다.</p>
</li>
<li><p><strong>새로운 기능 추가</strong>
새로운 기능이나 행위를 추가할 때는 기존 행위에 영향을 주지 않아야 합니다. 그러므로 기존 테스트의 변경 없이 새 기능을 검증할 테스트만 추가 됩니다.</p>
</li>
<li><p><strong>버그 수정</strong>
버그가 존재한다는 것은 기존 테스트에 빠진 것이 있다는 의미입니다. 따라서 버그 수정과 함께 누락된 테스트를 추가해야 합니다. 새로운 기능추가와 비슷하게 기존의 테스트는 수정하지 않습니다.</p>
</li>
<li><p><strong>행위 변경</strong>
시스템의 기존 행위를 변경하는 경우로 기존 테스트 역시 변경되어야 합니다. </p>
</li>
</ul>
<p>즉, 순수 리팩토링, 새 기능 추가, 버그 수정은 기존 테스트를 수정할 일이 없어야 합니다. 시스템을 확장할 때는 기존 테스트들을 일일이 손보는 것이 아니라 확장한 부분과 관련된 소수의 테스트만 새로 작성하면 됩니다.</p>
<p><strong>2) 공개 API를 사용해 테스트하기</strong> 
공개 되지 않은(ex. private 메소드) 로직을 직접 테스트하는 것은 실제 사용자와는 매우 다르게 사용하는 것입니다. 이런 테스트는 깨지기 쉬워집니다. 하지만 공개 API만 사용해서 테스트한다면 정의상 대상 시스템을 사용자와 똑같은 방식으로 사용하는 것이므로 더 현실적이고 깨지지 않습니다.
공개 API란 코드 소유자가 third-party에 노출한 API를 의미합니다. 명확히 어디까지가 공개 API라고 규정할 수는 없지만 구글은 다음과 같은 팁을 공유합니다.</p>
<ul>
<li><p>소수에 대한 보조 메소드/클래스
소수의 다른 클래스를 보조하는 용도인 메서드나 클래스라면 <strong>독립된 단위로 생각하지 않습니다.</strong> 이런 것들은 직접 테스트하지 말고 이들이 보조하는 클래스를 통해 우회적으로 테스트 합니다.  </p>
</li>
<li><p>누구나 접근 가능한 패키지/클래스
소유자의 통제 없이 누구나 접근 가능한 패키지나 클래스라면 <strong>직접 테스트하는 단위로 취급</strong>해야합니다. </p>
</li>
<li><p>접근 제한이 있고 다방면으로 보조적인 패키지/클래스
소유자만 접근 가능하지만 다방면으로 유용한 기능을 제공하는 패키지나 클래스는 <strong>직접 테스트 하는 단위로 취급</strong>해야 합니다. 테스트 중복이 생길 수 있지만 이는 유익한 중복입니다.</p>
</li>
</ul>
<p>이따금 &quot;내부 구현을 직접 테스트 하는 것이 좋은 것 아니야?&quot; 라고 의심하는 개발자들이 있습니다. 하지만 구글의 경험상 그것은 여러번 유지보수를 하도록 만드는 원인이 됩니다.</p>
<p><strong>3) 상호작용이 아닌 상태를 테스트하기</strong> </p>
<pre><code>- 상태 테스트
메서드 호출 후 시스템 자체를 관찰

- 상호작용 테스트
호출을 처리하는 과정에서 시스템이 다른 모듈들과 협력해 기대한 동작을 수행하는지 관찰</code></pre><p>대체로 상호작용 테스트가 상태 테스트보다 깨지기 쉽습니다. 우리가 진짜 원하는 것은 결과가 무엇(WHAT)이냐지만, 상호작용 테스트는 결과에 도달하기까지 시스템이 어떻게(HOW) 동작하냐를 확인하려하기 때문입니다.
상호작용 테스트는 Mocking Framework에 지나치게 의존해서 만들어집니다. 진짜 객체가 빠르고 결정적이라면 테스트 대역을 지양하고 진짜 객체를 사용해야 합니다.</p>
<h3 id="3-명확한-테스트-작성">3. 명확한 테스트 작성</h3>
<p>테스트가 실패하는 이유는 크게 두가지 입니다.</p>
<ul>
<li>대상 시스템에 문제가 있거나 불완전할 때</li>
<li>테스트 자체에 결함이 있을 때</li>
</ul>
<p>테스트가 실패했다면 둘 중 어느 부류인지 빠르게 파악하는 것이 중요합니다(=명확성). 그래서 명확한 테스트라 함은 존재 이유와 실패 원인을 엔지니어가 곧바로 알아차릴 수 있는 테스트를 말합니다. 명확한 테스트를 작성하는 방법은 다음과 같습니다.</p>
<p><strong>1) 완전하고 간결하게 만들기</strong></p>
<blockquote>
<p><strong>완전한 테스트</strong>
결과에 도달하기까지의 논리를 이해하는 데 필요한 모든 정보가 본문에 담겨있는 테스트
<strong>간결한 테스트</strong>
코드가 산만하지 않고, 관련 없는 정보는 포함하지 않은 테스트</p>
</blockquote>
<p>두 특성 중 어느하나라도 담고 있지 않다면 안좋은 테스트입니다.</p>
<p><strong>2) 메서드가 아니라 행위를 테스트하기</strong></p>
<blockquote>
<p><strong>행위</strong>
특정 상태에서 특정한 일련의 입력을 받았을 때 시스템이 보장하는 반응</p>
</blockquote>
<p>보통 메서드 하나 당 테스트 하나를 구현하려고 합니다. 하지만 행위를 기준으로 매서드를 바라보면 행위와 매서드는 다대다 관계입니다. 어떤 행위는 메서드 여러개를 연계해야 완성됩니다. 메서드에 얽메이지 않고 테스트를 구현해야 합니다. </p>
<p>행위 주도 테스트는 메서드 중심 테스트보다 명확합니다. 이유는 다음과 같습니다.</p>
<ul>
<li>자연어에 더 가깝게 읽히기 때문</li>
<li>테스트 각각이 더 좁은 범위를 검사하기 때문</li>
<li>각 테스트가 짧고 서술적이어서 이미 검사한 기능이 무엇인지 더 쉽게 확인할 수 있기 때문</li>
</ul>
<p><strong>테스트의 구조는 행위가 부각되도록</strong> 구성해야합니다. <strong>given/when/then</strong>으로 나누어 구성할 수 있습니다. assertion문을 코드 사이사이에 넣으면 읽기 어려워집니다. 이럴 땐 and문을 추가하거나 메서드를 쪼개야합니다. <strong>테스트 각각은 하나의 행위만 검사</strong>해야 합니다.</p>
<p>또한 <strong>테스트의 이름은 길고 상세해도 좋으니 검사하는 행위에 맞게 지어야합니다.</strong> 같은 테스트 클래스 안에서만 일관적이라면 다양한 방식의 이름 짓기 전략도 괜찮습니다. should로 시작하는 이름을 사용하는 것도 좋은 방법입니다.</p>
<p><strong>3) 테스트에 논리를 넣지 말기</strong>
테스트가 명확하면 검토하기 쉽습니다. 논리(연산자, 반복문, 조건문 등)가 포함되면 명확성을 해치게 됩니다. 스마트한 로직보다는 <strong>직설적인 코드</strong>를 고집해야 합니다. 또한 더 서술적이고 의미있는 테스트를 위해 약간의 중복은 허용하는 것이 좋습니다.</p>
<p><strong>4) 실패 메시지를 명확하게 작성하기</strong>
실패 메시지는 문제의 원인을 잘 파악할 수 있도록 작성해야 합니다. 그래서 {원하는 결과}, {실제 결과}, {이때 받은 매개변수}를 포함해야 합니다.</p>
<pre><code>[안좋은 예]
Test failed: account is closed</code></pre><pre><code>[좋은 예]
Expected an account is state CLOSED, but got account:
 {name: &quot;my account&quot;, state: &quot;OPEN&quot;}</code></pre><h3 id="4-테스트와-코드-공유-dry가-아니라-damp">4. 테스트와 코드 공유: DRY가 아니라 DAMP!</h3>
<blockquote>
<p><strong>DRY</strong>
Don&#39;t Repeat Yourself (반복하지 말라)
<strong>DAMP</strong>
Descriptive And Meaningful Phrase (서술적이고 의미있는 문구)</p>
</blockquote>
<p>원래 프로그래밍에서는 DRY 원칙을 따릅니다. 이것이 더 유지보수하기 쉽기 때문입니다. 하지만 테스트 코드에서는 DAMP 원칙을 따라야 합니다. 테스트에서 DRY를 고집하면 명확성이 떨어지며, 테스트가 복잡해집니다. DAMP가 DRY를 대체하는 것이 아니라 보완하는 개념입니다. <strong>테스트에서의 리팩토링은 반복을 줄이는 것이 아니라 더 서술적이고 의미 있게 하는 방향으로 이루어져야 한다</strong>는 것이 핵심입니다.</p>
<p>코드를 여러 테스트가 공유하는 패턴은 어떻게 구현해야 할까요? 다음의 세가지 분류로 알아보겠습니다.
** 1) 공유 값 (shared value)**
테스트 작성자가 필요한 값들만 명시해 도우미 메서드에 요청하면 그 외 값들에는 적절한 기본값을 설정해서 반환하도록 합니다.</p>
<p>** 2) 공유 셋업 (shared setup)**
setup 메서드란 테스트 스위트에 속한 테스트 각각을 수행하기 직전에 실행되는 메서드입니다. 대상 객체와 협력 객체(collaborator)를 생성하는데 유용합니다. 해당 객체를 생성할 때 쓰인 인자를 몰라도 되고, 테스트 수행 후에도 객체의 상태가 변하지 않을 때 유용합니다. 특정 값을 요구하는 테스트라면 코드가 반복되더라도 값을 재정의 해야 합니다.</p>
<p>** 3) 공유 도우미 메서드와 공유 검증 메서드**
테스트용 값을 생성하는 생성할 때는 공유 도우미 메서드가 효율적입니다. 검증 메서드는 여러 조건을 확인하지 않고 하나의 목적에만 집중해야 합니다.</p>
<blockquote>
<p><strong>테스트 인프라</strong>
다른 테스트 스위트와 코드를 공유해 유용해지는 코드
통합 테스트나 end-to-end 테스트 때 유용하며, 의존하는 코드가 많다. 테스트 인프라는 독립된 제품 대우를 해줘야 하며 테스트 인프라를 검사할 자체 테스트가 필요하다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[18. 빌드 시스템과 빌드 철학]]></title>
            <link>https://velog.io/@hyeonz_kang/18.-%EB%B9%8C%EB%93%9C-%EC%8B%9C%EC%8A%A4%ED%85%9C%EA%B3%BC-%EB%B9%8C%EB%93%9C-%EC%B2%A0%ED%95%99</link>
            <guid>https://velog.io/@hyeonz_kang/18.-%EB%B9%8C%EB%93%9C-%EC%8B%9C%EC%8A%A4%ED%85%9C%EA%B3%BC-%EB%B9%8C%EB%93%9C-%EC%B2%A0%ED%95%99</guid>
            <pubDate>Sat, 28 Jan 2023 15:04:11 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/e9681bd4-9c08-4174-811d-12c10b3a1c50/image.jpg" alt=""></p>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>개발자들의 생산성 유지를 위해 제대로 된 빌드 시스템은 필수</li>
<li>빌드 시스템에 적절한 제한을 두면 개발자는 더 편리해짐</li>
<li>아티팩트 중신으로 구성된 빌드 시스템이 태스크 중심보다 확장성과 안정성 면에서 우수</li>
<li>아티팩트와 의존성을 정의할 때 모듈을 작게 나누자 -&gt; 작은 모듈들이 병렬 빌드와 증분 빌드의 이점을 더 잘 활용하기 때문</li>
<li>외부 의존성의 버전도 명확하게 버전관리 해야함 -&gt; 단순히 &#39;최신&#39; 버전에 의존해서는 안됨</li>
</ul>
<p>구글은 엔지니어가 빠르고 안정적으로 빌드할 수 있도록 설립 초기부터 자체 빌드 시스템을 구축하는데 엄청나게 투자했습니다. 구글이 생각하는 <strong>모던 빌드 시스템</strong>이란 무엇이고 이런 시스템을 어떻게 활용하는지에 대해 알아봅시다.</p>
<h2 id="01-빌드-시스템의-목적">01. 빌드 시스템의 목적</h2>
<p>모든 빌드 시스템의 기본 목적은 엔지니어들이 작성한 소스 코드를 기계가 읽을 수 있는 바이너리로 변환하는 것입니다. 좋은 빌드 시스템은 다음 두가지를 최적화 합니다.</p>
<ul>
<li><strong>속도</strong>
개발자가 명령 하나로 빌드를 수행하고 몇 초안에 결과 바이너리를 얻을 수 있어야 한다.</li>
<li><strong>정확성</strong>
소스 파일과 기타 입력 데이터가 같다면 모든 개발자가 어떤 컴퓨터에서 빌드하더라도 항상 동일한 결과가 나와야 한다.</li>
</ul>
<p>과거 빌드 시스템은 속도와 정확성 사이에서 절충 하려다 보니 빌드 결과가 일관되지 못하는 문제가 있엇습니다. 구글의 빌드 시스템 Bazel은 속도와 정확성 어느 하나 희생하지 않고 빌드 시스템이 언제나 효율적이며 일관된 빌드를 수행하는 것을 목표로 했습니다.</p>
<h2 id="02-빌드-시스템이-없다면">02. 빌드 시스템이 없다면?</h2>
<p>빌드 시스템 없이 프로젝트 규모를 확장하려고 하면 온갖 난관에 부딪힐 것입니다. 우선 컴파일러로는 불충분합니다. 컴파일러는 외부 의존성을 다루는 방법을 전혀 모르기 때문입니다. 셸 스크립트로도 부족합니다. 시스템이 조금만 복잡해져도 스크립트를 개발하고 관리하는데 어려워집니다. 그리고 스크립트로 의존성을 매번 정확한 순서로 빌드하도록 하면 속도가 매우 느립니다.
그러므로 제대로된 빌드 시스템이 꼭 있어야만 합니다.</p>
<h2 id="03-모던-빌드-시스템">03. 모던 빌드 시스템</h2>
<p>작업 사이의 의존성, ARTIFACT 사이의 의존성, 자기 코드베이스 내부 의존성, third-party가 소유한 코드나 데이터로의 외부 의존성 등 다양한 의존성이 있습니다. 어떤 경우이든 빌드 시스템을 구축하는 데는 <strong>&quot;이걸 하려면 저게 필요해&quot; 패턴</strong>이 반복되며, 이러한 <strong>의존성을 관리</strong>하는 일이 가장 기본이 되는 작업입니다.</p>
<h4 id="task-based-build-system">[task-based build system]</h4>
<p>기본 작업 단위는 태스크 입니다. 셸 스크립트, Ant, Maven, Gradle, Grunt 등이 대표적인 태스크 기반 빌드 시스템입니다. 대부분 모던 빌드 시스템은 셸 스크립트 대신 빌드 파일을 이용합니다. 빌드 파일은 빌드 수행 방법을 기술한 파일입니다. 이는 대부분 엔지니어가 작성합니다. 빌드 파일을 사용하면 다음과 같은 이점이 있습니다.</p>
<ul>
<li>빌드 파일들을 서로 다른 디렉토리에 만든 후 연결 할 수 있다.</li>
<li>기존 태스크에 의존하는 새로운 태스크들을 임의의 복잡한 방식으로 쉽게 추가할 수 있다.</li>
</ul>
<p>하지만 단점이 있습니다. <strong>태스크 기반 빌드 시스템은 빌드 스크립트가 커져서 복잡해질 수록 다루기 어렵습니다. 시스템은 스크립트가 뭘 하는지 알 수 없으므로 각각의 빌드 단계를 매우 보수적으로 실행할 수밖에 없고, 이는 성능 저하의 원인이 됩니다.</strong> 또한 시스템은 각 스크립트가 할 일을 올바르게 수행하고 있는지 확인할 방법이 없습니다.</p>
<pre><code>엔지니어에게 너무 많은 힘을, 시스템에는 충분하지 못한 힘을 준다.</code></pre><blockquote>
<p><strong>주요 단점</strong></p>
</blockquote>
<ul>
<li>빌드 단계들을 병렬로 실행하기 어렵다.</li>
<li>증분 빌드(incremental build)를 수행하기 어렵다.</li>
<li>스크립트를 유지보수하고 디버깅 하기 어렵다.</li>
</ul>
<p><strong>태스크 기반 프레임워크에서는 성능, 정확성 유지보수성 문제를 한번에 해결할 수 있는 방법이 없습니다.</strong> 빌드 중에 실행되는 임의의 코드(빌드 스크립트)를 엔지니어가 작성할 수 있다는 것은 빌드를 빠르고 정확하게 수행하는 데 필요한 정보 일부가 누락될 수 있다는 뜻입니다.</p>
<h4 id="artifact-based-build-system">[artifact-based build system]</h4>
<p>아티팩트 기반 빌드 시스템은 태스크 기반보다 엔지니어의 힘을 제한합니다. <strong>엔지니어는 시스템에게 &#39;무엇&#39;을 빌드할지 정해줄 수 있지만 &#39;어떻게&#39;는 시스템이 알아서 합니다.</strong> 어떤 도구를 언제 실행할지를 빌드 시스템이 완전히 통제하므로 정확성을 보장하고 효율성을 높일 수 있습니다. 프로그래머 입장에서는 유연성이 줄어드는 대신 빌드의 각 단계에서 무슨 일이 이루어지는지를 빌드 시스템이 알게 됩니다. 빌드 시스템은 이 지식을 활용해 빌드 프로세스를 병렬화하고 최대한 많은 것을 재사용해 효율을 극대화시킵니다. 
기능적 관점에서 아티팩트 기반 빌드 시스템은 함수형 프로그래밍과 비슷한 점이 많습니다. 함수형 언어는 문제들을 병렬화하기가 쉽고 정확성을 보장해줍니다. 함수형 프로그램으로 표현하기 가장 쉬운 문제로는 일련의 규칙이나 함수를 이용해 데이터 조각 하나를 다른 데이터로 변환하기가 있습니다. 아티팩트 기반 빌드 시스템도 마찬가지 입니다.</p>
<blockquote>
<p><strong>Bazel의 특징</strong></p>
</blockquote>
<ul>
<li><strong>도구도 의존성으로 취급</strong>
빌드에 필요한 도구를 선언하도록해 언제 어느 시스템에서 빌드하든 정확한 도구들이 먼저 갖춰지도록 한다. 플랫폼에 의존하는 문제는 툴체인을 이용해 해결한다.</li>
<li><strong>빌드 시스템 확장</strong>
커스텀 규칙을 추가해 타깃 종류를 확장하는 방법을 제공한다.</li>
<li><strong>환경 격리하기</strong>
샌드박싱 기술로 액션들끼리 같은 파일을 써 서로 충돌하는 문제를 막았다. 액션은 입력으로 선언하지 않은 파일은 읽을 수 없고, 출력으로 선언하지 않은 파일에 쓰면 액션 종료 즉시 버려진다. 심지어 액션들이 네트워크로 서로 통신할 수 없다.</li>
<li><strong>외부 의존성 명확히 드러내기</strong>
의존성 변경은 의식적으로 진행해야 하지만 중앙에서 한 번만 이루어져야 한다. 버전 충돌 문제는 외부 의존성 각각의 암호화 해시를 워크스페이스 차원의 매니페스트 파일에 기록하여 해결한다. 해시를 통해 전체 파일을 소스 관리하에 두지 않고도 고유하게 식별 가능해진다.</li>
</ul>
<h2 id="04-분산-빌드">04. 분산 빌드</h2>
<p>분산 빌드란 <strong>단위 작업들을 여러 컴퓨터에 뿌려 빌드한 후 취합해 최종 결과를 만들어주는 기술</strong>입니다. 빌드 단위를 충분히 작게 쪼갤 수 있다면 큰 빌드도 원하는 시간 내 끝낼 수 있습니다.</p>
<p><strong>원격 캐싱</strong>
<img src="https://velog.velcdn.com/images/hyeonz_kang/post/27e89fb9-37d2-4702-ad58-76968c254e60/image.png" alt=""></p>
<p>빌드를 수행하는 모든 시스템, 즉 개발자 컴퓨터와 지속적 통합 시스템 모두 공통의 원격 캐시 서비스를 참조하는 모양입니다. <strong>자주 변경되지 않는 저수준 라이브러리</strong>는 한 번 빌드되면 많은 사용자에게 공유됩니다. 이런 식으로 구글은 빌드 시스템 운영 비용을 크게 절감하고 있습니다. 
원격 캐시 시스템이 제역할을 하려면 빌드 시스템이 빌드를 완벽하게 재현할 수 있어야 합니다. 참고로 캐시된 아티팩트들의 key로는 해당 타깃과 입력값들의 해시 모두가 제공되어야 합니다. 아티팩트를 다운로드 하는 시간이 새로 빌드할 때보다 빨라야 원격 캐시가 의미 있습니다.</p>
<p><strong>원격 실행</strong>
<img src="https://velog.velcdn.com/images/hyeonz_kang/post/7315cb71-095a-4cbf-b075-1c57a789cae5/image.png" alt=""></p>
<p>원격 실행은 빌드를 하는 &#39;실제&#39; 작업들을 여러 워커에 나눠 수행하는 기술입니다. 빌드 마스터는 요청 받은 빌드를 구성하는 액션들을 스케줄링 합니다. 이때 worker pool이 활용됩니다. 빌드 환경은 필요한 모든 것을 완벽하게 자기 기술(self-descriptive)해야 워커들이 사람의 개입없이 동작할 수 있습니다.</p>
<p><strong>분산 빌드 @ 구글</strong>
<img src="https://velog.velcdn.com/images/hyeonz_kang/post/a4a0dc2f-0b41-4951-8864-e8d307f5563a/image.png" alt=""></p>
<p><strong>ObjFS는 구글 버전의 원격캐시</strong>입니다. ObjFS는 백엔드와 프론트엔드로 구성됩니다. 백엔드는 구글의 프로덕션 머신들 전체에 배포된 빅테이블에 결과를 저장합니다. 프론트엔드는 Objfsd라는 이름의 FUSE 데몬이 각 개발자의 컴퓨터에서 실행되는 형태입니다. 파일의 내용은 사용자가 직접 요청할 때만 on-demand로 다운로드합니다. 덕분에 네트워크와 디스크 사용을 크게 줄여주며, 모든 빌드 결과를 개발자 컴퓨터에 저장할 때보다 빌드가 두 배나 빨라집니다.
<strong>Forge는 구글의 원격 실행 시스템</strong>입니다. Blaze단의 Forge 클라이언트(Forge Distributor)가 데이터센터에서 실행 중인 스케줄러에 수행할 액션들을 전송합니다. 스케줄러는 액션의 결과를 캐싱해두었다가 똑같은 액션이 요청될 경우 즉시 돌려줍니다. 캐시된 결과가 없다면 해당 액션을 큐에 추가합니다. 큐에서 가져온 액션들을 실행하고, 결과는 ObjFS 빅테이블에 직접 저장합니다. </p>
<h2 id="05-모듈과-의존성-다루기">05. 모듈과 의존성 다루기</h2>
<p>프로젝트의 각 모듈은 다른 모듈과의 의존 관계를 BUILD 파일에 기술합니다. 이 모듈과 의존성을 어떻게 구성하느냐가 빌드 시스템의 성능과 감당할 수 있는 작업량에 지대한 영향을 줍니다. </p>
<p><strong>작은 모듈 사용</strong>
Bazel에서 모듈은 빌드 가능한 단위를 지정하는 타깃을 말합니다. 모듈의 단위를 크게 잡으면 build 파일을 관리하기 쉽겠지만 빌드 단계를 병렬로 실행하거나 분산할 수 없습니다. 반대로 작게 잡으면 빌드 시스템은 캐시와 분산 빌드를 최대로 이용할 수 있습니다. 하지만 엔지니어가 build 파일을 유지보수하기 힘들어집니다. 구글은 작은 단위의 모듈을 선호합니다.</p>
<pre><code>자바의 경우 각 디렉토리가 보통 하나의 패키지, 타깃, 빌드 파일을 갖습니다. 
이를 [1:1:1 규칙]이라 합니다.</code></pre><p><strong>모듈 가시성 최소화</strong>
Bazel을 포함한 여러 빌드 시스템은 타깃이 가시성을 명시할 수 있게 합니다. 가시성이란 자신에게 의존할 수 있는 타깃의 범위를 지정하는 속성입니다. 가시 범위는 가능한 좁히는 것이 좋습니다. </p>
<p><strong>의존성 관리</strong></p>
<ul>
<li><p>내부 의존성
내부 의존성은 의존하는 타깃 대부분이 같은 소스 리포지터리에서 정의되고 빌드 됩니다. 이는 <strong>소스로부터 빌드</strong>된다는 점에서 외부 의존성과 차이가 납니다. 또한 <strong>&#39;버전&#39;이란 개념이 없습니다.</strong> 
내부 의존성에서 주의할 점은 <strong>전이 의존성을 어떻게 취급하느냐</strong> 입니다. 구글은 Blaze에 <strong>엄격한 전이 의존성 모드(strict transitive dependency mode)</strong>를 도입하여 문제를 해결했습니다. </p>
</li>
<li><p>외부 의존성
외부 의존성은 빌드 시스템 바깥에서 저장되어 있는 아티팩트를 발합니다. 아티팩트 리포지터리에서 직접 가져와 그대로 이용합니다. 또한 내부 의존성과 달리 <strong>&#39;버전&#39;이 있습니다.</strong></p>
<ol>
<li><p>외부 의존성은 자동, 수동으로 관리할 수 있습니다. 구글은 <strong>수동</strong>관리를 선호합니다. </p>
</li>
<li><p>구글은 코드베이스에서 이용하는 모든 thrid-party 의존성들에 <strong>one-version 규칙</strong>을 강제했습니다. 같은 라이브러리에 다양한 버저닝을 할 경우 다이아몬드 의존관계가 만들어지기 때문입니다.</p>
</li>
<li><p>외부 의존 대상의 전이 의존성은 다루기 어렵습니다. 하지만 Bazel은 <strong>전이 의존성을 자동으로 다운로드하지 않습니다.</strong> 자동으로 관리할 경우 예상하지 못한 문제가 많이 발생하기 때문입니다.</p>
</li>
<li><p><strong>외부 의존성을 이용해 빌드 결과를 캐시</strong>합니다. 애티팩트를 직접 빌드하기보다 다운로드 하는것이 빠를 수 있지만 이는 상당한 오버헤드와 복잡성이 더해집니다. 그래서 원격 캐시를 지원하는 빌드 시스템을 이용해 대처합니다.</p>
</li>
<li><p>third-party 아티팩트는 가용성 위험, 보안 위험을 갖고 있습니다. 두 위험은 필요한 모든 아티팩트를 통제할 수 있는 서버에 미러링 해두고, 빌드 시스템이 third-party 아티팩트 리포지터리를 이용하지 못하게 하면 해결할 수 있습니다. 또는 프로젝트에 필요한 의존성을 복사해 프로젝트에 포함시켜 해결할 수도 있습니다.</p>
<pre><code>Vendoring: 외부 의존성을 자신의 관리 하에 두는 것</code></pre></li>
</ol>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[10. 문서자료]]></title>
            <link>https://velog.io/@hyeonz_kang/10.-%EB%AC%B8%EC%84%9C%EC%9E%90%EB%A3%8C</link>
            <guid>https://velog.io/@hyeonz_kang/10.-%EB%AC%B8%EC%84%9C%EC%9E%90%EB%A3%8C</guid>
            <pubDate>Sun, 15 Jan 2023 16:34:21 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/8400103d-0bbd-4007-acdf-7072f4494a07/image.jpg" alt=""></p>
<h2 id="10-문서자료">10. 문서자료</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>문서자료는 시간이 흐르고 조직 규모가 커질수록 더 중요</li>
<li>문서자료 변경도 기존 개발자 워크플로에 통합되어야 함</li>
<li>하나의 문서는 하나의 목적에 집중하자</li>
<li>문서자료는 작성자가 아니라 독자를 위해 써야함</li>
</ul>
<p>엔지니어들이 양질의 문서자료를 더 쉽게 작성하도록 하는 비결이 무엇일까요? 바로 현재 개발 워크플로에 긴밀하게 통합되고 조직의 성장에 발맞춰 확장되는 프로세스와 도구입니다. <strong>문서자료를 코드처럼 취급</strong>하여 엔지니어링 워크플로에 통합해야 합니다.</p>
<h3 id="1-문서자료의-필요성">1. 문서자료의 필요성</h3>
<p>이번 장에서 말하는 <strong>문서자료(documentation)</strong>란 엔지니어가 작업을 끝마치기 위해 작성해야하는 모든 부수적인 텍스트를 의미합니다. 그러므로 별도로 작성한 문서뿐 아니라 코드 주석까지 포함합니다. 
문서자료는 이렇게 설계한 이유, 이렇게 코드를 구성한 이유 등을 설명해주는 중요한 역할을 하지만 엔지니어들이 &#39;덜 중요하게&#39; 생각하는 이유가 무엇일까요? </p>
<ul>
<li>혜택이 (특히 작성자에게) 즉각적으로 돌아오지 않는다.</li>
<li>많은 엔지니어가 글쓰기를 프로그래밍과는 별개의 기술로 본다. (이 시각은 잘못되었다. 글쓰기는 SW 엔지니어링에 꼭 필요한 기술이다.)</li>
<li>글쓰기에 자신없어 하는 엔지니어도 있다. (영어에 꼭 유창해야만 양질의 문서자료를 작성할 수 있는 것은 아니다.)</li>
<li>문서자료는 도구 지원이나 개발 워크플로 통합 측면에서 아직 만이 부족하기 때문에 작성하기가 상대적으로 더 어렵다.</li>
<li>문서자료를 유지보수할 대상이 하나 더 늘어난 짐으로 생각한다.</li>
</ul>
<p>하지만 문서자료는 다음과 같은 혜택을 줍니다.</p>
<ul>
<li>API를 가다듬는데 도움이 된다. </li>
<li>유지보수를 위한 로드맵과 과거 이력을 제공한다. (코딩에서 꼼수는 무조건 피해야 하지만, 어쩔 수 없다면 주석이라도 잘 달아둬야 한다.)</li>
<li>코드를 더 전문적이고 매력 있어 보이게 한다. (실제로 문서화가 잘되어 있는 제품은 유지관리가 잘되고 있는 제품일 확률이 높다.)</li>
<li>이용자들의 질문이 줄어든다. </li>
</ul>
<p>문서자료는 세월이 흐를수록 더 중요해지며, 특히 핵심 코드를 잘 문서화해두면 조직이 커질수록 지대한 기여를 합니다. </p>
<h3 id="2-문서자료는-코드와-같다">2. 문서자료는 코드와 같다</h3>
<p><strong>문서자료에도 프로그래밍 언어처럼 규칙이 있고, 구문 규정이 있고, 스타일도 있습니다.</strong> 코드와 마찬가지로 일관되어야 하고, 명확해야 하고, 이해를 방해하는 오류를 피해야 합니다. 이는 설명하는 문체를 표준화하고 혼동 요소를 없애 독자가 헷갈리지 않게 하기 위함입니다.
따라서 문서자료는 다음과 같이 취급해야합니다.</p>
<ul>
<li>꼭 따라야 하는 내부 정책과 규칙이 있어야 한다.</li>
<li>버전 관리 시스템에 등록해 관리해야 한다.</li>
<li>관리 책임자를 명시해야 한다.</li>
<li>변경 시 (문서자료가 설명하는 코드와 함께) 리뷰를 거쳐야 한다.</li>
<li>코드상의 버그를 추적하듯 문제를 추적해야 한다.</li>
<li>주기적으로 평가(혹은 테스트)를 받아야 한다.</li>
<li>가능하다면 정확성이나 최신 정보 반영 여부 등을 측정해야 한다.</li>
</ul>
<h3 id="3-문서자료는-독자에-맞게-쓰자">3. 문서자료는 독자에 맞게 쓰자</h3>
<p>엔지니어들이 문서자료를 작성하며 범하는 가장 중요한 실수는 자신만을 위해 쓴다는 것입니다. 좋은 문서자료라 해서 완벽할 필요는 없습니다. 하지만 <strong>독자가 누구인지는 꼭 파악</strong>한 후에 작성해야 합니다. 그리고 <strong>문서를 짧게 쓰는 것</strong>이 유리합니다. 독자 유형은 다음과 같이 나눌 수 있습니다.</p>
<ul>
<li><strong>경험 수준</strong>: 전문 프로그래머, 혹은 프로그래밍 언어조차 낯선 초보 엔지니어</li>
<li><strong>도메인 지식</strong>: 팀원, 혹은 최종 API 정도에만 친숙한 사내 다른 엔지니어</li>
<li><strong>목적</strong>: 제공하는 API를 사용해 특정 작업을 수행하거나 급히 정보를 얻어내야 하는 최종 사용자 등 </li>
</ul>
<p>사용자가 문서 자료를 접하게 되는 방식에 따라서 독자를 구분할 수 있습니다.</p>
<ul>
<li><strong>탐색자(seeker)</strong>
자신이 원하는 것을 <strong>정확히 알고</strong>, 읽고 있는 문서자료가 원하는 정보를 담고 있는지를 알고 싶어 하는 엔지니어 입니다. 이럴 때는 <strong>일관성</strong>이 핵심입니다. 비슷한 포맷을 일관되게 적용하는 것이 좋습니다.</li>
<li><strong>배회자(stumbler)</strong>
무엇을 원하는지를 <strong>정확하게 알지 못하는</strong> 사람입니다. 이럴 때는 <strong>명료한 글</strong>이 효과적 입니다. 예를 들어 파일의 맨 위에 개요나 소개 절을 두어 파일에 담겨 있는 코드의 목적을 설명할 수 있습니다. </li>
</ul>
<pre><code>[TL;DR문]
구글에서는 어떤 독자에게 적합하지 않은 문서인지도 알려줍니다.
예를들어 다음과 같이 TL;DR문을 사용해 표시합니다.
- TL;DR: 구글의 C++컴파일러가 궁금한 것이 아니라면 더 읽을 필요 없습니다. </code></pre><p> 마지막으로 <strong>고객</strong>(ex. API 사용자)이냐 <strong>제공자</strong>(ex. 프로젝트 팀원)이냐도 중요한 독자 구분 기준입니다. 가능하다면 각각의 독자를 위한 문서를 구분해주는 것이 좋습니다. 각자에게 필요한 정보가 다르기 때문입니다.</p>
<h3 id="4-문서자료의-유형">4. 문서자료의 유형</h3>
<p>다양한 문서자료의 종류가 다름을 알고 서로 섞이지 않게 하는 것도 중요합니다. 하나의 문서는 일반적으로 하나의 목적에 집중해야 합니다.</p>
<ol>
<li>참조용 문서자료
코드베이스에 속한 코드의 사용법을 설명하는 문서 모두를 일컫습니다. 가장 대표적인 예는 코드 주석입니다. </li>
</ol>
<pre><code>[코드 주석의 분류]
API 주석
- 구체적인 구현 방법이나 설계 결정 사항을 언급할 필요는 없음
- 사용자가 작성자만큼이나 API에 대해 잘 안다고 가정해서는 안됨
구현 주석
- 읽는 이가 도메인 지식을 상당히 갖추고 있다고 가정해도 됨</code></pre><ul>
<li>파일 주석
파일에 담겨 있는 내용을 요약해야 한다. 간결하게 설명할 수 없는 API라면 API의 설계가 잘못된 것일 수 있다.</li>
<li>클래스 주석
구글에서는 모든 공개 클래스(+구조체)는 클래스 주석을 담고 있어야 한다. 목적과 주요 메서드를 설명한다. </li>
<li>함수 주석
구글에서는 자유함수나 클래스의 공개 메서드에는 무조건 함수가 무슨 일을 하는지 설명하는 함수 주석이 있어야 한다. 능동성을 부각하기 위해 동사로 시작해야 한다. parameters, returns, throws 등의 섹션을 구분하지 않고 하나의 문장으로 표현하는 것이 더 명확하다. </li>
</ul>
<ol start="2">
<li><p>설계문서
구글의 팀 대부분은 중요한 프로젝트에 착수하기 전에 설계 문서부터 승인받아야 한다.</p>
</li>
<li><p>튜토리얼
튜토리얼은 프로젝트 환경을 새로 구축하는 과정을 담은 것입니다. 튜토리얼이 아직 없다면 누군가가 팀에 새로 합류했을 때입니다. 튜토리얼에는 어떠한 사전 설정, 권한, 도메인 지식도 가정하면 안됩니다. 무언가 먼저 설정되어 있다고 가정했다면 튜토리얼 앞부분의 사전 요구사항 절에 명시하세요.</p>
</li>
<li><p>개념 설명 문서
어떤 코드는 코드 주석 같은 참조용 문서자료만으로는 부족하여 깊이 있는 설명을 곁들여야 합니다. 이 때 해당 API나 시스템의 개요를 알려주는 개념문서를 첨부합니다. 개념 문서는 참조 문서자료들을 대체하기보다는 보강하는 역할입니다. 개념문서는 명확성이 중요하므로 다소 완전하지 않거나 (완전한 문서 역할은 참조문서가 담당) 때로는 정확성을 희생하곤 합니다.</p>
</li>
<li><p>랜딩 페이지
랜딩 페이지는 홈페이지의 교통경찰 역할을 합니다. 랜딩페이지의 목적을 명확히 인식하고 자세한 정보는 모두 다른 페이지를 가리키는 링크로 대체합니다. 랜딩페이지의 두가지 역할은 1)해당 팀 제품의 고객이나 API 사용자를 위한 goto 페이지 역할이고, 2)다른 하나는 팀의 홈페이지 역할입니다. 절대 두 역할을 한 페이지에서 수행하면 안됩니다.</p>
</li>
</ol>
<blockquote>
<p>코드 주석이 문서자료계의 단위 테스트라면, 개념 문서는 통합 테스트이다.</p>
</blockquote>
<h3 id="5-문서자료의-리뷰">5. 문서자료의 리뷰</h3>
<p>문서자료 역시 리뷰를 거쳐야 합니다. 기술 문서 리뷰에 효과적인 방식은 크게 세가지 입니다.</p>
<ul>
<li><p><strong>정확성</strong> 확인용 <strong>기술</strong> 리뷰
주로 해당 주제 전문가가 수행하며, 팀 동료인 경우가 많습니다. 코드 리뷰 과정에서 함께 다루곤 합니다.</p>
</li>
<li><p><strong>명확성</strong> 확인용 <strong>독자</strong> 리뷰
주로 도메인을 잘 모르는 사람이 수행합니다. 팀에 새로 합류한 동료나 해당 API의 고객일 것입니다.</p>
</li>
<li><p><strong>일관성</strong> 확인용 <strong>작문</strong> 리뷰
주로 테크니컬 라이터나 자원자가 수행합니다.</p>
</li>
</ul>
<h3 id="6-문서화-철학">6. 문서화 철학</h3>
<ol>
<li><p>누가 / 무엇을 / 언제 / 어디서 / 왜
대부분의 기술 문서 자료는 <strong>HOW</strong>에 대한 답을 제시합니다. 하지만 다음 질문들에 답하는 것이 더 도움 될 것입니다.</p>
<ul>
<li><strong>WHAT</strong>: 문서의 목적</li>
<li><strong>WHEN</strong>: 문서가 생성되고, 리뷰되고, 갱신된 날짜</li>
<li><strong>WHERE</strong>: 문서가 존재해야 할 장소</li>
<li><strong>WHY</strong>: 문서의 목적 (=요약, 문서의 소개 부분에 명시)</li>
</ul>
</li>
<li><p>시작 / 중간 / 끝
문서에 절을 추가하면 내용 흐름을 논리적 조각으로 나눌 수 있습니다. 또한 독자에게 문서가 다루는 내용의 로드맵을 제시할 수 있습니다. 각 절의 도입 단락에서 핵심을 요약해 알려준 후, 해당 절의 나머지에 구체적으로 사례를 설명하는 방법이 좋습니다. </p>
</li>
<li><p>좋은 문서자료의 특징
완전성(Completeness), 정확성(Accuracy), 명확성(Clarity) 이 세가지가 좋은 문서의 특징이지만 하나의 문서에 세 특징을 다 담기는 어렵습니다. 결국 &#39;좋은 문서&#39;란 의도한 역할을 잘 수행하는 문서여야 합니다. </p>
</li>
<li><p>문서 폐기하기
본래의 목적을 더 이상 수행할 수 없다면 폐기하거나 &#39;폐기 대상&#39;으로 표시해야 합니다. 구글에서는 문서자료에 &#39;신선도 보증 기간freshness date&#39;을 붙여두곤 합니다. </p>
</li>
</ol>
<h3 id="7-테크니컬-라이터가-필요한-순간은">7. 테크니컬 라이터가 필요한 순간은?</h3>
<p>구글은 예전에 중요하다고 생각되는 프로젝트에는 팀에 정말 필요한지와 상관없이 테크니컬 라이터를 배정하는 경향이 있었습니다. 하지만 이는 잘못된 가정으로 판명됐습니다. 엔지니어들은 팀에 필요한 문서자료를 스스로 완벽하게 작성할 수 있습니다. 테크니컬 라이터가 필요한 경우는 오직 팀원 외 독자를 위한 문서를 작성할 때뿐입니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[22. 대규모 변경]]></title>
            <link>https://velog.io/@hyeonz_kang/22.-%EB%8C%80%EA%B7%9C%EB%AA%A8-%EB%B3%80%EA%B2%BD</link>
            <guid>https://velog.io/@hyeonz_kang/22.-%EB%8C%80%EA%B7%9C%EB%AA%A8-%EB%B3%80%EA%B2%BD</guid>
            <pubDate>Thu, 05 Jan 2023 15:39:52 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/70b0eafb-588f-4c90-845e-bbe589534747/image.jpg" alt=""></p>
<h2 id="22-대규모-변경">22. 대규모 변경</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>LSC 프로세스는 되돌릴 수 없다고 여기던 기술적 결정들을 다시 생각하게 해줌</li>
<li>전통적인 리팩토링 모델은 코드 규모가 커지면 한계가 나타남</li>
<li>코드베이스를 오래 방치할 수록 고치기 힘들어지므로 꾸준히, 조금씩 개선 필요</li>
</ul>
<p>구글은 일찍이 코드베이스 전반을 전면적으로 건드리는 변경을 원자적으로 수행한다는 아이디어를 포기했습니다. 이번 장에서는 거대한 구글 코드베이스가 기반 인프라의 변경을 유연하게 받아들일 수 있도록 해준 사회적 기법과 기술적 기법을 이야기 합니다.</p>
<h3 id="1-대규모-변경이란">1. 대규모 변경이란?</h3>
<p>대규모 변경(Large-scale change, LSC)이란 논리적으로 연관되어 있으나 현실적인 한계 때문에 원자적으로 서브밋할 수 없는 변경들의 집합입니다. 예시는 다음과 같습니다.</p>
<ul>
<li>너무 많은 파일을 수정하여 한번에 커밋을 할수 없는 경우 </li>
<li>너무 커다란 변경으로 병합과정에서 충돌이 해결되지 않는 경우 </li>
<li>분산 레파지토리나 여러 레포지토리를 함께 사용하는 경우</li>
</ul>
<p>구글의 LSC는 거의 항상 자동화 도구를 이용해 생성합니다. LSC로 인해 생성되는 변경들은 대체로 다음과 같이 분류할 수 있습니다.</p>
<ul>
<li>코드베이스 전반을 훑는 분석 도구로 찾은 공통 안티패턴 청소</li>
<li>폐기 대상 API 호출 대체</li>
<li>(컴파일러 업그레이드 등) 저수준 인프라 개선사항 활성화</li>
<li>사용자들을 옛 시스템에서 새로운 시스템으로 마이그레이션</li>
</ul>
<p>구글에서 수행하는 LSC의 대다수는 기능은 거의 변경하지 않습니다. 주로 <strong>명확성, 최적화, 미래 호환성 개선</strong>이 목표입니다. </p>
<h3 id="2-누가-대규모-변경을-처리할까">2. 누가 대규모 변경을 처리할까?</h3>
<p>구글에서는 LSC의 상당 비중을 인프라팀들이 수행합니다. 왜 인프라팀일까요?
첫째, 하부 시스템을 구축하고 관리하는 인프라팀들은 그 시스템을 활용하는 수만 개의 참조를 수정하는 데 필요한 도메인 지식 역시 갖추고 있습니다. 
둘째, 변경에 대한 의지가 높은 집단(주로 인프라팀과 같은)이 맡는 것이 효율적입니다. 조직 전체의 관점에서 이득이 있는 대규모 변경을 개별 개발자에게 합당한 보상 없이 부탁한다면 좋아할 사람은 없을 것이므로 조직 차원에서 비용을 부담하는 것이 맞습니다. 
셋째, 대규모로 변경해야 할 시스템을 소유한 팀이 주도해야 변경을 완료하는 데 유리합니다. </p>
<h3 id="3-원자적-변경을-방해하는-요인">3. 원자적 변경을 방해하는 요인</h3>
<p>LSC 프로세스를 설명하기 전에 왜 수많은 변경들이 원자적으로 커밋될 수 없는지를 이해해봅시다. </p>
<ol>
<li><p>기술적 한계
대부분의 버전관리 시스템(Version Control System, VCS)에서는 기능을 수행하는 비용이 변경의 크기에 비례해 커집니다. 파일 수천개를 원자적으로 커밋하기엔 메모리나 프로세싱 능력이 부족할 수 있습니다.</p>
</li>
<li><p>병합 충돌
병합 시 충돌이 생길 가능성이 커집니다. 버전 관리 시스템이 제공해주는 기능으로도 커버가 불가능한 경우가 많으며, 변경하는 동안 다른 사람들의 작업을 중단시킵니다.</p>
</li>
<li><p>유령의 묘지
유령의 묘지(haunted graveyard)란 너무 오래되고 둔하고 복잡해서 아무도 손대려 하지 않는 시스템을 뜻합니다. 유령의 묘지를 잘못 수정할 경우 많은 파급효과가 발생합니다. 이런 시스템에 대한 해결 방법은 충실한 테스트가 가장 효과적이며, 꾸준한 테스트는 시스템의 코드 베이스를 지속적으로 개선할 수 있는 동기를 줍니다.</p>
</li>
<li><p>이질성
LCS가 가능하려면 사람이 아닌 컴퓨터가 처리해줘야 합니다. 하지만 컴퓨터는 사람과 달리 모호한 일은 잘 처리하지 못합니다. 때문에 시스템 환경이 일관되어야 하며, 개발 조직의 도구와 스타일 가이드를 단순화해야 합니다. 구글 프리서브밋 검사는 복잡성을 높이지만 일관성 유지를 위해 복잡성을 희생한 좋은 예입니다. 다만 LSC로 인한 테스트 때는 팀 특화 검사를 생략하도록 조언합니다.</p>
</li>
<li><p>테스트
모든 변경에 대해서는 테스트가 수행되어야 하며, 직접 또는 간접 영향을 받는 코드들은 모두 테스트가 수행될 수 있도록 진행해야 합니다. 변경을 작은 단위로 수행하면 테스트의 횟수와 시간은 많이 늘어나지만 큰 변경의 테스트를 한번에 많이 실행할 수 있습니다. 실패를 추적하는 시간보다 소규모 변경을 자주 테스트 하는 것이 더 효율적입니다.</p>
</li>
<li><p>코드리뷰
모든 변경은 테스트와 함께 리뷰도 거쳐야 합니다. LSC도 예외는 아닙니다. 하지만 거대한 커밋의 검토는 지루하고 번거로우며 오류가 스며들 확률이 높습니다. 이러한 변경을 별도의 조각(shard)으로 나누면 좀 더 쉽게 리뷰할 수 있습니다. </p>
</li>
</ol>
<blockquote>
<p><strong>[사례 연구: 대규모 변경 테스트하기]</strong>
오늘날 구글에는 변경의 10~20%가 LSC 때문인 프로젝트가 흔합니다. 많은 양의 코드가 프로젝트의 전담 인력이 아닌 사람들에 의해 변경된다는 뜻입니다. LSC를 테스트 하는 것은 느리고 힘듭니다. 구글은 속도를 높이기 위해 TAP 열차라는 테스트 자동화 플랫폼(Test Automation Platform) 전략을 활용합니다.
LSC들은 서로 상당히 독립적이며, 영향을 받는 테스트 대다수가 대부분의 LSC에서 문제없이 성공합니다. TAP 열차가 유용한 것은 다음의 두 요인 덕입니다.</p>
</blockquote>
<pre><code>-LSC 대부분은 순수한 리팩토링이라서 주제 범위가 매우 좁고 코드의 원래 의미가 변하지 않음
-LSC를 구성하는 개별 변경은 단순하고 면밀히 검토해 진행하므로 잘못될 가능성이 크지 않음</code></pre><p>TAP 열차는 다음의 다섯 단계로 진행되며, 3시간마다 수행됩니다.</p>
<pre><code>1) 변경에 대해 무작위로 선택한 테스트 1000개 수행
2) 1000개의 테스트를 통과한 변경 중 대표 변경을 하나 선택 (= Train)
3) 변경들에 직접 영향받는 테스트를 모두 실행 
   일정 이상 큰 혹은 저수준의 LSC인 경우, 구글 레포지터리의 모든 테스트가 실행됨
   때문에 시간 소요가 큼
4) 불규칙하지 않으면서 실패한 테스트만 추려 개별 변경에 대해 독립적으로 다시 수행
   train에 올라탄 변경 중 어느것이 실패의 원흉인지 파악
5) TAP이 train에 탑승한 각 변경에 대한 보고서를 생성
   보고서에는 성공한 개상과 실패한 대상 모두 포함
   이는 LSC가 서브밋 여부를 판단하는 근거로 활용</code></pre><h3 id="4-대규모-변경-인프라">4. 대규모 변경 인프라</h3>
<p>구글은 LSC를 가능케 하기 위해 인프라에 막대한 투자를 했습니다. 이 인프라에는 변경 생성, 변경 관리, 변경 리뷰, 테스트 도구 등이 포함됩니다. 하지만 도구보다 중요한 것은 대규모 변경과 이를 감독하는 프로세스를 둘러싼 문화적 규범의 진화입니다.</p>
<ol>
<li><p>정책과 문화
LSC를 만들려는 팀과 개인을 위한 가벼운 승인 프로세스를 고안했습니다. 이는 다양한 언어의 미묘한 특성에 익숙한 숙련된 엔지니어 그룹이 감독하며, 새로 만들려는 LSC 관련 도메인 전문가도 참여합니다. 이 정책과 관련해 코드 소유자가 담당 소프트웨어에 대한 책임감을 갖는 것도 중요하지만, LSC가 구글의 소프트웨어 엔지니어링 관행을 확장하는데 중요한 축임도 이해해야 합니다. 또한 LSC에 거부권을 행사할 수 없다는 사실도 받아들여야 합니다.</p>
</li>
<li><p>코드베이스 인사이트
LSC를 진행하려면 코드베이스 전반을 분석할 수 있어야 합니다. 또한 리포지터리가 커져도 사람이 개입하는 시간은 크게 달라지지 않아야 합니다. 그리고 변경 생성 도구가 코드베이스 전반을 포괄해 다룰 수 있어야 합니다.</p>
</li>
<li><p>변경 관리
마스터 변경을 여러개의 shard로 나눈 후 테스트, 메일링, 리뷰, 커밋 단계로 관리해주는 도구가 가장 중요합니다. 구글은 Rosie라는 도구를 사용합니다.</p>
</li>
<li><p>테스트
LSC 테스트는 마스터 변경이 문제를 일으키지 않음을 확인하는 일 외에, 개별 샤드를 안전하고 독립적으로 서브밋할 수 있는지 까지 검증해야 합니다. </p>
</li>
<li><p>언어 지원
구글은 LSC를 주로 언어별로 진행합니다. 정적 타입 언어가 동적 타입 언어보다 훨씬 유리합니다. 자동 포맷터도 중요한 역할을 담당하고 있습니다.</p>
</li>
</ol>
<h3 id="5-대규모-변경-프로세스">5. 대규모 변경 프로세스</h3>
<p>LSC 프로세스는 크게 다음의 네 단계로 이루어지며, 각 단계의 경계는 매우 모호합니다.</p>
<ol>
<li>권한 부여
LSC 제안 문서를 프로세스 감독자 10여 명으로 구성된 위원회에 제안을 송부합니다. 위원회는 논의 후 어떻게 진행할지 피드백한 후, 대다수의 기계적인 LSC는 해당 변경의 본질과 필요한 필드 자동화를 깊이 이해하는 <strong>전문가 한 명</strong>에게 맡깁니다.
```
LSC 작성자에게 다음의 내용을 포함한 간단한 제안 문서 작성을 요청합니다.</li>
</ol>
<ul>
<li>변경을 제안하는 이유</li>
<li>코드베이스 전반에 주는 예상 영향</li>
<li>리뷰어들이 던질만한 질문과 그에 대한 답변<pre><code></code></pre></li>
</ul>
<ol start="2">
<li><p>변경 생성
변경 생성 프로세스는 가능한 자동화해야 합니다. 이전 방식의 코드로 되돌아가거나 변경된 코드에서 병합 충돌이 발생했을 때 상위 변경을 업데이트해야하기 때문입니다.</p>
</li>
<li><p>샤드 관리
Rosie를 실행합니다. Rosie는 거대한 변경을 하나 입력받아서 서브밋할 수 있는 작은 변경(shard)들로 쪼개줍니다. 이때 프로젝트 경계와 소유권 규칙을 참고합니다. 이후 shard는 독립된 테스트-메일-서브밋 파이프라인을 거치게 됩니다. </p>
</li>
<li><p>마무리 청소
가장 중요한 부분은 폐기 대상인 코드를 사용하지 못하도록 하는 장치입니다. 구글은 Tricorder 프레임워크를 사용합니다. Tricorder는 누군가 폐기 대상 객체를 사용하는 코드를 새로 작성하면 코드 리뷰 때 알려줘서 변경을 역행하지 않도록 막아줍니다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[09. 코드 리뷰]]></title>
            <link>https://velog.io/@hyeonz_kang/09.-%EC%BD%94%EB%93%9C-%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@hyeonz_kang/09.-%EC%BD%94%EB%93%9C-%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Tue, 20 Dec 2022 12:43:46 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/a5eefaac-695c-4934-b56a-32cb35f2f2eb/image.jpg" alt=""></p>
<h2 id="09-코드-리뷰">09. 코드 리뷰</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>코드 리뷰의 이점이 많음 - 정확성, 이해 용이성, 일관성 보장 등</li>
<li>코드 리뷰는 조직의 지식 공유에 기여함</li>
<li>코드 리뷰 프로세스 확장을 위해서는 자동화가 중요</li>
<li>코드 리뷰 자체가 변경 이력임</li>
<li>모범사례가 엄격히 지켜져야 개발자의 만족도와 생산성이 유지됨</li>
</ul>
<p>이번 장에서는 코드 리뷰 프로세스에 대해 이야기합니다. 코드 리뷰란 <strong>작성자 이외의 사람이 코드를 검토하는 프로세스</strong>로, 주로 <strong>코드를 코드베이스에 반영하기 전에 수행</strong>합니다. &#39;버그가 코드베이스로 침투하기 전에 잡아낸다&#39;라는 이점 외에도 다양한 코드 리뷰의 장점을 확인하고, 필요성에 대해 이해합시다.</p>
<h3 id="1-코드-리뷰-흐름">1. 코드 리뷰 흐름</h3>
<p>코드 리뷰는 SW 개발 단계 어느 곳에서나 가능합니다. 구글은 변경을 코드베이스에 커밋하기 이전에 수행합니다. 이를 <strong>precommit review</strong>라고 합니다. <strong>코드 리뷰의 최종 목표는 다른 엔지니어로부터 해당 변경을 적용해도 된다는 합의를 이끌어내는 것</strong>입니다. 구글에서는 이를 LGTM 이라는 태그를 달아 표현합니다.</p>
<blockquote>
<p><strong>LGTM (Looks Good to me)</strong>
to me: 각자가 자신이 맡은 영역에만 한정해서 리뷰한다는 의미
looks good: 코드의 완벽한 품질보다는 개선을 중시하는 구글의 문화에서 비롯된 것
즉, 코드가 완벽하지 않더라도 전체적인 품질을 높이는 상태에 도달했다면 승인하는 방향 지향</p>
</blockquote>
<p><strong>구글의 코드 리뷰 절차</strong></p>
<ul>
<li><p>작성자가 변경사항을 작성한 후 스냅샷을 생성합니다. 스냅샷이란 코드 리뷰 도구에 업로드할 코드 패치와 관련된 설명입니다. </p>
</li>
<li><p>한 명 이상에게 리뷰를 요청합니다.</p>
</li>
<li><p>리뷰어들은 diff에 댓글로 의견을 남깁니다. (수정 사항, 유용한 정보 등)</p>
</li>
<li><p>작성자는 피드백을 기초로 변경을 수정하고 새로운 스냅샷을 업로드해 리뷰어들에게 회신합니다.</p>
</li>
<li><p>리뷰어들이 변경 내용에 모두 만족하면 LGTM 태그를 달아줍니다. 보통은 모든 리뷰어가 LGTM을 달아주는 것이 관례지만 원칙적으로는 한 개만 얻어도 됩니다.</p>
</li>
<li><p>모든 댓글에 LGTM이 달려 변경이 승인 되면 작성자는 커밋할 수 있습니다.</p>
</li>
</ul>
<h3 id="2-코드-리뷰--구글">2. 코드 리뷰 @ 구글</h3>
<p>구글에서는 어떤 변경이든 &#39;승인&#39;을 얻으려면 세 가지 측면의 리뷰를 통과해야 합니다.</p>
<ul>
<li><p><strong>정확성(correctness)과 이해 용이성(comprehension) 평가</strong>
필수는 아니며, 팀원이 해주는 경우가 많음.</p>
</li>
<li><p><strong>코드 영역을 관리하는 코드 소유자로부터의 승인</strong>
작성자가 코드 소유자라면 자동으로 승인됨. 구글의 코드베이스는 트리 구조이며, 디렉토리별 소유자들이 계층적으로 할당되어 있음. 소유자는 테크 리드나 해당 영역의 기술 전문가가 맡음. 코드베이스에 변경을 반영하려면 해당 디렉토리 소유자의 승인이 반드시 필요. </p>
</li>
<li><p><strong>가독성 승인</strong>
해당 언어 가독성 인증자가 승인하며, 작성자가 가독성 인증자라면 자동으로 승인됨.</p>
</li>
</ul>
<p>과해보이지만 대부분의 리뷰는 세 역할을 모두 수행할 수 있는 한 명이 처리하므로 빠르게 진행됩니다. 세 가지 승인 조건은 어떤 형태로 조합되든 상관 없습니다. 
만약 승인을 두 개 이상 얻어야 하는 코드 리뷰는 대부분 동료로 부터 LGTM을 받은 후, 해당 코드 소유자와 가독성 인증자에게 승인을 요청합니다. 이를 통해 두 역할의 사람들이 각기 다른 측면에 집중해 리뷰하도록 해줘 시간을 절약해 줍니다. 또한 승인 측면을 셋으로 나눔으로써 코드 리뷰 프로세스가 더 유연해져 확장성이 생깁니다.</p>
<blockquote>
<p><strong>소유권</strong>
구글에서는 리포지터리의 지식과 책임을 소유권(Ownership)이라 하고, 소유권을 행사하는 사람을 소유자(Owner)라고 합니다. 회사가 추구하는 가치가 지켜지도록 관리한다는 의미의 소유입니다. 리포지터리에는 OWNERS 파일을 담고 있는 디렉토리들이 있고, 해당 파일엔 디렉토리별 소유자 이름이 나열되어 있습니다. 
코드 소유권으로 코드 커밋을 승인해줄 사람을 알릴 수 있습니다. 소유자는 대규모 변경을 책임지는 전역 승인자 역할을 맡을 수도 있습니다. 또한 OWNERS 파일을 통해 사람이나 도구가 책임자를 찾기 쉬워집니다.</p>
</blockquote>
<h3 id="3-코드-리뷰의-이점">3. 코드 리뷰의 이점</h3>
<p>구글은 아무리 작더라도 코드베이스를 수정하는 거의 모든 변경에 코드 리뷰를 요구합니다. 이런 강제적인 규제는 비용을 유발하고 엔지니어링 속도에도 영향을 줍니다. 하지만 다음과 같은 이점 때문에 장기적으로 봤을 때는 더 효율적입니다.</p>
<ul>
<li><p><strong>코드 정확성</strong>
변경된 코드의 정확성을 확인할 수 있고 소프트웨어 버그를 예방하는 효과가 있습니다. 이때 코드 리뷰 프로세스 자체는 단순화하여 가볍게 유지해야 합니다. 정확성 평가가 객관적이기 위해 변경자의 방식을 존중해야 합니다. 리뷰어는 자신이 선호한다는 이유로 다른 안을 주장해서는 안됩니다. 덜 복잡하거나 더 효율적인 대안이 있을 경우에만 제시할 수 있습니다. 코드 리뷰는 만능 치트기도 아니고, 정확성 검사의 유일한 수단도 아니므로 완벽할 필요는 없습니다. </p>
</li>
<li><p><strong>코드 이해 용이성</strong>
타인으로 부터 작성자의 관점에 치우치지 않은 피드백을 받을 수 있는 기회입니다.</p>
</li>
<li><p><strong>코드 일관성</strong>
규모가 커질수록 코드는 읽히는 시간이 더 길며, 다른 사람이 유지보수 하게 될 것입니다. 따라서 리뷰를 통해 코드가 건실함(health)을 보장해야 합니다. LGTM을 받은 상태와 가독성 승인을 분리한 이유는 유지보수성 때문입니다. 코드가 일관되고 단순할 수록 사람들이 쉽게 이해하고 리팩토링하기도 편리해집니다. </p>
</li>
<li><p><strong>심리적/문화적 이점</strong>
코드는 &#39;자신의 것&#39;이 아니라 협업을 통해 만들어지는 &#39;조직의 공동 소유물&#39;임을 인식시켜주는 효과가 있습니다. 다른 사람의 피드백을 받고, 더 큰 이익을 위해 적절히 타협할 수 있도록 합니다. 비판적 피드백도 코드 리뷰를 통해 기분 좋게 받아들일 수 있습니다. 또한 타인으로부터 검증을 받음으로써 좋은 코드라고 인정해주는 효과가 있습니다. 마지막으로 코드 리뷰를 위해 자신의 코드를 다시 확인하게 하여 더 완벽한 코드를 작성하도록 돕습니다.</p>
</li>
<li><p><strong>지식공유</strong>
코드 리뷰는 지식 공유의 기회입니다. 리뷰어는 FYI(For Your Information)라는 주석으로 프로세스 제안, 신기술 소개, 조언 등을 통해 도메인 지식을 전파합니다. 피드백을 주고 받으며 정보가 교환되고 지식 공유를 촉진시킵니다. </p>
</li>
</ul>
<h3 id="4-코드-리뷰-모범-사례">4. 코드 리뷰 모범 사례</h3>
<ul>
<li><p><strong>공손하고 전문가 답게</strong>
작성자가 다른 대안 중 특별히 더 우수한게 없음을 설명할 수 있다면 리뷰어들은 작성자의 취향을 받아들여야 합니다. 작성자가 선택한 방식에서 결함을 찾게 되면 (작성자와 리뷰어 모두)배움의 기회로 생각하면 됩니다.
리뷰어는 신속하게 피드백해야 합니다. 작성자는 피드백에 감정적으로 대응해서는 안되며, 리뷰어가 단 댓글은 모두 TODO로 취급해야 합니다. 댓글을 의문 없이 수용할 필요는 없지만, 동의하지 않는 다면 리뷰어에게 그 이유를 설명해야 합니다.</p>
</li>
<li><p><strong>작게 변경하기</strong>
변경을 가능한 작게 만들어야 합니다. 작은 변경이란 약 200줄 이하의 코드를 뜻합니다. 코드 리뷰를 작게 해야 확장성을 유지할 수 있습니다. 또한 롤백에도 용이하며, 빠른 리뷰를 할 수 있습니다.</p>
</li>
<li><p><strong>변경 설명 잘 쓰기</strong>
변경 설명의 첫 줄은 어떤 종류의 변경인지를 잘 요약해야 합니다. 구체적으로 무엇을 왜 변경하는지도 작성해야 합니다. 연관된 수정 여러 개를 포함했다면 그 모두를 간략하게 열거합니다. 코드 주석을 통해서도 자세히 설명할 수 있습니다.  </p>
</li>
<li><p><strong>리뷰어는 최소한으로</strong>
사공이 많으면 배가 산으로 갑니다. 첫 번째 LGTM이 가장 중요합니다.</p>
</li>
<li><p><strong>가능한 자동화하기</strong>
프로세스 중 자동화할 수 있는 요소가 있다면 자동화를 해야합니다. 이를 통해 더 효율적인 코드리뷰가 가능해집니다. </p>
</li>
</ul>
<h3 id="5-코드-리뷰-유형">5. 코드 리뷰 유형</h3>
<p>코드 리뷰 유형에 따라 리뷰 프로세스의 어느 측면에 더 집중해야 하는지가 달라집니다. 다음과 같은 네 가지 분류가 있으며 때로는 겹치기도 합니다.</p>
<ul>
<li><p><strong>그린필드 코드 리뷰와 새로운 기능 개발</strong>
Greenfield review는 완전히 새로운 코드를 대상으로 하는 가장 드문 유형의 코드 리뷰입니다. 코드는 부채(Debt)이므로 오래 존속될 수 있는지, 유지보수 하기 쉬운지 등을 확인해야 합니다. 코드 리뷰때는 이미 결정된 설계에 관해서는 얘기해서는 안되고, 단지 API가 합의된 설계에 부합하고 테스트가 완벽히 이뤄졌는지에 대해 확인해야 합니다. 주석도 충분해야 하고, 필요하다면 보충 문서도 제공해야 합니다.</p>
</li>
<li><p><strong>동작 변경, 개선, 최적화</strong>
꼭 필요한 변경인지, 코드베이스를 개선하는지를 살펴햐 합니다. 최적화를 할 경우에는 벤치마크 테스트를 준비하는 것이 좋습니다.</p>
</li>
<li><p><strong>버그 수정과 롤백</strong>
버그를 수정하면서 기능 변경 등 다른 문제까지 묶어서 처리해서는 안됩니다. 한편 테스트 코드 보강도 이뤄져야 합니다. 기존 테스트 케이스가 충분히 커버하지 못했기 때문에 버그가 새로 발견된 것입니다.</p>
</li>
<li><p><strong>리팩터링과 대규모 변경</strong>
기계에 의해 많은 변경이 일어날 수 있습니다. 이런 변경도 리뷰가 필요합니다. 하지만 이 때는 댓글 작성을 지양합니다. 또한 기반 도구나 변경을 생성한 LSC(대규모 변경) 자체에는 신경쓰지 말고 리뷰어 자신의 코드와 관련된 문제만 신경써야 합니다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[08. 스타일 가이드와 규칙]]></title>
            <link>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-08</link>
            <guid>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-08</guid>
            <pubDate>Wed, 14 Dec 2022 16:02:43 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/280be4cd-95d8-47dd-b782-6d104033db32/image.jpg" alt=""></p>
<h2 id="08-스타일-가이드와-규칙">08. 스타일 가이드와 규칙</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>규칙과 지침의 목표는 시간과 확장 관점에서의 탄력성을 높이는 것이어야 함</li>
<li>상황이 변하면 규칙도 바뀌어야 함</li>
<li>규칙의 변경을 위해 규칙이 만들어진 근거를 기록해야 함</li>
<li>핵심은 일관성</li>
<li>가능한 규칙들이 자동으로 적용되도록 해야 함</li>
</ul>
<p><strong>규칙(rule)</strong>은 코드 전반에서 따라야 하는 강제사항이며, 꼭 필요한 경우를 제외하고는 무시할 수 없습니다. <strong>지침(guidance)</strong>은 권장사항과 모범 사례를 뜻합니다. 구글에서는 프로그래밍 스타일 가이드로 정리해 표준으로 삼고 있습니다. 또한 구글은 스타일 가이드를 프로그래밍 언어별로 관리하며, 이를 통해 코드의 지속 가능성을 높입니다.</p>
<h3 id="1-규칙-만들기">1. 규칙 만들기</h3>
<p>좋은 것과 나쁜 것의 해석은 조직마다 차이가 있으므로 조직이 추구하는 가치를 확실히 해야합니다. 그런 다음 규칙을 만들면 엔지니어들은 코드를 표현하는 &#39;형식&#39;보다 &#39;내용&#39;에 집중할 수 있게 됩니다. 규칙을 정의할 때 반드시 던져야 하는 질문은 <strong>&quot;어떤 목표를 이루려 하지?&quot;</strong>입니다.</p>
<p>** [기본 원칙] ** </p>
<ul>
<li><p><strong>규칙의 양을 최소화</strong>
규칙이 많아지면 규칙 모음을 관리하기 어렵고 비용도 증가합니다. 그래서 너무 자명한 규칙은 의도적으로 배제합니다.</p>
</li>
<li><p><strong>코드를 읽는 사람에게 맞추기</strong>
코드 작성자보다는 읽는 사람에게 최적화해야합니다. 코드는 작성되는 횟수보다 읽히는 횟수가 더 많습니다. </p>
</li>
<li><p><strong>일관성 있는 규칙</strong>
코드베이스의 스타일과 기준이 일관되면 코드를 작성하는 엔지니어와 읽는 이들은 &#39;어떻게&#39; 표현하느냐가 아닌 &#39;무엇을&#39; 수행하느냐가 집중할 수 있습니다. 또한 일관성에 위계를 둬야합니다. 일관성을 위해서는 &#39;무엇&#39;을 선택했냐가 아니라 &#39;선택을 했다&#39;는 사실에 의의가 있습니다.</p>
<pre><code>[우선 순위]
단일 파일 &gt; 팀 &gt; 프로젝트 &gt; 전체 코드 베이스</code></pre></li>
<li><p><strong>오류가 발생하기 쉽거나 예상치 못한 동작을 유발하는 구조 피하기</strong>
예상과 다르게 동작할 여지가 있거나 정확한 동작을 예측하기 까다로운 구조는 사용하지 않도록 제한합니다. 예를 들어 구글은 python 스타일 가이드는 reflaction 등 몇 가지 고급 기능을 사용하지 못하게 제한합니다.</p>
</li>
<li><p><strong>꼭 필요하다면 실용성을 위해 예외를 허용하기</strong>
일관성은 중요하지만 융통성이 필요합니다.</p>
</li>
</ul>
<p>** [스타일 가이드] **</p>
<ul>
<li><p>위험을 피하기 위한 규칙</p>
</li>
<li><p>모범 사례를 적용하기 위한 규칙</p>
</li>
<li><p>일관성을 보장하기 위한 규칙</p>
</li>
</ul>
<h3 id="2-규칙-수정하기">2. 규칙 수정하기</h3>
<p>규칙은 고정불변이 아닙니다. 그러므로 각각의 결정을 뒷받침하는 근거를 명시해둬야 합니다. 장단점과 잠재적인 파장을 분석하고, 변경량이 규모에 무리가 없는지 검증하는 데 시간을 많이 써야합니다. 각 결정에 이른 근거를 문서로 남겨두면 규칙을 변경해야 할 때가 언제인지를 알 수 있습니다. &#39;문제&#39;는 잠재적인 가능성이 아니라 현존하는 코드에서 발견된 패턴으로 입증해야 합니다. </p>
<pre><code>스타일 가이드 수정 대부분은 커뮤니티의 토론에서 발생하곤 합니다.</code></pre><p>구글은 스타일 중재자(style arbiter)라는 언어별 소유자를 두고, 스타일 가이드에 대한 최종 결정과 승인을 책임집니다. 예외 상황도 스타일 중재자와 함께 논의하고 결정합니다. </p>
<h3 id="3-지침">3. 지침</h3>
<p>지침이란 구글 엔지니어링 경험에서 선별한 지혜이자 과거에서 배운 교훈들로부터 추린 모범 사례들을 문서로 남긴 것입니다. 사람들이 자주 실수하는 것 혹은 아직 익숙하지 않은 새로운 주제라서 혼란스러워하는 것들에 집중합니다. </p>
<blockquote>
<p>규칙(Rule)은 반드시(must) 지켜야 한다면, 지침(guidance)는 되도록(should) 따라야 하는 것</p>
</blockquote>
<h3 id="4-규칙-적용하기">4. 규칙 적용하기</h3>
<p>규칙을 적용할 때는 자동화 도구를 활용하는 것이 좋습니다. 도구를 활용할 경우 시간이 흐르거나 조직이 커져도 규칙이 누락되는 것을 방지할 수 있습니다. 또한 일관성있게 적용할 수 있습니다. 언어 사용법과 관련한 규칙들의 상당수는 정적 분석 도구로 강제할 수 있습니다. 물론 모든 규칙을 도구로 적용하는 것은 불가능할 수 있습니다. 때로는 사람이 판단해야만 하는 규칙도 있기 때문입니다.
구글은 코드의 형식을 일관되게 관리하기 위해 자동 스타일 검사기와 코드 포맷터를 적극 이용합니다. 그래서 presubmit 검사로 포맷터를 반드시 사용하게 합니다.</p>
<pre><code>[구글의 코드 포맷터]
c+ : clang-format
python : YAPF
Go : gofmt
Dart : dartfmt
BUILD 파일 : buildifier</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[03. 지식 공유]]></title>
            <link>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-03</link>
            <guid>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-03</guid>
            <pubDate>Mon, 12 Dec 2022 14:39:39 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/99434f89-c197-4e14-b1a8-a7165e90501a/image.jpg" alt=""></p>
<h2 id="03-지식-공유">03. 지식 공유</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>심리적 안전은 지식 공유 환경을 조성하기 위한 토대</li>
<li>전문가, 문서화된 자료로 부터 도움을 쉽게 얻을 수 있어야 함</li>
<li>자신의 전문 지식을 가르치고 전파하는 사람들에게 보상하는 체계적 제도 필요</li>
</ul>
<p>조직은 자신의 문제 대부분에 스스로 답할 수 있어야 합니다. 이번 장에서는 조직 내 질문의 답을 아는 <strong>전문가</strong>들과 <strong>지식을 전파할 메커니즘</strong>의 중요성을 이야기합니다. 메커니즘을 정착시키기 위해서는 조직에 <strong>배움의 문화</strong>와 모르는 것을 인정할 수 있도록 돕는 <strong>심리적 안정</strong>이 있어야 합니다.</p>
<h3 id="1-배움을-가로막는-장애물">1. 배움을 가로막는 장애물</h3>
<p><strong>심리적 안전 부족 (lack of psychological safety)</strong>
불이익이 두려워서 스스로 위험을 감수하거나 실수를 드러내기 꺼리는 환경을 뜻합니다.</p>
<p><strong>정보 섬 (information of island)</strong>
조직의 각 부서가 자원을 공유하지 않거나 소통의 부재로 지식이 파편화 되는 것을 뜻합니다. 각 부서가 일하는 방식을 제각기 만들어 내며, 다음과 같은 현상이 나타납니다.</p>
<ul>
<li>정보 파편화</li>
<li>정보 중복</li>
<li>정보 왜곡</li>
</ul>
<p><strong>단일 장애점 (single point of failure, SPOF)</strong>
중요한 정보를 한 사람이 독점하는 것입니다.</p>
<p><strong>전부 아니면 전무 전문성 (all-or-nothing expertise)</strong>
조직 구성원이 &#39;모든 것을 아는&#39; 사람과 &#39;아무것도 모르는&#39; 초심자로 나뉘는 현상입니다.</p>
<p><strong>앵무새처럼 흉내내기 (parroting)</strong>
이해하지 못한 상태로 흉내만 내는 것을 말합니다.</p>
<p><strong>유령의 묘지 (haunted graveyard)</strong>
무언가 잘못될 게 두려워서 아무도 손대지 않는 영역을 말합니다. (ex. 레거시 코드)</p>
<h3 id="2-철학">2. 철학</h3>
<p>소프트웨어 엔지니어링에서 가장 중요한 요소는 사람이며, 사람 사이에 1:1로 이루어지는 조언은 어떤 측면에서는 매우 효과적입니다. 하지만 확장성이 부족하여 팀이 커지면 비효율적입니다. 
한편, 문서화된 자료는 조직 전체로 퍼뜨릴 수 있습니다. 하지만 개별 학습자가 처한 특수 상황에는 부적합할 수 있습니다. 또한 가능한 최신 정보를 반영해야 하므로 유지보수 비용이 듭니다.
그러므로 <strong>전문가와 문서화된 자료는 둘 다 꼭 필요하며, 상호 보완적으로 사용해야 합니다.</strong></p>
<h3 id="3-심리적-안전">3. 심리적 안전</h3>
<p>배움에는 &#39;무언가를 시도하다가 실패해도 안전하다&#39;라는 인식이 중요합니다. 또한 항상 무언가 배울 게 있음을 인식하는 게 중요합니다. </p>
<p><strong>멘토제도</strong>
Noogler(구글에 새로 입사한 직원)에게 심리적 안전을 심어주기 위해 멘토 제도를 시행합니다. 멘토는 궁금한 점에 대답해주고 누글러의 성장을 돕습니다. 누글러가 속한 팀의 팀원이나 관리자, 테크리드는 멘토에서 제외됩니다. </p>
<p><strong>협조적 문화</strong>
안전하고 편안한 근무 환경을 조성하기 위해서는 적대적이지 않고 협조적으로 일하는 문화가 필요합니다. </p>
<h3 id="4-지식-확장하기">4. 지식 확장하기</h3>
<blockquote>
<p>항상 배우고 항상 질문하라!</p>
</blockquote>
<p><strong>내 지식 키우기</strong>
항상 무언가 배울게 있음을 인식하는 것이 중요합니다. 편안하게 질문할 수 있는 분위기와 끈기를 갖고 상냥하게 답변해주는 환경이 필요합니다. 또한 상급자라면 모든 것을 알아야 한다는 인식은 나쁩니다. </p>
<blockquote>
<p><strong>울타리 원칙 (Chesterson&#39;s fence)</strong>
무언가를 옮기거나 바꾸려면 그게 왜 그자리에 있는지부터 이해하자</p>
</blockquote>
<p><strong>커뮤니티에 묻기</strong>
1:1 도움은 밀도가 높지만 확장하는 데는 한계가 있습니다. 그래서 다음과 같은 커뮤니티를 통해 질문을 확장해야 합니다. 각각 장단점이 있으므로 적절히 섞어서 사용해야합니다. </p>
<ul>
<li>그룹 채팅
동시에 여러 사람한테 질문할 수 있고 빠르게 답변을 받을 수 있습니다. 간단한 질문에 적합합니다.</li>
<li>메일링 리스트
맥락 정보가 많이 필요한 복잡한 질문에 적합한 반면, 그룹 채팅처럼 빠르게 주고 받는 대화에는 취약합니다. </li>
<li>질의응답 플랫폼
YAQS(Yet Another Question System)는 구글 내부에서 사용하는 stack overflow와 유사한 플랫폼입니다. </li>
</ul>
<p><strong>누구나 가르칠 게 있다</strong></p>
<ul>
<li>office hours
누군가가 특정 주제에 관한 질문에 답해줄 목적으로 시간을 비워 둔 정기적인 이벤트입니다. 직접 대화를 해야지만 쉽게 풀리는 문제에 좋은 해결책입니다.</li>
<li>tech talk &amp; class<ul>
<li>자주 오해를 일으킬 정도로 복잡한 주제를 다뤄야 합니다.</li>
<li>주제가 비교적 안정적이어야 합니다. 수업 교재를 자주 고치는 것은 큰 일이기 때문입니다.</li>
<li>질문에 답해주고 1:1로 도와줄 수 있는 교사가 있어야 효과가 큰 주제여야 합니다. 자습할 수 있는 내용은 문서나 동영상이 더 효과적입니다.</li>
<li>수업을 정기적으로 개설해도 될 만큼 수요가 많아야 합니다.</li>
</ul>
</li>
<li>문서자료<ul>
<li>문서자료 갱신하기
처음 배울 때가 기존 문서자료에서 개선점을 찾기 가장 좋을 때입니다. 따라서 문서자료는 소유자 외에도 누구에게나 갱신 권한을 줘야합니다.</li>
<li>새로운 문서자료 작성하기</li>
<li>문서화 촉진하기
기여자와 수혜자가 달라서 적절한 보상 없이는 문서화를 장려하기 어렵습니다. 꼭 보상과 인정을 체계화 해줘야 합니다.</li>
</ul>
</li>
<li>코드
코드도 지식이라는 사실을 인지해야 합니다.</li>
</ul>
<h3 id="5-조직의-지식-확장하기">5. 조직의 지식 확장하기</h3>
<blockquote>
<p>높은 수준의 기술 리더십을 요구하지만, 모든 리더십이 기술 문제와 관련된 것은 아닙니다. 리더는 주변 사람들을 성장시키고, 팀의 심리적 안전을 개선하고, 팀워크와 협업 문화를 조성하고, 팀 내 긴장을 해소하고, 구글 문화의 가치를 설정하며, 구글을 더 활기차고 신나는 일터로 가꿔야 합니다. 괴짜는 좋은 리더가 아닙니다.
<strong><em>-구글의 SW 엔지니어링 직무사다리에서 리더십 항목 중-</em></strong></p>
</blockquote>
<p><strong>지식 공유와 문화 일구기</strong></p>
<ul>
<li>존중
지식을 공유할 때는 상냥함과 존중을 담아야합니다. </li>
<li>보상과 인정
좋은 문화는 적극적으로 육성해야하며 인정과 보상 제도가 뒷받침되어야 합니다.</li>
</ul>
<p><strong>표준 정보 소스 구축하기</strong>
표준 정보 소스는 회사 차원의 중앙집중적 정보 원천으로, 전문가의 지식을 표준화하고 전파하는 수단입니다. 표준 정보의 내용은 해당 분야 전문가들이 적극적으로 관리하고 감독해야 합니다. 또한 복잡한 주제일수록 소유자를 명확히 정해둬야합니다.</p>
<ul>
<li>개발자 가이드</li>
<li>go/ 링크
구글 내에서 쓰는 URL 단축 서비스입니다. 구글 내부의 참조 대부분의 하나 이상의 내부 go/ 링크를 갖고 있습니다. 덕분에 정보에 쉽게 접근할 수 있습니다.</li>
<li>codelab
구글 코드랩은 동작하는 예시 코드, 설명, 코딩 연습문제 등을 활용해 엔지니어에게 새로운 개념이나 프로세스를 가르치는 실습형 튜토리얼입니다.</li>
<li>정적 분석</li>
<li>뉴스레터</li>
<li>커뮤니티</li>
</ul>
<p><strong>가독성 제도: 코드 리뷰를 통한 표준 멘토 제도</strong>
가독성 제도는 단순한 코드 가독성을 넘어 프로그래밍 언어 모범 사례를 전파하기 위한 구글 전사 차원의 &#39;표준 멘토링 프로세스&#39;를 의미합니다. 언어 idiom, 코드 구조, API 설계, 공통 라이브러리의 올바른 사용법, 문서화, 테스트 커버리지 등 광범위하게 다룹니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[02. 팀워크 이끌어내기]]></title>
            <link>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-02</link>
            <guid>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-02</guid>
            <pubDate>Tue, 29 Nov 2022 14:26:38 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/8ea9953c-a9e9-461a-9c6c-1eb9a9adbf66/image.jpg" alt=""></p>
<h2 id="02-팀워크-이끌어내기">02. 팀워크 이끌어내기</h2>
<blockquote>
<h4 id="주요내용">주요내용</h4>
</blockquote>
<ul>
<li>사람은 완벽하지 않음</li>
<li>고립되어 일하면 초반에 문제를 인지할 수 없음</li>
<li>자신뿐만 아니라 다른 사람의 성향과 일하는 방식도 이해하고 존중해야 함</li>
</ul>
<p>이번 챕터에서는 구글에서 이루어지는 <strong>소프트웨어 엔지니어링의 문화적/사회적 측면</strong>에 대해 다룹니다. 소프트웨어 개발은 <strong>&#39;팀의 단합된 노력&#39;</strong>의 결실입니다. 인간은 완벽하지 않기 때문에 <strong>겸손, 존중, 신뢰</strong>라는 핵심 원칙에 맞게 행동해야 엔지니어링 팀이 성공할 수 있습니다.</p>
<h3 id="1-내-코드를-숨기고-싶어요">1. 내 코드를 숨기고 싶어요</h3>
<pre><code>다른 사람들이 아직 완성되지 않은 내 코드를 보는 건 진짜 진짜 겁이 나. 
그걸 진지하게 보고 내가 바보라고 생각할 것만 같아.</code></pre><p>많은 개발자들은 미완성인 자신의 코드를 누군가 보고 판단하는 것을 두려워합니다. 이는 프로그래머들이 느끼는 매우 일반적인 감정입니다. 다들 자신의 코드를 숨기고 완벽해질 때 까지 다듬은 후 세상에 알리고 싶어합니다.</p>
<p>리눅스 개발자 리누스, 파이썬 개발자 귀도 반 로섬, 빌 게이츠 등 개발자로서 우상으로 섬기는 사람을 떠올려 보세요. 이들은 모두 커뮤니티를 이끌어 엄청난 집단적 성과물을 이끌어 냈습니다. 마이클 조던 역시 혼자서 경기를 승리로 이끈 것은 아닙니다. 조던의 진정한 천재성은 그 팀과 협동하는 방식에 있습니다. 단지 <strong>천재 신화(The Genius Myth)는 팀이 이룬 성공을 단 한 사람(리더)에게 몰아주어 만들어지는 경향이 있습니다</strong>. 
우리는 천재가 아닙니다. 혼자서 위대한 무언가를 해내는 것보다는 협업을 통해 해내는 것이 훨씬 쉽습니다.  </p>
<h3 id="2-숨기는-건-해롭다">2. 숨기는 건 해롭다</h3>
<p>오롯이 홀로 일한다면 실패할 위험성을 불필요하게 키우고 자신의 성장 잠재력을 속이는 것입니다. 구글은 다음의 근거들을 바탕으로 코드를 숨겨가며 혼자 일하는 것을 심각한 문제라고 생각합니다. </p>
<p><strong>조기감지</strong></p>
<blockquote>
<p>일찍 실패하고, 빨리 실패하고, 자주 실패하라</p>
</blockquote>
<p>초기 설계에는 근본적인 실수가 스며 있기 쉽습니다. 피드백을 조기에 받을수록 위험이 크게 줄어듭니다. 혼자 일한다면 협업이 주는 이점도 얻지 못합니다. </p>
<p><strong>버스 지수</strong></p>
<blockquote>
<p><strong>버스 지수 (Bus Factor)</strong>
몇 명의 팀원이 버스에 치어서 일을 할 수 없게 될 때 프로젝트가 망하게 되는지를 나타내는 지수</p>
</blockquote>
<p>최소한 각 책임 영역 마다 2차 소유자(담당자)를 두고, 제대로 된 문서를 갖춰 둔다면 프로젝트의 미래를 보장하고 버스지수를 높이는 데 도움이 됩니다. 혼자 일한다면 버스 지수 외에 전반적인 진행 속도에도 해롭습니다. </p>
<p><strong>진척 속도</strong>
현재 Devops 철학은 &#39;가능한 일찍 피드백 하고, 가능한 일찍 테스트하고, 보안과 프로덕션 환경을 가능한 초기부터 고려한다&#39;라는 목표를 천명하고 있습니다. 팀 플레이를 할 경우 계획이나 설계 변경이 필요한 시점을 즉시 알려줄 피드백 루프를 마련할 수 있습니다. </p>
<pre><code>[사례 연구: 엔지니어와 사무실]
- 엔지니어들이 방해받지 않고 코드 작성에 몰두 할 수 있는 1인실이 좋을까? (X)
- 수십명의 사람이 함께 쓰는 오픈 오피스가 좋을까? (X)
둘 다 활발한 대화를 하기에 적합하지 않다. 
팀마다 4~8명 정도의 방을 사용하는 것이 자발적이고 활발한 대화를 이끌어 낼 수 있다.</code></pre><h3 id="3-결론-숨기지-말자">3. 결론: 숨기지 말자</h3>
<p>&#39;홀로 일하기&#39;는 &#39;함께 일하기&#39;보다 본질적으로 더 위험합니다. 다른 사람이 아이디어를 훔친다거나 여러분이 똑똑하지 않다고 생각하는 게 두렵더라도, 잘못된 일에 여러분의 천금 같은 시간을 낭비할 가능성을 더 걱정해야 합니다.</p>
<h3 id="4-모든-것은-팀에-달렸다">4. 모든 것은 팀에 달렸다</h3>
<p>소프트웨어 엔지니어링은 팀의 단합된 노력입니다. 그러므로 가능한 고기능 팀을 경험하는 것을 목표로 삼아야 합니다. 또한 사회적 관계의 힘을 과소평가하지 마세요. 일이 진행되도록 관계를 형성해야 합니다.</p>
<p><strong>겸손(Humility)</strong>
당신과 당신의 코드는 우주의 중심이 아닙니다. 당신은 모든 것을 알지도, 완벽하지도 않습니다. 겸손한 사람은 배움에 열려 있습니다.</p>
<p><strong>존중(Respect)</strong>
함께 일하는 동료를 진심으로 생각합니다. 친절하게 대하고 그들의 능력과 성취에 감사해야 합니다.</p>
<p><strong>신뢰(Trust)</strong>
동료들이 유능하고 올바른 일을 하리라 믿습니다. 필요하면 그들에게 스스로 방향을 정하게 해도 좋습니다.</p>
<h3 id="5-겸손-존중-신뢰-실천하기">5. 겸손, 존중, 신뢰 실천하기</h3>
<p><strong>자존심 버리기</strong>
자기가 가장 현명하다고 확신하더라도 그런 속내를 겉으로 드러내서는 안됩니다. 모든 것을 다 아는 듯 행동하면 안됩니다. 집단적 자존심을 찾아야합니다. 자신일 잘 아는 분야에 대해 걱정하는 대신 팀의 성취와 단체의 자부심을 높이려 노력해야 합니다.</p>
<p><strong>비평하고 비평받는 법 배우기</strong>
건설적으로 비판하는 사람은 상대방을 진심으로 생각하고 상대방의 업무가 개선되길 바라야 합니다. 그리고 동료를 존중하는 법을 배우고 건설적이고 공손하게 비평하는 법을 배워야 합니다. 또한 스스로도 비평을 잘 수용할 줄 알아야 합니다. 우리 자존감을 우리가 작성한 코드(혹은 이외의 창작물)와 동일시해서는 안됩니다. </p>
<pre><code>Bad :-(
- &#39;~ 했어야 해요&#39; 라고 말해서는 안됨
- &#39;~가 잘못했어요&#39; 라고 말해서는 안됨
- &#39;~를 고치세요&#39; 라고 요구해서는 안됨
- 다른 사람과 다르게 했다고 비난하면 안됨
Good :-)
- 상대가 틀린게 아니라 자신이 코드를 이해하는 데 문제를 겪고 있는 것이라고 말하기
- 개선 방안 제안하기
- 요구하지 않고 제안을 거부해도 부담을 느끼지 않도록 배려하기
- 누군가의 가치나 코딩 기술이 아니라 코드 자체에 집중하기</code></pre><p><strong>빠르게 실패하고 반복하기</strong>
실패를 &#39;배우고 다음 단계로 넘어갈 수 있는 절호의 기회&#39;라고 생각합시다.</p>
<pre><code>[사례 연구: Google X]
자율 주행 자동차 등 급진적인 신기술을 연구하는 구글X 사업부에서는 실패를 보상 제도에 녹였다.
사람들은 엉뚱한 아이디어를 내놓고 동료들에게 가능한 빠르게 그 아이디어를 파쇄하라고 장려한다.
연구원들은 정해진 기간 동안 얼마나 많은 아이디어를 반증하고 무력화하는지에 따라 보상을 받고 서로 경쟁한다.
그리고 잘못된 아이디어임을 증명할 수 있는 동료가 하나도 없는 경우에만 초기 프로토타이핑 단계로 넘어갈 수 있다.</code></pre><h3 id="6-postmortem-문화">6. Postmortem 문화</h3>
<p>실패한 근본 원인을 분석해 문서로 남기는 것이 실수로부터 배우는 핵심입니다. 이것을 포스트모템이라고 합니다. 제대로 된 포스트모템에는 무엇을 배웠는지와 배운 것을 토대로 앞으로 무엇을 바꿀지가 담겨야 합니다.</p>
<blockquote>
<p><strong>포스트모템의 내용</strong></p>
</blockquote>
<ul>
<li>사건의 개요</li>
<li>사건을 인지하고 해결에 이르기까지의 타임라인</li>
<li>사건의 근본 원인</li>
<li>영향과 피해 평가</li>
<li>문제를 즉시 해결하기 위한 조치 항목 (소유자 명시)</li>
<li>재발 방지를 위한 조치 항목</li>
<li>해당 경험에서 얻은 교훈</li>
</ul>
<p><strong>Googleyness (구글다움)</strong></p>
<ul>
<li><strong>모호함을 뚫고 번창한다</strong>
끊임 없이 변화하는 환경 속에서도 상충하는 메시지와 방향에 잘 대처하고, 합의를 이끌어내고, 문제에 대한 진전을 이룰 수 있다.</li>
<li><strong>피드백을 소중히 한다</strong>
피드백을 주고 받을 때 품위와 겸손을 유지하고 개인과 팀의 발전에 피드백이 주는 가치를 이해한다.</li>
<li><strong>저항(항상성)을 극복한다</strong>
다른 이들이 저항하거나 관성 때문에 움직이지 않으려 하더라도 야심찬 목표를 세우고 밀고 나간다.</li>
<li><strong>사용자를 우선한다</strong>
구글 제품의 사용자 입장에서 생각하고 존중하며 그들에게 가장 도움되는 행동을 추구한다.</li>
<li><strong>팀에 관심을 기울인다</strong>
동료들의 입장에서 생각하고 존중하며 팀의 결집을 위해 누가 시키지 않더라도 적극적으로 돕는다.</li>
<li><strong>옳은 일을 한다</strong>
모든 일에 강한 윤리 의식을 갖고 임한다. 팀과 제품의 진정성을 지키기 위해서라면 어렵거나 불편한 결정을 내릴 수 있어야 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Load Balancer]]></title>
            <link>https://velog.io/@hyeonz_kang/Load-Balancer</link>
            <guid>https://velog.io/@hyeonz_kang/Load-Balancer</guid>
            <pubDate>Mon, 21 Nov 2022 17:08:55 GMT</pubDate>
            <description><![CDATA[<h3 id="load-balancer">Load Balancer</h3>
<p><strong>등장 배경</strong>
Client가 한 두명인 경우 Server 한 대로도 여유롭게 응답할 수 있다. 만약 사용자가 수십만명 이라면 어떻게 될까? 한 대의 서버로는 요청을 다 처리할 수 없을 것이다. 
요청을 해결하려면 어떻게 할까?</p>
<ul>
<li><strong>scale-up</strong>: Server가 더 빠르게 동작하기 위해 사양을 올리는 방법</li>
<li><strong>scale-out</strong>: Server의 개수를 늘리는 방법</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/b3aabf56-9340-4fdf-b8f9-caa9b415bb7e/image.png" alt="https://tecoble.techcourse.co.kr/post/2021-10-12-scale-up-scale-out/"></p>
<p>** 로드 밸런서란? **
요청 트래픽이 많을 때, <span style="color:Salmon"><strong>여러 대의 서버로 scale-out하고 요청을 골고루 분산처리하여 서버의 로드율 증가, 부하량, 속도 저하 등을 해결하기 위해</strong></span> 로드 밸런서가 등장했다.</p>
<h3 id="load-balancer의-역할">Load Balancer의 역할</h3>
<ul>
<li>요청 분산<ul>
<li>전송된 요청을 여러 웹 서버에 균등하게 분산하는 것</li>
</ul>
</li>
<li>SSL 처리<ul>
<li>송수신 하는 데이터를 암호화 하는 SSL(https 통신에서 사용) 처리</li>
<li>데이터 암호화/복호화 처리는 복잡한 계산을 수행해야 하므로 웹 서버에서 할 경우 부담이 많이 발생</li>
<li>로드 밸런서에서 담당하여 성능 향상의 효과</li>
</ul>
</li>
<li>부정 요청 대응<ul>
<li>부정한 접근을 감지하는 처리를 웹 서버에서 할 경우 부담이 많이 발생, 서버 탈취 위험</li>
<li>로드 밸런서에서 담당하여 성능 향상의 효과</li>
<li>웹 서버별로 대책 수립하는 것보다 효율적</li>
</ul>
</li>
</ul>
<h3 id="load-balancing-algorithm">Load Balancing Algorithm</h3>
<p><strong>Round Robin</strong>
서버에 들어온 요청을 순서대로 돌아가며 배정하는 방식
서버와의 연결이 오래 지속되지 않을 경우 적합</p>
<p><strong>가중 Round Robin</strong>
각 서버에 가중치를 매기고 가중치가 높은 서버에 요청을 우선적으로 배정하는 방식
서버의 트래픽 처리 능력이 다를 경우 사용</p>
<p><strong>최소 연결 방식 (Least Connection Method)</strong>
요청이 들어온 시점에 가장 적은 연결 상태를 보이는 서버에 트래픽을 배정하는 방식
서버에 들어온 트래픽들이 일정하지 않은 경우에 적합</p>
<p><strong>IP Hash 방식</strong>
클라이언트의 IP 주소를 특정 서버로 매핑하여 요청을 처리하는 방식
사용자가 항상 동일한 서버로 연결됨</p>
<p><strong>최소 응답 시간 방식 (Least Response Time Method)</strong>
가장 적은 연결 상태와 가장 짧은 응답 시간을 보이는 서버에 우선적으로 배정</p>
<p><strong>쿠키 지속성 (Persistence with Cookies)</strong>
쿠키 정보를 바탕으로 클라이언트가 연결했었던 서버에 계속 할당</p>
<p><strong>Context Switching</strong>
클라이언트가 요청한 특정 리소스에 따라 특정 서버로 연결
ex) 이미지 파일에 대해서 확장자를 참조해 별도로 구성된 이미지 파일이 있는 서버 또는 스토리지에 직접 연결</p>
<p><strong>URL Switching</strong>
특정 하위 URL들은 특정 서버로 처리</p>
<h3 id="load-balancer의-기본-기능">Load Balancer의 기본 기능</h3>
<ul>
<li>Health Check<ul>
<li>서버들에 대한 주기적인 health check를 통해 서버들의 장애 여부를 판단</li>
<li>덕분에 fail-over가 가능</li>
<li>TCP/UDP 분석이 가능해 Firewall의 역할도 수행 가능
```</li>
<li>L3: ICMP를 이용해 서버의 IP 주소가 통신 가능한 상태인지 확인</li>
<li>L4: TCP의 경우 3way-handshaking 특성을 기반으로 포트 상태 체크</li>
<li>L7: 실제 웹 페이지에 통신 시도해 이상 유무 파악
```</li>
</ul>
</li>
<li>Tunneling<ul>
<li>눈에 보이지 않는 통로를 만들어 통신 할 수 있게 하는 개념</li>
<li>클라이언트와 서버 간 터널링을 제공해 연결된 상호간에만 캡슐화된 패킷을 구별해 캡슐화를 해제 하도록 함</li>
</ul>
</li>
<li>NAT (Network Address Translation)<ul>
<li>IP주소를 변환해 주는 기능 (사설IP → 공인IP / 공인IP → 사설IP)</li>
<li>부족한 공인 IP주소를 효율적으로 사용 가능</li>
<li>여러개의 호스트가 하나의 공인 IP주소를 통해 접속</li>
</ul>
</li>
<li>DSR (Direct Server Routing)<ul>
<li>server → client 의 경우, 목적지를 클라이언트로 설정한 다음 네트워크 장비나 로드 밸런서를 거치지 않고 바로 클라이언트를 찾아가는 방식</li>
<li>로드 밸런서의 부하를 줄일 수 있음</li>
</ul>
</li>
</ul>
<h3 id="load-balancing의-종류">Load Balancing의 종류</h3>
<ul>
<li>L2<ul>
<li>Mac주소를 바탕으로 Load Balancing</li>
</ul>
</li>
<li>L3<ul>
<li>IP주소를 바탕으로 Load balancing</li>
</ul>
</li>
<li>L4<ul>
<li>Transport 계층(전송 계층) 에서 Load Balancing</li>
<li>IP와 Port 부하 분산</li>
<li>데이터를 변경/수정 할 수 없음</li>
<li>패킷 레벨에서만 트래픽을 분산하기 때문에 속도가 빠르고 효율이 높음</li>
<li>섬세한 라우팅이 불가능하지만 L7로드 밸런서보다 가격이 저렴</li>
<li>TCP, UDP</li>
</ul>
</li>
<li>L7<ul>
<li>Application 계층(응용 계층) 에서 Load Balancing</li>
<li>URL 또는 HTTP 헤더에서 부하 분산</li>
<li>포트나 헤더등의 정보를 수정 할 수 있음</li>
<li>패킷 내용을 확인하고 그 내용에 따라 트래픽을 특정 서버에 분산하는 것이 가능</li>
<li>섬세한 라우팅이 가능하고, 비정상적인 트래픽을 필터링 할 수 있음</li>
<li>패킷의 내용을 복호화 하기 때문에 더 많은 비용 필요</li>
<li>HTTP(80), HTTPS(443), FTP(21), WebSocket</li>
</ul>
</li>
</ul>
<h3 id="aws의-load-balancer">AWS의 Load Balancer</h3>
<p>AWS에는 ELB(Elastic Balancing)라는 서비스로 로드 밸런서를 제공하며, 아래와 같은 종류로 나눌 수 있다.</p>
<table>
<thead>
<tr>
<th>종류</th>
<th>특징</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td>ALB (Application Load Balancer)</td>
<td>http, https 접근에 특화</td>
<td>웹 사이트나 REST API를 제공하는 사이트</td>
</tr>
<tr>
<td>NLB (Network Load Balancer)</td>
<td>다양한 통신에 대응 가능</td>
<td>게임, 채팅 등</td>
</tr>
<tr>
<td>CLB (Classic Load Balancer)</td>
<td>옛날에 사용하던 로드밸런서</td>
<td>특별히 사용하는 경우 없음</td>
</tr>
</tbody></table>
<p><strong>ALB 추가 설명</strong>
<img src="https://velog.velcdn.com/images/hyeonz_kang/post/4aaaf0ff-fcef-402e-8091-a99560ef3c3c/image.jpeg" alt=""></p>
<ul>
<li>L7, application layer의 프로토콜에 대한 부하 처리</li>
<li>Listen: http, https, gRPC</li>
<li>Target: IP, Instance, Lambda</li>
<li>port 단위로 연결 가능 → 도커에서 유용하며 하나의 대상 그룹에 더 많은 컨테이너를 넣을 수 있어 비용 최적화 가능</li>
<li>특정 요청에 대해 서버 없이 응답 메시지 작성 가능</li>
<li>기본 라우팅 알고리즘은 Round Robin</li>
<li>Reverse Proxy 대로 Client IP와 서버사이에 들어오고 나가는 트래픽이 모두 Load Balancer와 통신</li>
<li>CLB/ALB는 Security Group을 통한 보안 가능</li>
<li>Client → Load Balancer의 Access 제한 가능</li>
<li>CLB/ALB는 IP 주소가 변동되기 때문에 Client에서 Access 할 ELB의 DNS Name을 사용</li>
</ul>
<p><strong>NLB 추가 설명</strong>
<img src="https://velog.velcdn.com/images/hyeonz_kang/post/b24395d0-bfe9-4d21-9210-79486b34f493/image.jpeg" alt=""></p>
<ul>
<li>L4, Transport Layer의 프로토콜에 대한 부하 처리</li>
<li>Listen: TCP, UDP, TLS</li>
<li>Target: IP, Instance</li>
<li>Client IP와 서버사이에서 서버로 들어오는 트래픽은 Load Balancer를 통하고 나가는 트래픽은 Client IP와 직접 통신</li>
<li>NLB는 Security Group 적용이 되지 않아서 서버에 적용된 Security Group에서 보안이 가능합니다.</li>
<li>Client → Server에서 Access 제한 가능</li>
<li>NLB는 할당한 Elastic IP 를 Static IP로 사용이 가능하여 DNS Name과 IP주소 모두 사용 가능 (private, public IP 둘 다 고정) </li>
</ul>
<h3 id="load-balancer-주요-성능-지표">Load Balancer 주요 성능 지표</h3>
<ul>
<li>초당 연결 수 (Connections per second)<ul>
<li>최대 처리 가능한 초당 TCP 세션 개수</li>
</ul>
</li>
<li>동시 연결 수 (Concurrent connections)<ul>
<li>동시에 유지할 수 있는 최대 세션 개수</li>
</ul>
</li>
<li>처리 용량 (Throughput)<ul>
<li>UDP 프로토콜에 대한 로드 밸런싱 성능 지표</li>
<li>FWLB(Firewall Load Balancing)에서 중요</li>
<li>단위: bps(bit per second), pps(packet per second)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[11. 테스트 개요]]></title>
            <link>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-11</link>
            <guid>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-11</guid>
            <pubDate>Tue, 15 Nov 2022 15:20:19 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/14cb104d-f215-4d32-be58-5c2016d1cf06/image.jpg" alt=""></p>
<h2 id="11-테스트-개요">11. 테스트 개요</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>자동 테스트는 소프트웨어를 변경할 수 있게 해주는 토대</li>
<li>테스트를 확장하려면 반드시 자동화해야 함</li>
<li>우수한 테스트 커버리지를 위해서는 균형 잡힌 test suite 필요</li>
<li>조직의 테스트 문화를 바꾸는 데는 시간이 필요</li>
</ul>
<p>소프트웨어 시스템의 복잡도에 대응하기 위해 테스트 코드의 중요성이 강조되고 있는 요즘, 구글의 사례를 통해 <strong>어떻게 테스트 코드를 관리하고 테스트 문화를 도입</strong>하게 되었는지 알아보는 것이 이번 챕터의 목표 입니다. 테스트는 단순히 버그를 잡기 위해서 뿐만 아니라 소프트웨어가 안전하게 변화할 수 있도록 지원, 시스템의 설계 개선 등 여러 이유로 꼭 필요합니다.</p>
<h3 id="1-테스트를-작성하는-이유">1. 테스트를 작성하는 이유</h3>
<p>테스트 코드가 주는 혜택은 다음과 같습니다.</p>
<ul>
<li><strong>디버깅 감소</strong>
 프로덕션 환경으로 릴리즈 되기 전에 정상 상태로 되돌릴 수 있습니다.</li>
<li><strong>자신 있게 변경</strong>
 모든 소프트웨어는 변경됩니다. 이 때 좋은 테스트가 있다면 안전하게 변경할 수 있습니다.</li>
<li><strong>더 나은 문서자료</strong>
 하나의 행위에만 집중해 검증하는 명확한 테스트는 실행 가능한 문서와 같습니다. 테스트는 명확하고 간결해야만 문서 자료로서의 역할을 수행할 수 있습니다.</li>
<li><strong>더 단순한 리뷰</strong>
 구글은 최소 한 명의 다른 엔지니어가 리뷰한 코드만이 submit 될 수 있습니다. 리뷰어가 변경된 코드가 제대로 작동하는지를 검증하는 시간을 크게 줄여줍니다.</li>
<li><strong>사려 깊은 설계</strong>
 테스트를 작성하는 일은 실질적으로 해당 코드의 API가 잘 설계되었는지 시험하는 행위입니다.</li>
<li><strong>고품질의 릴리즈를 빠르게</strong></li>
</ul>
<p>가장 단순한 테스트는 다음의 요소들이라고 정의할 수 있습니다.</p>
<ul>
<li>테스트하려는 단 하나의 행위 (주로 method, api)</li>
<li>특정한 입력 (api에 전달하려는 값)</li>
<li>관측 가능한 출력 혹은 동작</li>
<li>통제된 조건 (하나의 격리된 프로세스 등)</li>
</ul>
<p>문제가 터진 후에야 테스트를 고민해서는 안되며, 제품 결함 해결을 프로그래머의 능력에만 의존해서는 안됩니다. 그러므로 <strong>자동 테스트는 필수</strong>입니다. 좋은 자동 테스트 문화는 QA뿐아니라 모두가 테스트를 작성하고 공유하도록 장려하는 것입니다. 또한 테스트를 정기적으로 실행해야 하며, 테스트가 실패하면 바로 조치하도록 권장해야합니다.</p>
<blockquote>
<p>기본적인 자동 테스트 = 테스트 작성, 테스트 수행, 실패한 테스트에 대한 조치</p>
</blockquote>
<p>마지막으로 테스트는 엔지니어에게 신뢰를 줄 때만 가치가 있음을 명심해야 합니다.</p>
<h3 id="2-테스트-스위트test-suite-설계하기">2. 테스트 스위트(Test Suite) 설계하기</h3>
<p>모든 test-case에는 <strong>size</strong>와 <strong>scope</strong>이라는 두 가지 독립된 요소가 있습니다. </p>
<blockquote>
<p><strong>size</strong>: test case 하나를 실행하는 데 필요한 자원 (ex. 메모리, 프로세스, 시간, ...)
<strong>scope</strong>: 검증하려는 특정한 코드 경로</p>
</blockquote>
<h4 id="테스트-크기">테스트 크기</h4>
<p>구글에서는 모든 테스트를 <strong>크기 기준으로 분류</strong>하며, 엔지니어들에게 주어진 기능 조각을 검사하는 <strong>가능한 한 작은 테스트를 작성</strong>하라고 독려합니다. 테스트의 크기를 가늠하는 기준은 <strong>어떻게 동작하고, 무엇을 하고, 얼마나 많은 자원을 소비하는지로 평가</strong>합니다. 또한 구글은 ‘단위/통합 테스트’ 대신 작은 테스트, 중간 테스트, 큰 테스트로 나누어 사용합니다. test suite에 바라는 품질은 <strong>속도와 결정성</strong>이기 때문입니다.</p>
<blockquote>
<ul>
<li><strong>작은 테스트</strong><ul>
<li>제약이 가장 엄격</li>
<li>단 하나의 프로세스에서 실행 되어야 함</li>
<li>서버를 두고 독립된 테스트 프로세스에 연결해 수행하는 방식도 허용하지 않음</li>
<li>DB와 같은 제3의 프로그램을 수행해서도 안됨</li>
<li>네트워크와 디스트에 접근할 수 없으므로 sleep, I/O 같은 블로킹 호출을 사용해서도 안됨</li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li><strong>중간 테스트</strong><ul>
<li>여러 프로세스와 스레드를 활용할 수 있음</li>
<li>로컬 호스트로의 네트워크 호출 같은 블로킹 호출도 이용 가능</li>
<li>DB를 실행하거나 웹 UI와 서버 코드의 조합도 테스트 가능</li>
<li>유연성이 커져 테스트는 느려지고 비결정적이 될 수 있음</li>
<li>외부 요인이 개입되므로 성능과 결정성을 온전히 스스로가 보장할 수 없음</li>
</ul>
</li>
<li><strong>큰 테스트</strong><ul>
<li>테스트와 대상 시스템이 여러 대의 기기를 활용할 수 있음</li>
<li>단일 기기에서 구동할 때보다 느려지거나 비결정성이 커질 가능성이 높음</li>
<li>몇가지 용도에 한정해서 활용<ul>
<li>시스템 종단간(end-to-end) 테스트: 설정을 검증하는 것이 주된 목적</li>
<li>테스트 대역을 사용하는 것이 불가능한 레거시 컴포넌트를 테스트</li>
</ul>
</li>
</ul>
</li>
<li><strong>테스트 크기와 무관한 공통 특성</strong><ul>
<li>모든 테스트는 밀폐 되어야 함</li>
<li>즉, setup, execute, tear down 하는 데 필요한 모든 정보를 담고 있어야 함</li>
<li>테스트 수행 순서 같은 외부 환경에 관해서는 가능한 아무것도 가정하지 않아야 함</li>
<li>테스트에서는 조건문이나 순환문 같은 제어문을 쓰지 않는 것이 좋음</li>
</ul>
</li>
</ul>
<h4 id="테스트-범위">테스트 범위</h4>
<p>테스트 범위란 주어진 테스트가 얼마나 많은 코드를 검증하느냐를 뜻합니다.</p>
<blockquote>
<ul>
<li><strong>좁은 범위 테스트</strong><ul>
<li>ex) 단위테스트</li>
<li>독립된 클래스나 메서드 같이 코드 베이스 중  일부 로직을 검증하도록 설계</li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li><strong>중간 범위 테스트</strong><ul>
<li>ex) 통합 테스트</li>
<li>컴포넌트 사이의 상호작용을 검증하도록 설계</li>
</ul>
</li>
<li><strong>넓은 범위 테스트</strong><ul>
<li>ex) 기능 테스트, 종단간 테스트, 시스템 테스트</li>
<li>시스템의 서로 다른 부분들 사이의 상호작용이나 클래스나 메서드 하나만 실행할 때는 괜찮다가 여럿을 조합해 실행하면 나타나는 예기치 못한 동작을 검증하도록 설계</li>
</ul>
</li>
</ul>
<h4 id="test-coverage">Test Coverage</h4>
<p>코드 커버리지는 어느 테스트가 기능 코드의 어느 라인을 실행하는지를 측정하는 수단입니다. 코드 버커리지를 테스트 품질을 파악하는 지표로 사용하는 것을 권장하지 않습니다. 왜냐하면 커버리지 자체가 목표가 될 수 있기 때문입니다. 예를 들어 80%라는 목표치를 정해두면 그 이상해야 할 동기를 잃게 됩니다. 그러므로 검사해야 할 행위에 집중합시다. 참고로 큰 테스트는 커버리지 인플레이션을 일으키므로 작은 테스트에서만 측정해야한다.</p>
<h3 id="3-구글-규모의-테스트">3. 구글 규모의 테스트</h3>
<p>구글의 개발 환경을 살펴보면 모든 코드를 monorepo로 관리합니다. 그리고 해당 코드는 모든 엔지니어가 재사용할 수 있습니다. 코드베이스를 열어두면 공동 소유 의식이 생기는 이점이 있습니다. 또한 리포지터리 브랜치를 사용하는 팀이 거의 없습니다. 모든 변경이 레포지터리 헤드에 직접 커밋되어 변경 즉시 모두가 볼 수 있습니다. 나아가 모든 소프트웨어는 테스트 인프라가 검증한 가장 최신 커밋까지 반영해 빌드 됩니다. 구글의 규모와 모노리포 정책 등을 생각하면 코드가 수정되는 것은 당연한 일입니다. 그러므로 테스트의 중요성이 더 대두되었습니다. </p>
<blockquote>
<p>깨지기 쉬운 테스트 (brittle test), 즉 예상 결과를 너무 세세하게 표현하거나 광범위하고 복잡한 상용구가 덕지덕지한 테스트는 지양해야합니다. 이런 테스트를 만드는 주범으로 모의 객체 오용을 들 수 있습니다. 또한 테스트 스위트가 커지면 수행시간이 길어진다는 점도 문제입니다.</p>
</blockquote>
<blockquote>
<p>많이 사용하는 유틸리티에서 sleep(), setTimeout() 같은 함수를 호출하면 유휴 시간이 몇 분까지 늘어날 수 있음에 주의해야합니다. 이런 방식보다는 수 마이크로초 정도의 짧은 주기로 상태가 달라졌는지를 폴링하는 전략이 좋습니다.</p>
</blockquote>
<blockquote>
<p>거대한 테스트 스위트를 잘 관리하는 비결은 테스트를 존중하는 문화입니다.</p>
</blockquote>
<h3 id="4-구글의-테스트-역사">4. 구글의 테스트 역사</h3>
<p>구글은 테스트 문화를 정착시키기 위해서 Testing Grouplet이라 불린 자원봉사단이 환경을 적극적으로 개선했습니다. 
첫째로, 신규 입사자들에게 테스트 코드 작성이 원래 구글의 관례였던 것 처럼 오리엔테이션을 진행했습니다. 그런 교육을 받은 신규 입사자들은 기존 엔지니어들에게 테스트 코드 문화를 전파했습니다.
둘째로, 테스트 인증이라는 인증 프로그램을 만들었습니다. 테스트 인증의 목적은 각 팀이 자신의 테스트 프로세스 수준(성숙도)을 알게 하고 한 단계 올라서기 위한 지침을 제공하는 것이었습니다. 
셋째로, Testing on the Toilet(TotT)을 했습니다. 화장실 변기 앞에 전단지를 붙여 회사 전반의 테스트에 대한 인식을 적극적으로 높이는 목적의 활동입니다. 현재 이 TotT는 구글의 문화가 되었고 이에 대한 글들은 <a href="https://testing.googleblog.com/search/label/TotT">https://testing.googleblog.com/search/label/TotT</a> 여기에 정리되어 있습니다.</p>
<pre><code>물론 모든 종류의 테스트를 다 자동화 할 수는 없습니다. 
예를 들어 검색 결과의 품질을 테스트 하려면 사람의 판단이 개입되어야 합니다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[ 01. 소프트웨어 엔지니어링이란]]></title>
            <link>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-01</link>
            <guid>https://velog.io/@hyeonz_kang/%EA%B5%AC%EA%B8%80-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%9D%BC%ED%95%9C%EB%8B%A4-01</guid>
            <pubDate>Sun, 06 Nov 2022 15:02:26 GMT</pubDate>
            <description><![CDATA[<h1 id="구글-엔지니어는-이렇게-일한다">구글 엔지니어는 이렇게 일한다</h1>
<p><img src="https://velog.velcdn.com/images/hyeonz_kang/post/77636b4e-f589-498d-84e3-a209cd81b925/image.jpg" alt=""></p>
<h2 id="01-소프트웨어-엔지니어링이란">01. 소프트웨어 엔지니어링이란</h2>
<blockquote>
<h4 id="주요-내용">주요 내용</h4>
</blockquote>
<ul>
<li>Programming과 Software Engineering의 차이를 구분</li>
<li>코드의 기대 수명 동안 의존성, 기술, 제품 요구사항 변경에 대응할 역량 필요</li>
<li>하이럼의 법칙</li>
<li>조직의 반복 작업은 필요 인력 측면에서 확장 가능해야 함</li>
<li>일을 수행할 때는 책임감과 근거를 갖고 결정</li>
<li>객관적 데이터만으로 모든 일을 결정하기는 어려움</li>
<li>잘못을 인정하는 자세 필요</li>
</ul>
<p><strong>프로그래밍</strong>과 <strong>소프트웨어 엔지니어링</strong>의 가장 큰 차이는 <strong>time, scale, trade-off</strong> 라고 할 수 있습니다. 둘의 차이를 비교하고 이해하는 것이 이번 챕터의 목표입니다.</p>
<h3 id="1-시간과-변경">1. 시간과 변경</h3>
<p>첫째, programming과 software engineering의 차이는 <strong>프로그램의 지속 시간</strong>에 있습니다. 코드의 수명이 길어질수록 &#39;동작한다&#39;와 &#39;유지보수 가능하다&#39;의 차이를 분명하게 인지해야 합니다. 프로그래밍은 코드의 수명이 짧으므로 단순히 동작만 하면 되지만 소프트웨어 엔지니어링의 경우 오랜 시간 생존하기 때문에 유지보수까지 고려해야 합니다.</p>
<blockquote>
<p><strong><em>하이럼의 법칙 (Hyrum&#39;s Law)</em></strong>
API 사용자가 충분히 많다면 API 명세에 적힌 내용은 중요하지 않다. 시스템에서 관측될 수 있는 모든 행동 양식은 다른 이들에게 달려있을 것이다.</p>
</blockquote>
<p>최선의 의도, 최고의 엔지니어, 꼼꼼한 코드 리뷰가 뒷받침 되더라도 공표한 계약이나 모범 사례를 완벽하게 구현해냈다고 단정할 수 없다는 현실을 표현한 법칙입니다. API의 작은 변화도 이를 사용하고 있던 사용자들에겐 큰 파장이 일어날 수 있으므로 주의해야 합니다. 변경이 얼마나 유용할지를 분석할 때는 충돌을 조사/식별/해결하는 데 따르는 비용도 고려해야 합니다.</p>
<pre><code>API의 명세에 명시되지 않은 즉, 언제든 변할 수 있는 기능을 사용하는 코드는 &#39;기발한&#39; 코드이다. 
모범 사례를 따르고 미래에 대비한 코드는 &#39;클린&#39;하고 &#39;유지보수 가능한&#39; 코드이다. 
코드의 기대 수명에 따라 선택해야 한다.</code></pre><p>변경은 본질적으로 좋지 않지만 이를 피할 수는 없습니다. 그러므로 변경을 위한 변경은 삼가야 하지만 변화에 대응할 수는 있어야 합니다.</p>
<h3 id="2-규모-확장과-효율성">2. 규모 확장과 효율성</h3>
<p>둘째, programming과 software engineering의 차이는 <strong>규모 확장</strong>에 있습니다. 코드를 작성하고 관리하는 데 활용하는 모든 것이 비용과 자원 소비 측면에서 확장 가능해야 합니다. 특히 반복적으로 수행하는 일이라면 인적 비용 측면에서도 확장 가능해야 합니다.</p>
<pre><code>[확장성 문제를 고려하는 방법]
- 조직이 10배로 커지면 이 작업도 10배로 많아질까?
- 엔지니어가 해야 하는 일의 양이 조직이 커질수록 늘어날까?
- 코드 베이스가 커질수록 작업량도 늘어날까?
- 이 중 하나라도 해당할 경우 작업을 자동화 하거나 최적화할 수단이 있을까?

마지막이 “NO”라면 확장성에 문제가 있다.</code></pre><p>조직에서 효과적으로 확장을 하기 위해서는 갈아타기 규칙 처럼 책임 소재를 달리하는 방법이 있습니다. </p>
<blockquote>
<p><strong>갈아타기 규칙 (Churn Rule)</strong>
마이그레이션의 책임 소재를 각 사용자가 아닌 인프라 팀으로 한다. 인프라 팀은 사내 사용자들이 새 버전으로 옮기도록 돕거나 직접 업데이트를 하되, 하위 호환성을 유지해야 한다.</p>
</blockquote>
<p>또한 안정적인 확장을 위해서는 비욘세 규칙 처럼 개발자가 자신이 짠 코드의 테스트까지 책임 지는 자세가 필요합니다.</p>
<blockquote>
<p><strong>비욘세 규칙</strong>
인프라를 변경해 문제가 발생하더라도 해당 문제가 CI의 자동테스트에서 발견되지 않는 다면 인프라 팀의 책임이 아니다.</p>
</blockquote>
<p>이러한 확장에 따르는 비용을 줄이기 위해서는 인프라를 자주 변경해야합니다. 최초의 업그레이드가 수정량이 가장 많으며, 업그레이드 할 수록 수정량이 적어집니다. 또한 개발 과정에서 문제를 일찍 발견할 수록 비용이 적게 듭니다. 개발 과정이 다음과 같다면 문제 발견 시점을 최대한 왼쪽으로 옮기는 <strong>원점 회귀(Shift Left)</strong> 전략이 필요합니다. 
<em>[설계 - 구현 - 리뷰 - 테스트 - 커밋 - 카나리 (canary) - 배포]</em></p>
<pre><code>[코드 베이스의 유연성에 영향을 주는 요인]
- 전문성 (expertise): 충분한 지식
- 안정성 (stability): 규칙적인 릴리즈로 변경량 줄이기
- 순응 (conformity): 규칙적인 업그레이드
- 익숙함 (familiarity): 자동화
- 정책 (policy): 비욘세 규칙처럼 유용한 정책과 절차 갖추기</code></pre><h3 id="3-트레이드-오프와-비용">3. 트레이드 오프와 비용</h3>
<p>셋째, programming과 software engineering의 차이는 <strong>trade-off</strong>에 있습니다. 당시엔 최선의 선택일지라도 나중에는 오류가 될 수 있음을 인정해야 합니다. 그러므로 시스템의 생애 동안 과거의 결정을 수시로 재고해야 합니다. trade-off시엔 금융 비용뿐만 아니라 인적 비용, 기회 비용, 사회적 비용 등 종합적인 비용을 고려해야 합니다. 또한 최종 결정자는 필요하지만 결정의 책임은 모두의 것임을 명심해야 합니다.</p>
<pre><code>[사례: 분산 빌드]
1. 빌드하느라 시간이 낭비됨
2. 자체 분산 빌드 시스템 개발
3. 처음엔 효과적이었으나 시간이 흐르고 분산 빌드 자체가 커짐, 개인이 빌드 효율을 위해 노력하지 않게됨

즉, 사소한 trade-off 조차 예기치 목한 부정적인 효과를 초래할 수 있음</code></pre><pre><code>[사례: 시간 vs 규모 확장]
우리 팀에만 해당하는 문제가 발생했을 때 의존성을 추가할까, fork하거나 다시 구현할까?
- fork한다면 확실하게 최적화할 수 있고 외부 솔루션에 의존하지 않고 완전한 통제가 가능해짐
- 하지만 확장성과 지속 가능성이 떨어짐

프로젝트의 수명이 짧거나 코드의 영향 범위가 제한적인게 확실할 경우 → fork O
데이터 구조, 직렬화 포맷, 네트워크 프로토콜 처럼 프로젝트 수명에 종속되지 않는 인터페이스 → fork X</code></pre><h3 id="4-software-engineering-vs-programming">4. Software Engineering vs Programming</h3>
<pre><code>Software engineering is programming integrated over time.</code></pre><p>차원(고려해야 하는 주제의 큰 축)의 개수라는 점에서 programming과 software engineering은 다릅니다. 뭐가 더 좋고 나쁘다, 허접하고 훌륭하다는 관점으로 봐서는 안됩니다. 각각 적용되는 제약 사항, 가치, 모범 사례가 서로 다르다는 뜻입니다. 
&quot;이 코드의 예상 수명은?&quot; 이라는 질문을 통해 둘을 구분할 수 있습니다. <strong>소프트웨어 지속 가능성</strong>이 둘 차이의 핵심입니다. 또한 의사 결정의 <strong>복잡성과 이해관계</strong> 측면에서도 차이가 있습니다. 조직, 프로젝트 구성, 정책, 관례 등이 소프트웨어의 복잡성을 좌우합니다.</p>
<p><strong>프로그래밍</strong></p>
<ul>
<li>코드를 생산하는 즉각적인 행위</li>
<li>development</li>
<li>&#39;기발한 코드&#39;라는 말이 칭찬으로 들림 - 쉽게 해결할 수 있고 당장 활용할 수 있는 방법이 더 중요</li>
<li>CI/CD, 의존성 관리 등을 고려하지 않음</li>
</ul>
<p><strong>소프트웨어 엔지니어링</strong></p>
<ul>
<li>활용 가치가 남아 있는 한 오랫동안 코드를 유용하게 관리하고 팀 간 협업을 가능케 하는 정책, 관례, 도구 등을 아우르는 종합적인 개념</li>
<li>development + modification + maintenance</li>
<li>&#39;기발한 코드&#39;라는 말이 질책으로 들림 - 프로그래밍을 확장해 SW의 수명이 다할 때 까지 코드를 유지보수 하는 문제까지 고려</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>