<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ge-um.log</title>
        <link>https://velog.io/</link>
        <description>전 이것도 몰라요</description>
        <lastBuildDate>Wed, 25 Jan 2023 14:58:15 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ge-um.log</title>
            <url>https://velog.velcdn.com/images/ge-um/profile/8df628b6-702d-481b-9a19-f9f36f27fada/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ge-um.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ge-um" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[가장 가까운 같은 글자(Javascript)]]></title>
            <link>https://velog.io/@ge-um/%EA%B0%80%EC%9E%A5-%EA%B0%80%EA%B9%8C%EC%9A%B4-%EA%B0%99%EC%9D%80-%EA%B8%80%EC%9E%90</link>
            <guid>https://velog.io/@ge-um/%EA%B0%80%EC%9E%A5-%EA%B0%80%EA%B9%8C%EC%9A%B4-%EA%B0%99%EC%9D%80-%EA%B8%80%EC%9E%90</guid>
            <pubDate>Wed, 25 Jan 2023 14:58:15 GMT</pubDate>
            <description><![CDATA[<p>문자열 s가 주어졌을 때, s의 각 위치마다 자신보다 앞에 나왔으면서, 자신과 가장 가까운 곳에 있는 같은 글자가 어디 있는지 알고 싶습니다.
예를 들어, s=&quot;banana&quot;라고 할 때,  각 글자들을 왼쪽부터 오른쪽으로 읽어 나가면서 다음과 같이 진행할 수 있습니다.</p>
<ul>
<li>b는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.</li>
<li>a는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.</li>
<li>n은 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.</li>
<li>a는 자신보다 두 칸 앞에 a가 있습니다. 이는 2로 표현합니다.</li>
<li>n도 자신보다 두 칸 앞에 n이 있습니다. 이는 2로 표현합니다.</li>
<li>a는 자신보다 두 칸, 네 칸 앞에 a가 있습니다. 이 중 가까운 것은 두 칸 앞이고, 이는 2로 표현합니다.</li>
</ul>
<p>따라서 최종 결과물은 [-1, -1, -1, 2, 2, 2]가 됩니다.</p>
<p>문자열 s이 주어질 때, 위와 같이 정의된 연산을 수행하는 함수 solution을 완성해주세요.</p>
<h4 id="제한사항">제한사항</h4>
<ul>
<li>1 ≤ s의 길이 ≤ 10,000</li>
<li>s은 영어 소문자로만 이루어져 있습니다.</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>s|result
|:-:|:-:|
&quot;banana&quot;|[-1, -1, -1, 2, 2, 2]
&quot;foobar&quot;|[-1, -1, 1, -1, -1, -1]</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1
지문과 같습니다.</p>
<p>입출력 예 #2
설명 생략</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(s) {
    let arr = [];
    for(let i = 0; i &lt; s.length; i++){
        if(s.slice(0,i).includes(s[i])){
            arr.push(i - s.slice(0,i).lastIndexOf(s[i]));
        }
        else{
            arr.push(-1);
        }
    }
    return arr;
}</code></pre>
<p>나는 한 글자씩 그 글자의 앞부분만 잘라서 검사해 주었다. 앞부분에 찾는 문자열이 있다면 현재 인덱스에서 잘린 앞부분 문자열의 마지막 인덱스를 뺀 값을 배열에 넣어주었고, 없다면 -1을 넣어 주었다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(s) {
    const hash={};

    return [...s].map((v,i)=&gt;{
        let result = hash[v] !== undefined ? i - hash[v] : -1;
        hash[v] = i;
        return result;
    });
}</code></pre>
<h2 id="해시-테이블을-사용하면-더-쉽게-구할-수-있었다-이-풀이는-해시-테이블을-만든-뒤-해시-테이블에서-값을-검색했을-때-있으면-i-hashv-값을-없다면--1을-result-변수에-넣어주었다-그리고-각-문자열은-나올-때-마다-문자열-키값에-인덱스-값을-넣어-준다-이렇게-하면-결국-중복으로-나오는-문자열이-있다면-현재-인덱스에서-중복-문자열의-인덱스를-뺀-값을-리턴할-수-있다">해시 테이블을 사용하면 더 쉽게 구할 수 있었다. 이 풀이는 해시 테이블을 만든 뒤, 해시 테이블에서 값을 검색했을 때 있으면 i-hash[v] 값을, 없다면 -1을 result 변수에 넣어주었다. 그리고 각 문자열은 나올 때 마다 문자열 키값에 인덱스 값을 넣어 준다. 이렇게 하면 결국 중복으로 나오는 문자열이 있다면 현재 인덱스에서 중복 문자열의 인덱스를 뺀 값을 리턴할 수 있다. </h2>
<p>hash는 map처럼 key와 value를 저장한다는 것은 같지만, map이 조금 더 고급 방법을 지원한다. 중요한 차이점은 다음과 같다. </p>
<ul>
<li><p>키: 맵의 키는 모든 값(개체 및 함수 포함)이 될 수 있는 반면 해시의 키는 문자열 또는 기호만 될 수 있다.</p>
</li>
<li><p>순서: Map의 요소는 삽입된 순서를 유지하지만 Hash의 요소는 그렇지 않다. </p>
</li>
<li><p>반복: for...of 루프를 사용하여 맵의 키와 값을 반복할 수 있는 반면 for...in 루프는 해시의 키를 반복하는 데만 사용할 수 있다. </p>
</li>
<li><p>크기: map에는 크기 속성이 있지만 해시에는 그러한 속성이 없다.</p>
</li>
<li><p>빌트인 메서드 : 맵에는 데이터를 조작하기 위한 set(), get(), has(), clear(), delete() 등과 같은 더 많은 기본 제공 방법이 있지만 Hash에는 이러한 방법이 없다. </p>
</li>
</ul>
<p>그래서 사실상 hash를 굳이 사용하기보다는 map을 사용하면 될 듯 하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[개발 도서 리뷰] 테스트 주도 개발 2부 & 3부]]></title>
            <link>https://velog.io/@ge-um/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C-2%EB%B6%80-3%EB%B6%80</link>
            <guid>https://velog.io/@ge-um/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C-2%EB%B6%80-3%EB%B6%80</guid>
            <pubDate>Tue, 24 Jan 2023 09:07:34 GMT</pubDate>
            <description><![CDATA[<p>일단 1회독은 했는데, 아직까지 이해하기 어려운 예시도 있었다. 개발 경험을 점점 쌓아가면서 다시 한 번 읽어 보면 좋을 듯 하다. 일단 이해가 가능하고 중요한 부분 위주로 정리를 해 보았다. </p>
<hr>
<h2 id="2부">2부</h2>
<ul>
<li><p>TDD를 마스터하기 위해서 작은 단계로 작업하는 연습이 필요하다. 마스터하면 훨씬 큰 기능 단계로 작업할 수 있지만, 처음에는 작은 단계로 연습을 해 보는 것이 좋다. 필요할 때 작은 단계로 작업할 수 있어야 하기 때문이다. </p>
</li>
<li><p>한 번에 메서드를 하나 이상 수정하지 않으면서 테스트가 통과하게 만들 수 있는 방법을 찾아내는 것이 좋다. </p>
</li>
<li><p>테스트를 하기 위해 객체를 생성하면 두 가지 제약이 상충한다. 객체 하나만 생성하여 여러 테스트에서 사용하면 성능상으로 이점을 가지지만, 그 객체를 수정했을 때 다른 테스트에서 오류가 날 수 있다. 따라서 테스트 커플링을 만들지 않는 것이 중요하다. </p>
</li>
<li><p>따라서 테스트를 처음 만들 때는 객체를 하나하나 생성하여 각각의 테스트가 잘 동작하는지 확인한 후, 일반화 시키는 것이 좋다. </p>
</li>
<li><p>리팩토링했다가 이를 다시 되돌리는 것은 흔한 일이다. </p>
</li>
<li><p>테스트를 선택할 때는 나에게 뭔가 가르침을 줄 수 있고 내가 만들 수 있다는 확신이 드는 것을 선택한다. 테스트를 하나 성공시켰는데 그 다음 테스트를 만들며 문제가 생기면 두 단계 뒤로 물러서는 것을 고려하라. </p>
</li>
</ul>
<h2 id="3부">3부</h2>
<ul>
<li><p>테스트는 다른 테스트와 완전히 독립적이어야 한다. 즉, 문제가 하나면 테스트도 하나만 실패해야 하고, 문제가 둘이면 테스트도 두 개만 실패해야 한다. </p>
</li>
<li><p>격리된 테스트가 암묵적으로 내포하는 특징 중 하나는 테스트가 실행 순서에 독립적이게 된다는 점이다. 테스트의 일부만 실행해보고 싶으면, 선행 테스트가 실행되지 않아서 내가 고른 테스트들이 실패하지 않을까 걱정할 필요 없이 그렇게 할 수 있어야 한다. </p>
</li>
<li><p>테스트 주도 개발을 할 때는 우선 구현할 필요가 있는 모든 오퍼레이션의 사용 예들을 적는다. 그 다음, 이미 존재하지 않는 오퍼레이션에 대해서 오퍼레이션에 널 버전(아무 일도 하지 않는 버전)을 리스트에 적는다. 마지막으로 깔끔한 코드를 얻기 위해 이번 작업을 끝내기 전에 반드시 해야 할 리팩토링 목록을 적는다. </p>
</li>
<li><p>테스트 작성은 테스트 대상이 되는 코드를 작성하기 직전에 작성하는 것이 좋다. </p>
</li>
<li><p>데이터의 의도를 표현할 때는 명백한 데이터를 사용할 수 있다. 예를 들어, 숫자 49.25 대신 100/2*(1-0.015) 같이 식을 사용한다면 입력으로 사용된 숫자와 예상되는 숫자 사이의 관계를 읽어낼 수 있다. </p>
</li>
<li><p>키보드로 뭘 쳐야 할지 알면, 명백한 구현을 한다. 잘 모르겠다면 가짜 구현을 한다. 올바른 설계가 명확하지 않다면 삼각측량 기법을 사용한다. 그래도 모르겠다면 샤워를 하러 간다. </p>
</li>
<li><p>지나치게 큰 테스트 케이스의 경우, 원래 케이스의 깨지는 부분에 해당하는 작은 테스트 케이스를 작성하고 그 작은 테스트 케이스가 실행되도록 한다. 그 후에 다시 원래의 큰 테스트 케이스를 추가한다.</p>
</li>
<li><p>혼자 작업한다면, 깨진 테스트를 만들어 놓고 작업을 종료한다. 오랜 시간 후에 작업할 때, 해야할 부분을 명확히 찾을 수 있다. 하지만 팀으로 작업한다면 코드를 항상 완성해 놓는 게 좋다. </p>
</li>
<li><p>객체 컬렉션을 다루는 연산은, 일단 컬렉션 없이 구현하고 그 다음에 컬렉션을 사용하게 한다. </p>
</li>
<li><p>설계 문제가 있음을 알려주는 테스트의 속성</p>
<ul>
<li><p>긴 셋업 코드 : 하나의 단순한 단언을 수행하기 위해서 수백 줄의 객체 생성 코드가 필요하다면 문제가 있는 것이다. </p>
</li>
<li><p>셋업 중복 : 공통의 셋업 코드를 넣어 둘 공통의 장소를 찾기 힘들다면, 서로 밀접하게 엉킨 객체들이 너무 많다는 뜻이다. </p>
</li>
<li><p>실행 시간이 오래 걸리는 테스트</p>
</li>
<li><p>깨지기 쉬운 테스트 : 예상치 못하게 실패하는 테스트가 있다면 특정 부분이 다른 부분에 이상한 방법으로 영향을 끼친다는 뜻이다. </p>
</li>
</ul>
</li>
<li><p>테스트를 지워야 할 때 </p>
<ul>
<li><p>테스트를 지워도 자신감이 떨어지지 않을 때.</p>
</li>
<li><p>두 개의 테스트가 코드의 동일한 부분을 실행하더라도, 둘이 서로 다른 시나리오를 말한다면 그대로 남겨두어야 한다. </p>
</li>
</ul>
</li>
</ul>
<h3 id="리팩토링">리팩토링</h3>
<ul>
<li><p>비슷해 보이는 두 코드 조각을 합치려면 두 코드를 단계적으로 닮아가게 수정한다. 이 둘이 완전히 동일해지면 둘을 합친다. </p>
</li>
<li><p>너무 코드 흐름이 꼬여있다면 메서드를 다시 인라인시킨 다음 흐름을 이해하고 다시 추상화한다. </p>
</li>
<li><p>한 메서드에서 다른 객체에 하나 이상의 메시지를 보내는 것을 보면 메서드를 옮기는 것이 좋다. </p>
</li>
<li><p>여러 개의 매개 변수와 지역 변수를 갖는 복잡한 메서드는 메서드를 꺼내서 객체로 만든다. </p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[안전지대]]></title>
            <link>https://velog.io/@ge-um/%EC%95%88%EC%A0%84%EC%A7%80%EB%8C%80</link>
            <guid>https://velog.io/@ge-um/%EC%95%88%EC%A0%84%EC%A7%80%EB%8C%80</guid>
            <pubDate>Sun, 15 Jan 2023 13:02:25 GMT</pubDate>
            <description><![CDATA[<p>다음 그림과 같이 지뢰가 있는 지역과 지뢰에 인접한 위, 아래, 좌, 우 대각선 칸을 모두 위험지역으로 분류합니다.
<img src="https://velog.velcdn.com/images/ge-um/post/d58bff2e-709a-420a-93a5-9b6febbe2770/image.png" alt=""></p>
<p>지뢰는 2차원 배열 board에 1로 표시되어 있고 board에는 지뢰가 매설 된 지역 1과, 지뢰가 없는 지역 0만 존재합니다.
지뢰가 매설된 지역의 지도 board가 매개변수로 주어질 때, 안전한 지역의 칸 수를 return하도록 solution 함수를 완성해주세요.</p>
<h4 id="제한사항">제한사항</h4>
<ul>
<li>board는 n * n 배열입니다.</li>
<li>1 ≤ n ≤ 100</li>
<li>지뢰는 1로 표시되어 있습니다.</li>
<li>board에는 지뢰가 있는 지역 1과 지뢰가 없는 지역 0만 존재합니다.</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>board|result
|:-:|:-:|
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0]]|16
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]]|13
[[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]]|0</p>
<p>입출력 예 설명</p>
<p>입출력 예 #1</p>
<p>(3, 2)에 지뢰가 있으므로 지뢰가 있는 지역과 지뢰와 인접한 위, 아래, 좌, 우, 대각선 총 8칸은 위험지역입니다. 따라서 16을 return합니다.
입출력 예 #2</p>
<p>(3, 2), (3, 3)에 지뢰가 있으므로 지뢰가 있는 지역과 지뢰와 인접한 위, 아래, 좌, 우, 대각선은 위험지역입니다. 따라서 위험지역을 제외한 칸 수 13을 return합니다.
입출력 예 #3</p>
<p>모든 지역에 지뢰가 있으므로 안전지역은 없습니다. 따라서 0을 return합니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(board) {
    for (let i = 0; i &lt; board.length; i++) {
        for (let j = 0; j &lt; board[i].length; j++) {
            if(board[i][j] === 1){
                checkBombs(i, j, board);
            }
        }
    }
    return board.flat().filter(v =&gt; v === 0).length;
}

function checkBombs(i, j, board) {
    for (let x = -1; x &lt;= 1; x++) {
        for (let y = -1; y &lt;= 1; y++) {
            checkBoardBounds(i+x, y+j, board);
        }
    }
}

function checkBoardBounds(xAxis, yAxis, board) {
    if (xAxis &gt;= 0 &amp;&amp; xAxis &lt; board.length &amp;&amp; yAxis &gt;= 0 &amp;&amp; yAxis &lt; board.length) {
        checkIfNotBomb(xAxis, yAxis, board);
    }
}

function checkIfNotBomb(xAxis, yAxis, board) {
    if (board[xAxis][yAxis] !== 1) {
        board[xAxis][yAxis] = 2;
    }
}</code></pre>
<p>중첩문이 너무 길어져서 함수를 뽑았다. depth가 너무 깊지 않게 줄였는데도 2차원 배열을 순회하다보면 자꾸 depth가 늘어나게 된다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(board) {

    let outside = [[-1,0], [-1,-1], [-1,1], [0,-1],[0,1],[1,0], [1,-1], [1,1]];
    let safezone = 0;

    board.forEach((row, y, self) =&gt; row.forEach((it, x) =&gt; {
        if (it === 1) return false;
        return outside.some(([oy, ox]) =&gt; !!self[oy + y]?.[ox + x])
               ? false : safezone++;
    }));

    return safezone;
}</code></pre>
<p>나는 겁나 어렵게 풀었는데~ 이분 코드는 참 깔끔하다는 생각이 들었다. 
일단 forEach문을 중첩시킴으로써 depth가 깊어지지 않도록 만들어 주었다. 2차원 배열을 검색할 때는 forEach문을 중첩하는 게 보기 깔끔하겠다는 생각이 들었다. </p>
<p>그리고 만약 1, 즉, 폭탄이 존재한다면 바로 리턴해주고 아니라면 some과 !!, optional chaining(?.)을 이용하여 이 바깥쪽 위치값이 배열에 존재하는지 확인해 준다. </p>
<p>찾아보니 some은 배열 안의 값이 주어진 함수를 하나라도 통과하는지 확인하는 메서드이고, !!은 값을 boolean 값으로 바꿔주는 것이다. 또한 optional chaining은 오류가 난다면 그 값을 undefined로 바꿔주기 때문에 !!와 결합하면 오류값을 false처럼 만들 수 있다. </p>
<p>그리고 삼항 연산자를 이용하여 값이 false, 즉, 0일 때만 safezone의 값을 증가시켜 준다. 앞쪽의 false는 삼항 연산자를 만들기 위해 임의로 아무 값이나 리턴해 준 것인 듯 하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[개발 도서 리뷰] 객체지향의 사실과 오해]]></title>
            <link>https://velog.io/@ge-um/%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%84%9C-%EB%A6%AC%EB%B7%B0-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4</link>
            <guid>https://velog.io/@ge-um/%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%84%9C-%EB%A6%AC%EB%B7%B0-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4</guid>
            <pubDate>Sun, 15 Jan 2023 10:22:49 GMT</pubDate>
            <description><![CDATA[<p>객체 지향에 대해 추상적인 내용이 주를 이루어서 좀 어려웠다. 제대로 이해한 건지는 모르겠지만 내 나름대로 중요하다고 생각하는 점을 정리해 보려고 한다. 쓰다 보니 길어져서 아무래도 나만 읽을 것 같긴 하지만 ㅋㅋ 중요한 점이랑 몰랐던 점이 한 둘이 아니라 어쩔 수 없었다. 다음에 기회가 된다면 이걸 더 쉽게 정리해 봐야겠다. </p>
<h3 id="1-객체지향의-목표는-실세계를-모방하는-것이-아니다">1. 객체지향의 목표는 실세계를 모방하는 것이 아니다.</h3>
<ul>
<li><p>실세계에 대한 비유가 객체지향의 개념을 이해하는 데는 유용하지만, 실무적인 관점에서는 부적합하다. </p>
</li>
<li><p>객체지향의 목표는 현실 세계를 모방하는 것이 아니라 현실 세계를 기반으로 새로운 세계를 창조하는 것이다. </p>
</li>
<li><p>소프트웨어 상품은 실제 세계의 상품이 하지 못하는 가격 계산과 같은 행동을 스스로 수행할 수 있다. </p>
</li>
<li><p>현실 세계와 객체지향 사이의 관계를 좀 더 정확하게 설명할 수 있는 단어는 은유이다. </p>
</li>
<li><p>은유 관계에 있는 실제 객체의 이름으로 사용하면 표현적 차이를 줄여 소프트웨어의 구조를 쉽게 예측할 수 있다. 따라서 소프트웨어 객체에 대한 현실 객체의 은유를 효과적으로 사용할 경우 표현적 차이를 줄일 수 있으며, 이해하기 쉽고 유지보수가 용이한 소프트웨어를 만들 수 있다.</p>
</li>
</ul>
<h3 id="2-객체는-자율적이고-협력적이다">2. 객체는 자율적이고, 협력적이다.</h3>
<ul>
<li><p>객체는 인간의 사회와 유사하게, 공동의 목표를 달성하기 위해 협력에 참여하지만 스스로의 결정과 판단에 따라 행동하는 존재이다. </p>
</li>
<li><p>객체의 자율성은 내부와 외부를 명확하게 구분하는 것으로부터 나온다. 객체는 다른 객체가 <strong>무엇</strong>을 수행하는지는 알 수 있지만 <strong>어떻게</strong> 수행하는지에 대해서는 알 수 없다. </p>
</li>
<li><p>객체는 시스템의 행위를 구현하기 위해 다른 객체와 <strong>협력</strong>한다. 각 객체는 협력 내에서 정해진 역할을 수행하며 역할은 관련된 <strong>책임</strong>의 집합이다. </p>
</li>
<li><p>객체는 다른 객체와 협력하기 위해 <strong>메시지</strong>를 전송하고, 메시지를 수신한 객체는 메시지를 처리하는 데 적합한 <strong>메서드</strong>를 자율적으로 선택한다. 메시지와 메서드를 분리하는 것은 객체의 자율성을 높이는 핵심 메커니즘이다. 이것은 <strong>캡슐화</strong>라는 개념과도 관련되어 있다. </p>
</li>
<li><p>전통적인 개발 방법은 데이터와 프로세스를 엄격하게 구분한다. 이에 반해 객체지향에서는 데이터와 프로세스를 객체라는 하나의 틀 안에 함께 묶어 놓음으로써 객체의 자율성을 보장한다. </p>
</li>
</ul>
<h3 id="3-객체의-상태와-행동-식별자">3. 객체의 상태와 행동, 식별자</h3>
<ul>
<li>객체는 상태와 행동, 식별자를 가지고 있다. </li>
</ul>
<h4 id="상태">상태</h4>
<ul>
<li><p>객체는 상태를 가지며 상태는 변경 가능하다.</p>
</li>
<li><p>객체의 상태를 구성하는 모든 특징을 통틀어 객체의 프로퍼티라고 한다. 일반적으로 변경되지 않고 고정되기 때문에 &#39;정적&#39;이다.</p>
</li>
<li><p>프로퍼티 값은 시간이 흐름에 따라 변경되기 때문에 &#39;동적&#39;이다. </p>
</li>
<li><p>객체의 프로퍼티는 단순한 값인 속성과 다른 객체를 가리키는 링크라는 두 가지 종류의 조합으로 표현할 수 있다. </p>
</li>
</ul>
<h4 id="행동">행동</h4>
<ul>
<li>객체의 상태를 변경시키는 것은 객체의 행동이다.<ul>
<li>행동의 결과는 상태에 의존적이며 상태를 이용해 서술할 수 있다.</li>
<li>행동의 순서가 실행 결과에 영향을 미친다.</li>
</ul>
</li>
</ul>
<h4 id="식별자">식별자</h4>
<ul>
<li>객체는 어떤 상태에 있더라도 유일하게 식별 가능하다. 객체가 아닌 단순한 값은 식별자를 가지지 않는다. </li>
</ul>
<h3 id="4-캡슐화">4. 캡슐화</h3>
<ul>
<li><p>객체는 상태를 캡슐 안에 감춰둔 채 외부로 노출하지 않는다. 객체가 외부에 노출하는 것은 행동뿐이며, 외부에서 객체에 접근할 수 있는 유일한 방법 또한 행동뿐이다. </p>
</li>
<li><p>객체를 캡슐화하는 것은 결과적으로 객체의 자율성을 높인다. 협력에 참여하는 객체들의 지능이 높아질수록 협력은 유연하고 간결해진다. </p>
</li>
</ul>
<h3 id="5-행동이-상태를-결정한다">5. 행동이 상태를 결정한다.</h3>
<ul>
<li><p>상태를 먼저 결정하고 행동을 나중에 결정하는 방법은 설계에 나쁜 영향을 끼친다. </p>
</li>
<li><p>상태를 먼저 고려하는 방식은 협력을 고려하지 않고 객체를 따로 설계하게 만들어 협력에 적합하지 못한 객체를 만들어 낸다. 따라서 재사용성 또한 저해된다. </p>
</li>
</ul>
<h3 id="6-타입과-추상화">6. 타입과 추상화</h3>
<ul>
<li><p>추상화를 함으로써 복잡한 세상을 제어 가능할 정도로 단순하게 만든다. </p>
</li>
<li><p>객체지향 프로그램을 작성할 때 우리는 객체를 일종의 데이터처럼 사용한다. 따라서 객체를 타입에 따라 분류하고 그 타입에 이름을 붙이는 것은 결국 프로그램에서 이용할 새로운 데이터 타입을 선언하는 것과 같다.</p>
</li>
<li><p>객체의 타입을 결정하는 것은 객체의 행동뿐이다. 객체가 어떤 데이터를 보유하고 있는지는 타입을 결정하는 데 아무런 영향도 미치지 않는다. </p>
</li>
<li><p>같은 타입에 속한 객체는 행동만 동일하다면 서로 다른 데이터를 가질 수 있다. 여기서 동일한 행동이란 동일한 책임을 의미하며, 동일한 책임이란 동일한 메시지 수신을 의미한다. 따라서 동일한 타입에 속한 객체는 내부의 데이터 표현 방식이 다르더라도 동일한 메시지를 수신하고 이를 처리할 수 있다. 다만 내부의 표현 방식이 다르기 때문에 동일한 메시지를 처리하는 방식은 서로 다를 수 밖에 없다. 이것은 다형성에 의미를 부여한다. </p>
</li>
<li><p>타입은 시간에 따라 동적으로 변하는 앨리스의 상태를 시간과 무관한 정적인 모습으로 다룰 수 있게 해준다. 이런 관점에서 타입은 추상화다. </p>
</li>
<li><p>객체를 분류하기 위해 타입을 결정한 후 프로그래밍 언어를 이용해 타입을 구현할 수 있는 한 가지 방법이 클래스이다. </p>
</li>
</ul>
<h3 id="7-역할-책임-협력">7. 역할, 책임, 협력</h3>
<h4 id="협력">협력</h4>
<ul>
<li>협력은 다수의 요청과 응답으로 구성되며 저체적으로 협력은 다수의 연쇄적인 요청과 응답의 흐름으로 구성된다. </li>
</ul>
<h4 id="책임">책임</h4>
<ul>
<li><p>객체지향 개발에서 가장 중요한 능력은 책임을 능숙하게 할당하는 것이다. 책임이 제자리를 잡지 않은 상태에서 구현하는 것은 변경에 취약하고 다양한 협력에 참여할 수 없는 비자율적인 객체를 만들게 된다. </p>
</li>
<li><p>객체의 책임은 하는 것(doing)과 아는 것(knowing)의 두 가지 범주로 나눌 수 있다. </p>
</li>
<li><p>메시지를 기반으로 객체가 책임을 수행하게 하는 것이 가능하다. 하지만 책임과 메시지의 수준이 같지는 않다. 책임을 결정한 후 협력을 정제하면서 이를 메시지로 변환할 때는 하나의 책임이 여러 메시지로 분할되는 것이 일반적이다. </p>
</li>
<li><p>객체지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고 어떤 객체로부터 메시지를 수신할 것인지를 결정하는 것으로부터 시작된다. </p>
</li>
<li><p>책임은 자율적이어야 한다. 자율적인 책임의 특징은 객체가 어떻게 해야 하는 것인가가 아니라 무엇을 해야 하는가를 설명한다.</p>
</li>
<li><p>책임은 너무 추상적이여도 안된다. </p>
</li>
</ul>
<h4 id="역할">역할</h4>
<ul>
<li><p>역할은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식이다. </p>
</li>
<li><p>어떤 객체라도 역할을 대신 할 수는 없다. 역할을 대체하기 위해서는 각 역할이 수신할 수 있는 메시지를 동일한 방식으로 이해해야 한다. </p>
</li>
<li><p>역할의 개념을 사용하면 유사한 협력을 추상화해서 인지 과부하를 줄일 수 있다. 역할은 객체지향 설계의 단순성, 유연성, 재사용성을 뒷받침하는 핵심 개념이다. </p>
</li>
<li><p>역할의 가장 큰 가치는 하나의 협력 안에 여러 종류의 객체가 참여할 수 있게 함으로써 협력을 추상화할 수 있다는 것이다. 따라서 역할을 이용하면 협력을 추상화함으로써 단순화할 수 있다. </p>
</li>
<li><p>역할의 대체 가능성은 행위 호환성을 의미하고, 행위 호환성은 동일한 책임의 수행을 의미한다. </p>
</li>
</ul>
<h4 id="흔한-오류">흔한 오류</h4>
<ul>
<li><p>객체가 존재하는 이유는 행위를 수행하며 협력에 참여하기 위해서다.</p>
</li>
<li><p>객체지향의 핵심은 클래스를 어떻게 구현할 것인가가 아니라 객체가 협력 안에서 어떤 책임과 역할을 수행할 것인지를 결정하는 것이다. </p>
</li>
<li><p>객체지향 입문자들이 데이터나 클래스를 중심으로 애플리케이션을 설계하는 이유는 협력이라는 문맥을 고려하지 않고 각 개체를 독립적으로 바라보기 때문이다. </p>
</li>
<li><p>어떤 애플리케이션에 적합한 객체를 설계하기 위해서는 협력이라는 문맥에서 바라 보아야 한다. </p>
</li>
</ul>
<h4 id="객체-지향-설계-기법">객체 지향 설계 기법</h4>
<ul>
<li><p>역할 책임, 협력의 관점에서 애플리케이션을 설계하는 유용한 방법</p>
</li>
<li><p>책임 주도 설계 : 협력에 필요한 책임들을 식별하고 적합한 객체에게 책임을 할당하는 방식으로 애플리케이션 설계</p>
</li>
<li><p>디자인 패턴 : 전문가들이 반복적으로 사용하는 해결 방법을 정의해 놓은 설계 템플릿의 모음</p>
</li>
<li><p>테스트 주도 개발 : 테스트가 아니라 설계를 위한 기법. 실제 목적은 구체적인 코드를 작성해나가면서 역할, 책임, 협력을 식별하고 식별된 역할 책임, 협력이 적합한지를 피드백받는 것이다. </p>
</li>
</ul>
<h3 id="8-메시지">8. 메시지</h3>
<ul>
<li><p>메시지가 있다면 메시지 그 자체와 그 메시지를 처리할 수 있는 방법이 필요하게 된다. 그 방법이 바로 메서드이다. 메서드는 클래스 안에 포함된 함수 혹은 프로시저를 통해 구현된다. </p>
</li>
<li><p>메시지와 메서드를 활용하면 다형성이라는 개념을 이해할 수 있다. 메시지는 무엇이 실행될지는 명시하지만 메시지를 어떻게 실행할 것인지는 수신자가 전적으로 결정할 수 있다. 메시지 처리 방법에는 어떤 제약도 없기 때문에 동일한 메시지라고 하더라도 서로 다른 방식의 메서드를 이용하여 처리할 수 있다. 따라서 다형성을 하나의 메시지와 하나 이상의 메서드 사이의 관계로 볼 수 있다. </p>
</li>
</ul>
<h3 id="9-책임-주도-설계">9. 책임 주도 설계</h3>
<ul>
<li><p>What/Who 사이클 : 책임-주도 설계의 핵심은 어떤 행위가 필요한지를 먼저 결정한 후에 이 행위를 수행할 객체를 결정하는 것이다. </p>
</li>
<li><p>묻지 말고 시켜라 : 송신자는 수신자가 어떤 객체인지 모르기 때문에 객체에 관해 꼬치꼬치 캐물을 수 없다. 단지 송신자는 수신자가 어떤 객체인지는 모르지만 자신이 전송한 메시지를 잘 처리할 것이라는 것을 믿고 메시지를 전송할 수 밖에 없다. </p>
</li>
</ul>
<h3 id="10-인터페이스">10. 인터페이스</h3>
<ul>
<li><p>인터페이스는 객체가 책임을 수행하기 위해 외부로부터 메시지를 받기 위한 통로이다. </p>
</li>
<li><p>객체가 어떤 메시지를 수신할 수 있느냐가 어떤 책임을 수행할 수 있느냐와 어떤 인터페이스를 가질 것인지를 결정한다. </p>
</li>
</ul>
<p>멧 와이스펠드는 객체지향적인 사고 방식을 이해하기 위해서는 다음의 세 가지 원칙이 중요하다고 주장한다. </p>
<ul>
<li><p>좀 더 추상적인 인터페이스</p>
</li>
<li><p>최소 인터페이스 : 외부에서 사용할 필요가 없는 인터페이스는 최대한 노출하지 말라</p>
</li>
<li><p>인터페이스와 구현 간에 차이가 있다는 점을 인식</p>
<ul>
<li><p>객체를 구성하지만 공용 인터페이스에 포함되지 않는 모든 것이 구현이다.</p>
</li>
<li><p>객체는 상태를 가진다. 상태는 객체에 포함되겠지만 객체 외부에 노출되는 공용 인터페이스의 일부는 아니다. 따라서 상태를 어떻게 표현할 것인가는 객체의 구현에 해당한다.</p>
</li>
<li><p>객체는 행동을 가진다. 행동은 메시지를 수신했을 때만 실행되는 일종의 메시지 처리 방법이다. 이 처리 방법을 메서드라고 한다. 메서드를 구성하는 코드 자체는 객체 외부에 노출되는 공용 인터페이스의 일부는 아니기 때문에 객체의 구현 부분에 포함된다. </p>
</li>
<li><p>객체의 외부와 내부를 분리하라는 말은 결국 객체의 공용 인터페이스와 구현을 명확하게 분리하라는 말과 동일하다. </p>
</li>
<li><p>훌륭한 객체란 구현을 모른 채 인터페이스만 알면 쉽게 상호작용할 수 있는 객체를 의미한다. 이것은 객체를 설계할 때 객체 외부에 노출되는 인터페이스와 객체의 내부에 숨겨지는 구현을 명확하게 분리해서 고려해야 한다는 것을 의미한다. 이를 인터페이스와 구현의 분리 원칙이라고 한다. </p>
</li>
</ul>
</li>
</ul>
<h3 id="11-책임의-자율성이-협력의-품질을-결정한다">11. 책임의 자율성이 협력의 품질을 결정한다.</h3>
<ul>
<li><p>자율적인 책임은 협력을 단순하게 만든다.</p>
<ul>
<li>자율적인 책임은 세부적인 사항들을 무시하고 의도를 드러내는 하나의 문장으로 표현함으로써 협력을 단순하게 만든다. 즉, 책임이 적절하게 추상화된다. </li>
</ul>
</li>
<li><p>자율적인 책임은 객체의 외부와 내부를 명확하게 분리한다.</p>
<ul>
<li>요청하는 객체가 몰라도 되는 사적인 부분이 객체 내부로 캡슐화되기 때문에 인터페이스와 구현이 분리된다. </li>
</ul>
</li>
<li><p>책임이 자율적일 경우 책임을 수행하는 내부적인 방법을 변경하더라도 외부에 영향을 미치지 않는다.</p>
<ul>
<li>변경의 파급효과가 객체 내부로 캡슐화되기 때문에 두 객체 간의 결합도가 낮아진다. </li>
</ul>
</li>
<li><p>자율적인 책임은 협력의 대상을 다양하게 선택할 수 있는 유연성을 제공한다. </p>
</li>
<li><p>객체가 수행하는 책임들이 자율적일수록 객체의 역할을 이해하기 쉬워진다. </p>
<ul>
<li>객체가 수행하는 책임들이 자율적일수록 객체의 존재 이유를 명확하게 표현할 수 있다. 객체는 동일한 목적을 달성하는 강하게 연관된 책임으로 구성되기 때문이다. 책임이 자율적일수록 객체의 응집도를 높은 상태로 유지하기가 쉬워진다. </li>
</ul>
</li>
</ul>
<h4 id="요약">요약</h4>
<ul>
<li>책임이 자율적일수록 적절하게 축상화되며, 응집도가 높아지고, 결합도가 낮아지며, 캡슐화가 증진되고, 인터페이스와 구현이 명확히 분리되며, 설계의 유연성과 재사용성이 향상된다. </li>
</ul>
<h3 id="12-기능-설계-vs-구조-설계">12. 기능 설계 vs 구조 설계</h3>
<ul>
<li><p>길을 모른다고 가정했을 때, 사람들에게 길을 물어 찾아가는 방법은 <strong>기능적이고 해결 방법 지향적인 접근법</strong>이라면 지도를 이용하는 방법은 <strong>구조적이고 문제 지향적인 접근법</strong>이다. </p>
</li>
<li><p>사람들의 요구사항은 계속 변하기 때문에 모델이 제공해야 하는 기능 역시 이에 따라 변하게 된다. 따라서 기능을 중심으로 구조를 종속시키는 접근법은 범용적이지 않고 재사용이 불가능하며 변경에 취약한 모델을 낳게 된다. </p>
</li>
<li><p>이와 달리 안정적인 구조를 중심으로 기능을 종속시키는 접근법은 범용적이고 재사용 가능하며 변경에 유연하게 대처할 수 있는 모델을 만든다. </p>
</li>
<li><p>전통적인 소프트웨어 개발 방법은 변경이 빈번하게 발생하는 기능에 안정적인 구조를 종속시키는 길을 묻는 방법과 유사하다. 반면에 객체지향 개발 방법은 안정적인 구조에 변경이 빈번하게 발생하는 기능을 종속시키는 지도의 방법이다. 즉, 객체지향은 자주 변경되는 기능이 아니라 안정적인 구조를 기반으로 시스템을 구조화한다. </p>
</li>
</ul>
<h4 id="기능과-구조">기능과 구조</h4>
<ul>
<li><p>구조는 사용자나 이해관계자들이 도메인에 관해 생각하는 개념과 개념들 간의 관계로 표현한다. </p>
</li>
<li><p>기능은 사용자의 목표를 만족시키기 위해 책임을 수행하는 시스템의 행위로 표현한다. </p>
</li>
<li><p>일반적으로 기능을 수집하고 표현하기 위한 기법을 <strong>유스케이스 모델링</strong>이라고 하고 구조를 수집하고 표현하기 위한 기법을 <strong>도메인 모델링</strong> 이라고 한다. 두 가지 모델링 활동의 결과물을 각각 유스케이스와 도메인 모델이라고 한다. </p>
</li>
</ul>
<h3 id="13-도메인-모델">13. 도메인 모델</h3>
<ul>
<li><p>소프트웨어를 사용하는 사람들은 자신이 관심을 가지고 있는 특정한 분야의 문제를 해결하기 위해 소프트웨어를 사용한다. 이처럼 사용자가 프로그램을 사용하는 대상 분야를 도메인이라고 한다. </p>
</li>
<li><p>도메인 모델이란 사용자가 프로그램을 사용하는 대상 영역에 대한 지식을 선택적으로 단순화하고 의식적으로 구조화한 형태다. 도메인 모델은 소프트웨어 개발과 관련된 이해관계자들이 도메인에 대해 생각하는 관점이다. </p>
</li>
<li><p>은행 업무에 종사하는 살마들은 은행 도메인을 고객과 계좌 사이의 돈의 흐름으로 이해할 것이다. 게임 플레이어들은 게임 도메인을 캐릭터와 몬스터 그리고 몬스터가 떨구는 아이템 관의 관계로 파악한다. 소프트웨어의 도메인이 무엇이든 상관없이 그곳에는 항상 도메인과 관련된 사람들이 도메인을 바라보는 모델이 존재한다. </p>
</li>
<li><p>도메인 모델은 이해관계자들이 바라보는 멘탈 모델이다. 멘탈 모델이란 사람들이 자기 자신, 다른 사람, 환경, 자신이 상호작용하는 사물들에 대해 갖는 모형이다. </p>
</li>
<li><p>도널드 노먼은 제품을 설계할 때 제품에 관한 모든 것이 사용자들이 제품에 대해 가지고 있는 멘탈 모델과 정확하게 일치해야 한다고 주장한다. 사용자들은 자신의 멘탈 모델과 유사한 방식으로 제품이 반응하고 움직일 것이라고 기대하기 때문에 훌륭한 디자인이란 사용자가 예상하는 방식에 따라 정확하게 반응하는 제품을 만드는 것이다. </p>
</li>
<li><p>노먼은 멘탈 모델을 사용자 모델, 디자인 모델, 시스템 이미지의 세 가지로 구분한다. 사용자 모델은 사용자가 제품에 대해 가지고 있는 개념들의 모습이다. 디자인 모델은 설계자가 마음 속에 갖고 있는 시스템에 대한 개념화다. 시스템 이미지는 최종 제품이다. </p>
</li>
<li><p>사용자의 모델과 디자인 모델이 동일하다면 이상적이겠지만 사용자와 설계자는 직접적으로 상호작용할 수 없으며 단지 최종 제품인 시스템 그 자체를 통해서만 의사소통할 수 있다. 따라서 설계자는 디자인 모델을 기반으로 만든 시스템 이미지가 사용자 모델을 정확하게 반영하도록 노력해야 한다.</p>
</li>
<li><p>도메인 모델은 도메인에 대한 사용자 모델, 디자인 모델, 시스템 이미지를 포괄하도록 추상화한 소프트웨어 모델이다. 따라서 도메인 모델은 소프트웨어에 대한 멘탈 모델이다. </p>
</li>
<li><p>객체지향을 사용하면 사용자들이 이해하고 있는 도메인의 구조와 최대한 유사하게 코드를 구조화할 수 있다. 동적인 객체가 가진 복잡성을 극복하기 위해 정적인 타입을 이용해 세상을 단순화할 수 있으며, 클래스라는 도구를 이용해 타입을 코드 안으로 옴길 수 있다. </p>
</li>
</ul>
<h4 id="표현적-차이">표현적 차이</h4>
<ul>
<li><p>소프트웨어 객체와 현실 객체 사이의 의미적 거리를 가리켜 표현적 차이 또는 의미적 차이라고 한다. 핵심은 은유를 통해 현식 객체와 소프트웨어 객체 사이의 차이를 최대한 줄이는 것이다. </p>
</li>
<li><p>은유를 통해 투영해야 하는 대상은, 사용자가 도메인에 대해 생각하는 개념들이다. 즉, 소프트웨어 객체를 창조하기 위해 우리가 은유해야 하는 대상은 도메인 모델이다. </p>
</li>
<li><p>표현적 차이가 중요한 이유는 소프트에어를 이해하고 쉽게 만들어주기 때문에 코드의 구조가 도메인의 구조를 반영하기 때문에 도메인을 이해하면 코드를 이해하면 코드를 이해하기가 훨씬 수월해진다. </p>
</li>
<li><p>도메인 모델을 기반으로 코드를 작성하는 이유는 도메인 모델이 제공하는 구조가 상대적으로 안정적이기 때문이다. 사용자 모델에 포함된 개념과 규칙은 비교적 변경될 확률이 적기 때문에 사용자 모델을 기반으로 설계와 코드를 만들면 변경에 쉽게 대처할 수 있는 가능성이 커진다. </p>
</li>
</ul>
<h3 id="14-유스케이스">14. 유스케이스</h3>
<ul>
<li><p>사용자의 목표를 달성하기 위해 사용자와 시스템 간에 이뤄지는 상호작용의 흐름을 텍스트로 정리한 것을 유스케이스라고 한다. </p>
</li>
<li><p>유스케이스의 가치는 사용자들의 목표를 중심으로 시스템의 기능적인 요구사항들을 이야기 형식으로 묶릉 수 있다는 점이다. 산발적으로 흩어져 있는 기능에 사용자 목표라는 문맥을 제공함으로써 각 기능이 유기적인 관계를 지닌 체계를 이룰 수 있게 한다. </p>
</li>
<li><p>유스케이스는 사용자와 시스템 간의 상호작용을 보여주는 텍스트다. 유스케이스는 다이어그램이 아니다. 중요한 것은 유스케이스 안에 포함돼 있는 상호작용의 흐름이다. </p>
</li>
<li><p>유스케이스는 하난의 시나리오가 아닌 여러 시나리오들의 집합이다. 시나리오들을 유스케이스 인스턴스라고도 한다. </p>
</li>
<li><p>유스케이스는 단순한 피처(feature)목록과 다르다. 피처는 시스템이 수행해야 하는 기능의 목록을 단순하게 나열한 것이다. 피처의 단점은 두 피처를 연관이 없는 독립적인 기능으로 보이게끔 만든다는 점이다. 유스케이스는 단순히 기능을 나열하는 것이 아니라 이야기를 통해 연관된 기능들을 함께 묶을 수 있다는 점이다.</p>
</li>
<li><p>유스케이스는 사용자 인터페이스와 관련된 세부 정보를 포함하지 말아야 한다. </p>
</li>
<li><p>유스케이스는 내부 설계와 관련된 정보를 포함하지 않는다. 유스케이스는 시스템의 내부 구조나 실행 매커니즘에 관한 어떤 정보도 제공하지 않는다. 유스케이스에는 단지 사용자가 시스템을 통해 무엇을 얻을 수 있고 어떻게 상호작용할 수 있느냐에 관한 정보만 기술된다. </p>
</li>
<li><p>유스케이스는 객체의 구조나 책임에 대한 어떤 정보도 제공하지 않는다. 유스케이스 안에 도메인 모델을 구축할 수 있는 모든 정보가 포함돼 있다는 착각에 빠지지 말아야 한다. </p>
</li>
</ul>
<h3 id="15-기능과-구조의-통합">15. 기능과 구조의 통합</h3>
<ul>
<li><p>변경에 유연한 소프트웨어를 만들기 위해서는 유스케이스에 정리된 시스템의 기능을 도메인 모델을 기반으로 한 객체들의 책임으로 분배해야 한다.</p>
</li>
<li><p>협력의 출발은 시스템의 기능을 시스템의 책임으로 바꾸는 것이다. </p>
</li>
<li><p>시스템에 할당된 커다란 책임은 시스템 안의 작은 규모의 객체들이 수행해야 하는 더 작은 규모의 책임으로 세분화된다.</p>
</li>
<li><p>객체를 선택할 때 도메인 모델이 등장한다. 우리는 도메인 모델에 포함된 개념을 은유하는 소프트웨어 객체를 선택해야 한다. 이것은 소프트웨어와 코드 사이의 표현적 차이를 줄이는 첫걸음이다. </p>
</li>
<li><p>협력을 완성하는 데 필요한 메시지를 식별하면서 객체들에게 책임을 할당해 나간다.</p>
</li>
<li><p>마지막으로 협력에 참여하는 객체를 구현하기 위해 클래스를 추가하고 속성과 함께 메서드를 구현하면 시스템의 기능이 완성된다. 이제 코드는 불안정한 기능을 수용할 수 있는 안정적인 구조에 기반한다. </p>
</li>
<li><p>안정적인 도메인 모델을 기반으로 시스템의 기능을 구현하고, 도메인 모델과 코드를 밀접하게 연관시키기 위해 노력하는 것이 유지보수하기 십고 유연한 객체지향 시스템을 만드는 방법이다. </p>
</li>
</ul>
<h3 id="16-객체-지향-설계-안의-세-가지-관점">16. 객체 지향 설계 안의 세 가지 관점</h3>
<ul>
<li><p>개념 관점에서 설계는 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현한다. 이 관점은 사용자가 도메인을 바라보는 관점을 반영한다. 따라서 실제 도메인의 규칙과 제약을 최대한 유사하게 반영하는 것이 핵심이다.</p>
</li>
<li><p>커피를 제조하는 과정을 변경해야 한다면 소프트웨어 안에서도 Barista라는 클래스가 커페를 제조할 것이라고 쉽게 유추할 수 있다. 소프트웨어 클래스와 도메인 클래스 사이의 간격이 좁으면 좁을수록 기능을 변경하기 위해 뒤적거려야 하는 코드의 양도 점점 줄어든다. </p>
</li>
<li><p>명세 관점은 도메인의 개념이 아니라 실제로 소프트에어 안에서 살아 숨쉬는 객체들의 책임에 초점을 맞추게 된다. 즉, 객체의 인터페이스를 바라보게 된다. 명세 관점에서 프로그래머는 객체가 협력을 위해 무엇을 할 수 있는가에 초점을 맞춘다.</p>
</li>
<li><p>최대한 변화에 안정적인 인터페이스를 만들기 위해서는 인터페이스를 통해 구현과 관련된 세부 사항이 드러나지 않게 해야 한다. </p>
</li>
<li><p>구현 관점의 초점은 객체들이 책임을 수행하느 데 필요한 동작하는 코드를 작성하는 것이다. 따라서 프로그래머는 객체의 책임을 어떻게 수행할 것인가에 초점을 맞추며 인터페이스를 구현하는데 필요한 속성과 메서드를 클래스에 추가한다. </p>
</li>
<li><p>클래스의 메서드와 속성은 구현에 속하며 공용 인터페이스의 일부가 아니다. 따라서 메서드와 속성이 철저하게 클래스 내부로 캡슐화돼야 한다는 것을 의미한다. </p>
</li>
<li><p>다른 사람들이 여러분의 코드를 읽으면서 세 가지 관점을 쉽게 포착하지 못한다면 세 가지 관점이 명확하게 드러날 수 있게 코드를 개선하라. 그것이 변경에 유연하게 대응할 수 있는 객체지향 코드를 작성하는 가장 빠른 길이다. </p>
</li>
</ul>
<hr>
<p>이 글을 읽는 사람이 있기나 할까? 최대한 줄이고 줄였는데도 이 정도다. 하여튼 나는 정리하면서 다시 책을 꼼꼼히 읽었기 때문에 이제야 머리에 정리가 되는 기분이다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[겹치는 선분의 길이]]></title>
            <link>https://velog.io/@ge-um/%EA%B2%B9%EC%B9%98%EB%8A%94-%EC%84%A0%EB%B6%84%EC%9D%98-%EA%B8%B8%EC%9D%B4</link>
            <guid>https://velog.io/@ge-um/%EA%B2%B9%EC%B9%98%EB%8A%94-%EC%84%A0%EB%B6%84%EC%9D%98-%EA%B8%B8%EC%9D%B4</guid>
            <pubDate>Sat, 14 Jan 2023 08:48:11 GMT</pubDate>
            <description><![CDATA[<p>선분 3개가 평행하게 놓여 있습니다. 세 선분의 시작과 끝 좌표가 [[start, end], [start, end], [start, end]] 형태로 들어있는 2차원 배열 lines가 매개변수로 주어질 때, 두 개 이상의 선분이 겹치는 부분의 길이를 return 하도록 solution 함수를 완성해보세요.</p>
<p>lines가 [[0, 2], [-3, -1], [-2, 1]]일 때 그림으로 나타내면 다음과 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/ge-um/post/215cf228-1d4f-4974-8493-553c24a9be54/image.png" alt=""></p>
<p>선분이 두 개 이상 겹친 곳은 [-2, -1], [0, 1]로 길이 2만큼 겹쳐있습니다.</p>
<h4 id="제한사항">제한사항</h4>
<ul>
<li>lines의 길이 = 3</li>
<li>lines의 원소의 길이 = 2</li>
<li>모든 선분은 길이가 1 이상입니다.</li>
<li>lines의 원소는 [a, b] 형태이며, a, b는 각각 선분의 양 끝점 입니다.</li>
<li>-100 ≤ a &lt; b ≤ 100</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>lines|result
|:-:|:-:|
[[0, 1], [2, 5], [3, 9]]|2
[[-1, 1], [1, 3], [3, 9]]|0
[[0, 5], [3, 9], [1, 10]]|8</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1</p>
<p>두 번째, 세 번째 선분 [2, 5], [3, 9]가 [3, 5] 구간에 겹쳐있으므로 2를 return 합니다.</p>
<p>입출력 예 #2</p>
<p>겹친 선분이 없으므로 0을 return 합니다.</p>
<p>입출력 예 #3</p>
<p>첫 번째와 두 번째 선분이 [3, 5] 구간에서 겹칩니다.
첫 번째와 세 번째 선분 [1, 5] 구간에서 겹칩니다.
두 번째와 세 번째 선분 [3, 9] 구간에서 겹칩니다.
따라서 [1, 9] 구간에 두 개 이상의 선분이 겹쳐있으므로, 8을 return 합니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(lines) {
    const start = lines.map(v =&gt; v[0]);
    const end = lines.map(v =&gt; v[1]);

    let count = 0;
    let intersection = 0;

    for(let i = Math.min(...start); i &lt;= Math.max(...end); i++){
        for(let j = 0; j &lt; lines.length; j++){
            if(i &gt;= start[j] &amp;&amp; i &lt; end[j]){
                count++
            }
        }
        if(count &gt;= 2){
            intersection++
        }
        count = 0;
    }

    return intersection
}</code></pre>
<p>2차원 배열의 앞쪽 값이 시작값, 뒤쪽 값이 종료값이기 때문에 시작값과 종료값을 각각 다른 배열로 분리시켜 주었다. 시작값의 최소값이 가장 작은 값, 종료값의 최대값이 가장 큰 값일 것이기 때문에 그 값들을 각각 검사해 주었다. 만일 그 값이 다른 선분과 비교했을 때 겹치는 값이라면 count값을 증가시켜 주었다. 이를 통해 각 점에서 선분이 겹치는 개수를 셀 수 있다. 최종적으로 count가 2이상이라면 intersection 값을 증가시켜 주었고, intersection 값을 return해 주었다. </p>
<p>가장 큰 고민은 depth가 3까지 늘어난다는 점이었다. 이렇게 for과 if를 중첩시키면 가독성이 너무 떨어져서 고민이 많이 되었는데, 이 방법으로는 중첩을 줄일 방법이 생각이 나질 않았다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(lines) {
    let line = new Array(200).fill(0);

    lines.forEach(([a, b]) =&gt; {
        for(; a &lt; b; a++) line[a+100]++;
    });

    return line.reduce((a, c) =&gt;  c &gt; 1 ? a + 1 : a, 0)
}</code></pre>
<p>이 풀이는 line이라는 0으로 채워진 새로운 배열을 만들어 준 다음, lines 범위에 해당한다면 값을 각각 1씩 증가시켜 주었다. line[a+100]의 값을 증가시켜준 이유는, lines에 음수의 값도 존재하기 때문이다. 그리고 reduce를 이용해서 값이 1보다 크다면 1을 더해 전체 겹치는 부분의 합을 계산해 주었다. reduce 이외에도 filter을 사용해서 풀 수도 있을 듯 하다. 직관적이고, 무엇보다도 depth 문제를 해결해준 풀이라 참고할 만하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[다항식 더하기]]></title>
            <link>https://velog.io/@ge-um/%EB%8B%A4%ED%95%AD%EC%8B%9D-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ge-um/%EB%8B%A4%ED%95%AD%EC%8B%9D-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 13 Jan 2023 13:40:39 GMT</pubDate>
            <description><![CDATA[<p>한 개 이상의 항의 합으로 이루어진 식을 다항식이라고 합니다. 다항식을 계산할 때는 동류항끼리 계산해 정리합니다. 덧셈으로 이루어진 다항식 polynomial이 매개변수로 주어질 때, 동류항끼리 더한 결괏값을 문자열로 return 하도록 solution 함수를 완성해보세요. 같은 식이라면 가장 짧은 수식을 return 합니다.</p>
<h4 id="제한사항">제한사항</h4>
<ul>
<li><p>0 &lt; polynomial에 있는 수 &lt; 100</p>
</li>
<li><p>polynomial에 변수는 &#39;x&#39;만 존재합니다.</p>
</li>
<li><p>polynomial은 0부터 9까지의 정수, 공백, ‘x’, ‘+&#39;로 이루어져 있습니다.</p>
</li>
<li><p>항과 연산기호 사이에는 항상 공백이 존재합니다.</p>
</li>
<li><p>공백은 연속되지 않으며 시작이나 끝에는 공백이 없습니다.</p>
</li>
<li><p>하나의 항에서 변수가 숫자 앞에 오는 경우는 없습니다.</p>
</li>
<li><p>&quot; + 3xx + + x7 + &quot;와 같은 잘못된 입력은 주어지지 않습니다.</p>
</li>
<li><p>&quot;012x + 001&quot;처럼 0을 제외하고는 0으로 시작하는 수는 없습니다.</p>
</li>
<li><p>문자와 숫자 사이의 곱하기는 생략합니다.</p>
</li>
<li><p>polynomial에는 일차 항과 상수항만 존재합니다.</p>
</li>
<li><p>계수 1은 생략합니다.</p>
</li>
<li><p>결괏값에 상수항은 마지막에 둡니다.</p>
</li>
<li><p>0 &lt; polynomial의 길이 &lt; 50</p>
</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>polynomial|result
|:-:|:-:|
&quot;3x + 7 + x&quot;|&quot;4x + 7&quot;
&quot;x + x + x&quot;|&quot;3x&quot;</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1</p>
<ul>
<li>&quot;3x + 7 + x&quot;에서 동류항끼리 더하면 &quot;4x + 7&quot;입니다.</li>
</ul>
<p>입출력 예 #2</p>
<ul>
<li>&quot;x + x + x&quot;에서 동류항끼리 더하면 &quot;3x&quot;입니다.</li>
</ul>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(polynomial) {
    const terms = polynomial.split(&#39; + &#39;);
    let xCoeff = 0;
    let constant = 0;

    terms.forEach(term =&gt; {
        if(term.includes(&#39;x&#39;)){
            xCoeff += term.match(/\d+/) * 1||1 ;
        }
        else{
            constant += term * 1;
        }
    });

    if(xCoeff === 0 &amp; constant === 0){
        return &#39;&#39;;
    }
    if(xCoeff === 1 &amp; constant &gt; 0){
        return `x + ${constant}`
    }
    if(xCoeff === 1 &amp; constant === 0){
        return &#39;x&#39;;
    }
    if(xCoeff &gt; 1 &amp; constant === 0){
        return `${xCoeff}x`
    }
    if(xCoeff === 0 &amp; constant &gt; 0){
        return `${constant}`
    }
    return `${xCoeff}x + ${constant}`
}</code></pre>
<p>다항식을 +로 나누어 배열에 넣어준 다음, 배열을 돌아가며 x항과 상수항을 따로따로 더해 주었다. 그리고 더한 값을 출력해 주었다. 출력 부분에서는 많은 고민이 있었는데, 그냥 경우를 하나하나 적어 주는 편이 가독성 측면에서 나을 것 같아 if문을 활용해 각각 리턴해 주었다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(polynomial) {
    const arr = polynomial.split(&quot; + &quot;);
    const xNum = arr
                .filter(n =&gt; n.includes(&quot;x&quot;))
                .map(n =&gt; n.replace(&#39;x&#39;, &#39;&#39;) || &#39;1&#39;)
                .reduce((acc, cur) =&gt; acc + parseInt(cur, 10), 0);
    const num = arr
                .filter(n =&gt; !isNaN(n))
                .reduce((acc, cur) =&gt; acc + parseInt(cur, 10), 0);

    let answer = [];
    if(xNum) answer.push(`${xNum === 1 ? &quot;&quot; : xNum}x`);
    if(num) answer.push(num);

    return answer.join(&quot; + &quot;);
}</code></pre>
<p>출력 부분에서 배울 점이 있었다. 빈 배열을 만들어준 후 x항이 존재하면 x항의 계수를 배열에 담아주고, 상수항이 존재하면 상수를 배열에 담아준 다음 join으로 두 값을 합쳐준다. 내가 한 방식보다 훨씬 간결하고 쉬운 방식이라는 생각이 든다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[저주의 숫자 3]]></title>
            <link>https://velog.io/@ge-um/%EC%A0%80%EC%A3%BC%EC%9D%98-%EC%88%AB%EC%9E%90-3</link>
            <guid>https://velog.io/@ge-um/%EC%A0%80%EC%A3%BC%EC%9D%98-%EC%88%AB%EC%9E%90-3</guid>
            <pubDate>Thu, 12 Jan 2023 14:22:36 GMT</pubDate>
            <description><![CDATA[<p>3x 마을 사람들은 3을 저주의 숫자라고 생각하기 때문에 3의 배수와 숫자 3을 사용하지 않습니다. 3x 마을 사람들의 숫자는 다음과 같습니다.</p>
<p>10진법|3x 마을에서 쓰는 숫자|10진법|3x 마을에서 쓰는 숫자
|:-:|:-:|:-:|:-:|
1|1|6|8
2|2|7|10
3|4|8|11
4|5|9|14
5|7|10|16
정수 n이 매개변수로 주어질 때, n을 3x 마을에서 사용하는 숫자로 바꿔 return하도록 solution 함수를 완성해주세요.</p>
<h4 id="제한사항">제한사항</h4>
<p>1 ≤ n ≤ 100</p>
<h4 id="입출력-예">입출력 예</h4>
<p>n|result
|:-:|:-:|
15|25
40|76</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1</p>
<p>15를 3x 마을의 숫자로 변환하면 25입니다.
입출력 예 #2</p>
<p>40을 3x 마을의 숫자로 변환하면 76입니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(n) {
    let noThree = Array(n*2).fill()
                            .map((v,i) =&gt; i+1)
                            .filter(v =&gt; v % 3 !== 0 &amp;&amp; !(v+(&#39;&#39;)).includes(&#39;3&#39;))
    return noThree[n-1]
}</code></pre>
<p>숫자를 증가시켜 가며 n번 반복할 방법이 생각나질 않아서 애초에 1씩 증가하는 숫자를 담은 배열을 만든 뒤, 조건에 맞지 않는 값을 필터해 주었다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(n) {
    let arr = [];
    let num = 0;
    while (arr.length !== n &amp;&amp; ++num) {
        if (num%3!==0 &amp;&amp; !(&#39;&#39;+num).includes(&#39;3&#39;))
            arr.push(num)
    };
    return arr.pop();
}</code></pre>
<p>특이한 점이라면 값 증가를 while문 조건에서 해 주었다. while문 조건에 쓰는 대신 if 앞부분에 num++이라고 적어 주어도 동일하게 작동한다. 값을 배열에 넣어 준 다음, 값의 길이가 n이 될 때까지 반복해 주었다. 그리고 배열의 마지막 값을 추출해 3x 숫자를 추출해 주었다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[개발 도서 리뷰] 함께 자라기 애자일로 가는 길]]></title>
            <link>https://velog.io/@ge-um/%ED%95%A8%EA%BB%98-%EC%9E%90%EB%9D%BC%EA%B8%B0-%EC%95%A0%EC%9E%90%EC%9D%BC%EB%A1%9C-%EA%B0%80%EB%8A%94-%EA%B8%B8</link>
            <guid>https://velog.io/@ge-um/%ED%95%A8%EA%BB%98-%EC%9E%90%EB%9D%BC%EA%B8%B0-%EC%95%A0%EC%9E%90%EC%9D%BC%EB%A1%9C-%EA%B0%80%EB%8A%94-%EA%B8%B8</guid>
            <pubDate>Mon, 09 Jan 2023 16:58:59 GMT</pubDate>
            <description><![CDATA[<p>이 글은 함께 자라기 애자일로 가는 길을 읽고 쓴 내용입니다. </p>
<p>아무래도 많이 들어본 책이라 그런지 내용도 많이 들어봤던 것 같았다. 부제가 애자일로 가는 길이지만 애자일에 관한 내용은 그리 많지 않았다. </p>
<h3 id="1-자라기">1. 자라기</h3>
<p>의도적 수련을 위해서 자신이 하는 일을 적절한 난이도로 바꾸는 것을 제안하고 있다. 만약 난이도가 높다면 업무를 쪼개어 난이도를 낮추거나, 자신이 필요한 부분을 학습하여 난이도를 낮출 수 있다. 난이도가 낮다면 의도적으로 난이도를 높게 만들거나 자신에게 제약을 주는 식으로 몰입을 할 수 있도록 만들라고 이야기 한다. 이 부분은 잘 알고 있는 부분이지만 막상 하다보면 실천하기 어려운 부분이다. </p>
<p>또한 피드백을 잘 받을 수 있는 구조, 메타인지, 실수를 배울 수 있는 기회로 여기기 등에 대해 이야기한다. </p>
<p>프로그래밍 언어를 배우는 비결도 몇 가지 소개되어 있다. </p>
<ul>
<li>튜토리얼을 읽을 때 뭘 만들지 생각하며 읽는다</li>
<li>공부할 때 표준 라이브러리 소스를 읽는다</li>
<li>공부 중 다른 사람의 코드에 내가 필요한 기능을 추가한다. </li>
</ul>
<p>뭘 만들지 생각하며 읽는다거나, 다른 사람의 코드에 내가 필요한 기능을 추가하는 일은 좀 어렵다고 생각해서 할 수 있을지 모르겠지만, 표준 라이브러리 소스에 대해서는 처음 들어 보았다. 그것도 다음에 한 번 읽어 보고 효과에 대해 생각해 봐야겠다. </p>
<p>전문가에게 질문을 하는 방법도 소개되어 있다. 전문가를 만나고, 구체적인 사건에 대해서 물어보는 것이다. 그래서 구체적인 생각들을 물어보는 것이 좋다고 한다. </p>
<h3 id="2-함께">2. 함께</h3>
<p>애자일을 도입하기 위해서 다른 사람을 설득하는 방법에 대해서는 공감이 많이 되었다. 보통 애자일을 팀원들에게 소개하기 위해서 객관적인 정보를 많이 모아가지만, 실제로 판단하는 사람은 주관적이기 때문에 객관적인 자료를 아무리 모아도 설득하기 어렵다. 나도 그런 경험이 꽤나 있기 때문에, 그 사람에 대해서 알아가는 것이 필요하다는 것에 공감이 많이 되었다. </p>
<p>코칭에 대해서 이야기하는 부분도 나오는데, 뭔가 심리 상담이랑 비슷한 것 같기도 하다는 생각이 들었다. 결국 구체적인 생각을 물어보고, 공감해주고 제안을 한다는 점에서 비슷한 듯하다. </p>
<p>성공적인 팀을 위해서는 심리적 안전감이 중요하다는 것에도 많은 공감이 되었다. 생각해보니 실패하는 팀의 사례를 전부 겪어본 것 같다. 팀에서 의견을 나눌 때는 서로 비난하는 분위기가 되지 않도록 하고, 발언을 격려하는 것이 중요하다는 생각이 들었다. </p>
<h3 id="3-애자일">3. 애자일</h3>
<p>애자일 실천법 중 도입해서 성과가 있는 항목은 고객 참여, 리팩토링, 코딩 후 자동화 테스트 붙이기, 코드 공유이다. 특히 애자일 성숙도가 낮은 팀에서는 고객 참여가 가장 중요하고 성숙도가 높은 팀에게는 짧은 반복 개발 주기, 고객 참여, 코드 공유에 신경을 써야 한다고 말한다. </p>
<hr>
<p>여러가지 방법들을 제시하지만, 필자는 어떤 방법론보다 자신을 탐색하고 주변을 살펴보며, 그에 맞는 방법을 찾는 게 중요하다고 말한다. 메타인지와 비슷한 개념인 것 같다. </p>
<p>여러 가지 방법을 여러 객관적 근거를 들어 주장하지만, 이러한 방법을 무작정 도입하기보다는 자신과 주변을 잘 관찰하라고 말하는 역설적인 책인 것 같다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[개발 도서 리뷰 ] 테스트 주도 개발 1]]></title>
            <link>https://velog.io/@ge-um/%EC%BC%84%ED%8A%B8-%EB%B0%B1%EC%9D%98-TDD-1%EB%B6%80-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C</link>
            <guid>https://velog.io/@ge-um/%EC%BC%84%ED%8A%B8-%EB%B0%B1%EC%9D%98-TDD-1%EB%B6%80-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C</guid>
            <pubDate>Mon, 09 Jan 2023 12:33:59 GMT</pubDate>
            <description><![CDATA[<p>이 글은 켄트 백의 테스트 주도 개발을 읽고 쓴 내용입니다. </p>
<p>우테코 프리코스를 진행하면서 가장 어려웠던 부분은 TDD였다. jest에 대해서 잘 모르니까 테스트 코드 자체를 작성하는 것도 어려웠고 특히나 테스트 코드를 어느 정도 짜야 하는지 감이 오지 않았다. 그래서 구체적인 테스트 코드를 짜는 방법에 대해 궁금해졌고, 이 책을 읽게 되었다. 내가 테스트 코드를 짰던 경험을 바탕으로 인상 깊었던 부분을 간략하게 정리해 보려고 한다. 1부만 정리하는 이유는 내가 자바를 잘 몰라서 속도가 잘 안나고 😓 이러다 결국 안 쓸까봐 나눠서 정리한다. </p>
<hr>
<h3 id="1-테스트-코드-실행-주기">1. 테스트 코드 실행 주기</h3>
<p>저자가 테스트 코드를 실행하는 주기를 기록했는데, 약 1분에 한 번 정도 테스트를 실행했다고 한다. 프로그래밍에 익숙한 사람이라 속도가 빠른 것도 있겠지만, 피드백 주기를 이정도로 짧게 하기 위해서 할 일 목록을 엄청 세분화했구나 싶었다. </p>
<h3 id="2-할일-목록-만들기">2. 할일 목록 만들기</h3>
<p>나는 기능 목록을 만들었기 때문에 기능 단위로 테스트를 만들고 구현하려고 노력하였다. 하지만 저자는 </p>
<ul>
<li>85 + 10CHF = $10(환율이 2:1일 경우)</li>
<li>$5 × 2 = $10</li>
<li>amount를 private로 만들기</li>
<li>Dollar 부작용(side effect)?</li>
<li>Money 반올림? </li>
</ul>
<p>기능 목록을 조금 더 세분화한 다음, 해결하기 쉬운 것부터 조금씩 해결해 나간다. 나는 도메인 로직이 중요하다고 생각해 그것부터 붙잡고 해결하려고 했는데, 시간이 많이 들었던 원인인 듯 하다. </p>
<h3 id="3-가짜로-구현하기">3. 가짜로 구현하기</h3>
<p>TDD의 기초는 테스트를 작성하고, 실행 가능하게 만든 뒤 올바르게 만드는 것이라고 한다. 나는 이 실행 가능하게 만든다는 부분을 어찌되었든 기능 목록에서 요구하는 것에 맞게 제대로 작동하게 만들려고 노력했기 때문에 시간이 많이 걸렸다. 하지만 저자가 말하는 방법은 가짜로 상수를 넣어서라도 돌아가게 만든 뒤 점점 일반화하는 것이다. </p>
<p>예를 들어, </p>
<pre><code class="language-java">public void testMultiplication () {
  Dollar five= new Dollar (5);
  five.times (2);
  assertEquals (10, five.amount);
}</code></pre>
<p>위의 테스트를 통과하기 위해서 간단히 아래의 테스트를 작성하였다. </p>
<pre><code class="language-java">//Dollar 

int amount;

void times (int multiplier) {
  amount = 5 * 2;
}</code></pre>
<p>원래는 인수를 받아서 인수만큼 곱하는 것이지만, 그냥 5 * 2라는 상수를 반환시켜서 테스트를 통과시켰다. 이것을 조금씩 일반화하는 것이다.</p>
<h3 id="4-명백하게-구현하기">4. 명백하게 구현하기</h3>
<p>이 방법은 내가 여태까지 했던 방법으로, 그냥 쉽게 일반화할 수 있는 방법이 떠오르면 바로 일반화하여 테스트를 통과하게 만드는 것이다. 저자는 가짜로 구현하기와 명백하게 구현하기를 상황에 맞게 사용하라고 알려 준다. 자신이 어떻게 구현할 지 확신이 든다면 바로 일반화하여 테스트를 통과한다. 어떻게 할 지 방법이 떠오르지 않는다면 가짜로 구현하기와 삼각측량법을 이용한다.  </p>
<h3 id="5-삼각측량법">5. 삼각측량법</h3>
<blockquote>
<p>만약 라디오 신호를 두 수신국이 감지하고 있을 때, 수신국 사이의 거리가 알려져 있고 각 수신국이 신호의 방향을 알고 있다면, 이 정보들만으로 충분히 신호의 거리와 방위를 알 수 있다(당신이 나보다 삼각법에 대해 더 잘 기억하고 있다면). 이 계산법을 삼각측량이라고 한다.</p>
</blockquote>
<p>말이 어렵지만 일반화하는 방법이라고 생각한다. </p>
<p>우리가 5달러라는 객체를 만들 때, 5달러 객체는 여러 번 만들어도 똑같이 5달러여야 한다. 따라서 이 테스트 코드를 통과해야 한다. </p>
<pre><code class="language-java">public void testEquality () {
assertTrue (new Dollar (5) .equals(new Dollar (5)));
}</code></pre>
<p>이 테스트 코드를 통과하기 위해서라면 Dollar 객체에서 상수를 반환해도 테스트 코드를 통과할 수 있다. </p>
<p>하지만 실제 세계에서, 5달러는 6달러와는 다르다. 따라서 아래의 테스트 코드도 통과해야 한다. </p>
<pre><code class="language-java">public void testEquality () {
assertFalse (new Dollar (5) .equals(new Dollar (6)));
}</code></pre>
<p>이 두 가지의 테스트 코드를 통과하기 위해서 일반화를 하면, 결국 일반화된 코드가 나온다. 저자는 오로지 예가 두 가지 이상일 때만 추상화를 하라고 제안한다. </p>
<h3 id="6-중복-제거하기">6. 중복 제거하기</h3>
<p>이런 식으로 진행하다 보면 테스트코드와 코드 사이에 중복이 생기게 된다. 예시가 너무 복잡해서 들고 오지는 않았지만, 그 중복을 제거해나가다 보면 코드가 완성된다. </p>
<hr>
<p>이 이후부터는 계속해서 우리가 보통 알고 있는 테스트 추가 -&gt; 테스트가 실패하도록 만들기 -&gt; 수정 -&gt; 테스트 성공 확인 -&gt; 중복 제거를 위한 리팩토링의 TDD 과정의 연속이다. 실제 TDD 과정을 확인해보고 싶었는데, 좋은 참고가 되었다. </p>
<p>TDD 과정을 보다보니 할 일 쪼개서 능률을 높이는 방법이랑도 유사하다. 이걸 실제 생활에 적용해 봐도 효율을 늘릴수 있겠다 싶다. </p>
<p>이론상으로 참고할 부분이 생겼으니 앞으로는 실제로 적용해볼 차례이다! TDD의 적용 사례에 대해서도 쓸 수 있었으면 좋겠다 😁</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[개발 도서 리뷰] 소프트웨어 장인]]></title>
            <link>https://velog.io/@ge-um/%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%84%9C-%EB%A6%AC%EB%B7%B0-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EC%9E%A5%EC%9D%B8</link>
            <guid>https://velog.io/@ge-um/%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%84%9C-%EB%A6%AC%EB%B7%B0-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EC%9E%A5%EC%9D%B8</guid>
            <pubDate>Fri, 16 Dec 2022 16:11:27 GMT</pubDate>
            <description><![CDATA[<p>첫 부분엔 개발자로서의 열정을 강조해서 구체적인 내용은 없는 정신론적인 책인 줄 알았지만, 뒷부분에는 실용적인 부분이 꽤나 있어서 기억나는 부분 위주로 정리를 하려고 한다.</p>
<h3 id="tdd">TDD</h3>
<p>일단 첫 번째로 기억이 남는 부분은 TDD에 관한 이야기이다. 필자는 TDD를 이용할 것을 강조한다. TDD를 이용하면 QA 시간이 줄어들고, 효율적으로 개발을 할 수 있다고 한다.</p>
<p>나도 최근에 TDD를 이용해 보았는데 나 같은 경우에는 테스트 도구에 익숙하지 않아서 그런가, 테스트를 작성하는 데 꽤 많은 시간이 들었다. 테스트를 작성하고 나서도 테스트 코드에 확신이 없어서 내가 원하는 바를 테스트하고 있는 것이 맞는가? 하는 의문이 들었다. 리팩토링을 할 때마다 함수의 내용이 변경되니까 테스트를 계속해서 변경해야 하는 점도 힘들었다. 그래서 개발 일정이 급한 경우에는 테스트 코드를 생략하고 나중에 시간이 있을 때 거꾸로 테스트 코드를 짜는 식으로 진행하곤 했다.</p>
<p>하지만 테스트 코드를 짜는 것이 좋다는 생각에는 동의한다. 문제가 발생하지 않으면 다행이지만, 문제가 발생한 경우 콘솔을 사용하여 계속해서 값을 넣어 봐야 했기 때문이다. 다른 사람들은 테스트 코드를 어떻게 짜는지, 그리고 테스트 코드는 어떤 식으로 짜는 게 좋은지에 대한 공부가 필요해 보인다. 테스트 주도 개발이라는 책을 읽고, 저번 syncSwift에서 들었던 강의를 바탕으로 테스트 코드에 대한 개념을 정리해야겠다. 이 책에서는 TDD의 중요성을 강조하기만 하고 구체적인 실현 방안이 없어서 조금 아쉬웠다. 테스트 코드의 도입을 반대하는 동료를 설득하기라는 주제로 글을 써도 즐거울 것 같다.</p>
<h3 id="개발-도서">개발 도서</h3>
<p>이 책에서는 독서를 통한 자기 계발을 강조하면서 개발 도서를</p>
<ol>
<li><p>특정 기술에 대한 서적(특정 언어나 소프트웨어 이용 방법)</p>
</li>
<li><p>특정 개념에 대한 서적(새로운 개념이나 패러다임, ex - 테스트 주도 개발, 도메인 기반 개발, 객체 지향 설계)</p>
</li>
<li><p>행동 양식에 대한 서적(소프트웨어 개발 이외의 프로페셔널에 관한 책)</p>
</li>
<li><p>혁명적 서적(일하는 방식이나 개인의 가치관을 바꾸는 책)</p>
</li>
</ol>
<p>의 4가지로 분류한다. 필자는 혁명적인 서적부터 읽기를 권하는데 나 또한 동의한다. 특정 기술은 계속해서 변화하므로 큰 틀을 먼저 공부하고 기술을 필요할 때마다 공부하는 것이 좋다고 생각한다. 커리어를 위해서라면 4-2/3-1의 순서로 권하지만 나는 개인적으로 행동 양식에 대한 서적은 추상적인 가치관에 대해 이야기하는 것이라고 생각해서 실용도가 좀 떨어진다고 생각한다. 한 두 권 정도는 괜찮지만, 여러 권을 읽을 필요는 없다고 생각한다. 소프트웨어 장인 정신은 3번 행동 양식에 대한 서적에 속한다.</p>
<p>혁명적 서적의 추천 도서는 다음과 같다.</p>
<ul>
<li><p>실용주의 프로그래머 (1999년, 앤드류 헌트 Andrew Hunt, 데이비드 토마스 David Thomas 저)</p>
</li>
<li><p>The Mythical Man-Month (1975년, 프레드릭 브룩스 Frederick Brooks 저)</p>
</li>
<li><p>디자인 패턴(GoF) (1994년, 에리히 감마, Erich Gamma외 4인 제)</p>
</li>
<li><p>테스트 주도 개발 (2002년, 켄트 백 Kent Beck 저)</p>
</li>
<li><p>익스트림 프로그래밍 (1999년, 켄트 백 저)</p>
</li>
<li><p>클린 코더 (2011년, 로버트 C. 마틴 저)</p>
</li>
<li><p>소프트웨어 장인정신 (2001년, 피트 맥브린 저)</p>
</li>
<li><p>리펙토링(1999년, 마틴 파울러 Martin Fowler외 5인 저)</p>
</li>
</ul>
<p>이 책에서는 펫 프로젝트의 중요성을 강조하기도 한다. 아마 토이 프로젝트와 비슷한 개념 같아 보인다. 본인이 흥미 있는 분야에, 시간 제약과 기술적 제약 없이 프로젝트를 체험해 볼 수 있는 기회이기 때문이다. 펫 프로젝트 관련해서는 구체적인 지침을 적어 주어서 체크리스트로 이용하면 될 듯하다.</p>
<ul>
<li><p><input disabled="" type="checkbox">  프로젝트 아이디어 찾기</p>
</li>
<li><p><input disabled="" type="checkbox">  기능 상세화</p>
</li>
<li><p><input disabled="" type="checkbox">  백로그에 할 일 정리</p>
<ul>
<li><p><input disabled="" type="checkbox">  작업 분할</p>
</li>
<li><p><input disabled="" type="checkbox">  우선순위 생각</p>
</li>
<li><p><input disabled="" type="checkbox">  대략적인 일정 추산</p>
</li>
<li><p><input disabled="" type="checkbox">  사용자 스토리 작성</p>
</li>
</ul>
</li>
</ul>
<p>그 외의 것들</p>
<ul>
<li><p><input disabled="" type="checkbox">  테스트</p>
</li>
<li><p><input disabled="" type="checkbox">  애플리케이션 배포(deploy)</p>
</li>
<li><p><input disabled="" type="checkbox">  버전 컨트롤</p>
</li>
<li><p><input disabled="" type="checkbox">  지속적인 통합</p>
</li>
<li><p><input disabled="" type="checkbox">  사용성</p>
</li>
<li><p><input disabled="" type="checkbox">  사용자 인터페이스</p>
</li>
<li><p><input disabled="" type="checkbox">  코드 베이스</p>
</li>
<li><p><input disabled="" type="checkbox">  설계</p>
</li>
<li><p><input disabled="" type="checkbox">  데이터베이스</p>
</li>
</ul>
<p>일다 펫 프로젝트의 중요한 점은 재미있어야 한다는 것이다. 아이디어는 이미 갖고 있으니 펫 프로젝트를 통해 프로그램을 만드는 일도 시작해 볼 생각이다.</p>
<h3 id="채용">채용</h3>
<p>채용에 대해 써 놓은 부분도 인상 깊었다. 나는 구직자의 입장이기 때문에 구직자가 고려해야 할 사항에 관해서 관심이 갔다.</p>
<ol>
<li>관리층이 개발자를 신뢰하는지를 확인하기</li>
</ol>
<p>면접관이 실무 개발자들이 아니라 관리자, 아키텍트, 팀 리더들로만 이루어져 있다면 고위 직급들에 의해서 모든 결정들이 이루어지는 회사일 수 있다.</p>
<ol start="2">
<li>다단계 면접이 아니라 원샷 면접</li>
</ol>
<p>원샷 면접이라면 지원자들을 확인할 시간이 없을 수가 있다. 다단계 면접이라면 지원자들의 서로 다른 측면을 보려는 것이다. 프로페셔널을 채용하는 데 진지하다는 의미이다.</p>
<ol start="3">
<li>면접관의 질문을 분석하면 대개 면접관이 중요하게 생각하는 것을 반영한다.</li>
</ol>
<p>주어진 질문지를 읽기만 하고 짧은 질문만 내놓는다면 그 면접관은 새로운 아이디어를 듣거나 논쟁하고 싶지 않다는 이야기이다. 회사 분위기가 폐쇄적일 수 있다. 현실 세계나 구체적인 문제에 관해서 열린 대화를 하는 것이 좋다.</p>
<p>지원자도 면접에서 회사에 대해 정보를 얻을 수 있어야 회사에 오래 다닐 수 있다고 생각하기 때문에, 이러한 지침들은 매우 유용했다. 또한 채용 공고를 보고 회사에 대한 정보를 얻을 수 있다는 사실도 굉장히 흥미로웠다.</p>
<p>이 책을 읽고 무작정 아무 회사에 들어가기보다는 내가 원하는 커리어를 염두에 두고, 차근히 준비해서 나의 최선을 다하고 싶다는 열망이 커졌다. 회사에 들어가서 같은 열정을 가진 사람들끼리 함께 동기부여받고 함께 성장해 나가보고 싶다. 이를 위해서는 내가 원하는 커리어를 명확하게 설정하는 것이 좋겠다는 생각이 들었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[특이한 정렬]]></title>
            <link>https://velog.io/@ge-um/%ED%8A%B9%EC%9D%B4%ED%95%9C-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@ge-um/%ED%8A%B9%EC%9D%B4%ED%95%9C-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Fri, 16 Dec 2022 14:47:44 GMT</pubDate>
            <description><![CDATA[<p>정수 n을 기준으로 n과 가까운 수부터 정렬하려고 합니다. 이때 n으로부터의 거리가 같다면 더 큰 수를 앞에 오도록 배치합니다. 정수가 담긴 배열 numlist와 정수 n이 주어질 때 numlist의 원소를 n으로부터 가까운 순서대로 정렬한 배열을 return하도록 solution 함수를 완성해주세요.</p>
<h4 id="제한사항">제한사항</h4>
<ul>
<li>1 ≤ n ≤ 10,000</li>
<li>1 ≤ numlist의 원소 ≤ 10,000</li>
<li>1 ≤ numlist의 길이 ≤ 100</li>
<li>numlist는 중복된 원소를 갖지 않습니다.</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>numlist|n|result
|:-:|:-:|
[1, 2, 3, 4, 5, 6]|4|[4, 5, 3, 6, 2, 1]
[10000,20,36,47,40,6,10,7000]|30|[36, 40, 20, 47, 10, 6, 7000, 10000]</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1</p>
<p>4에서 가까운 순으로 [4, 5, 3, 6, 2, 1]을 return합니다.
3과 5는 거리가 같으므로 더 큰 5가 앞에 와야 합니다.
2와 6은 거리가 같으므로 더 큰 6이 앞에 와야 합니다.
입출력 예 #2</p>
<p>30에서 가까운 순으로 [36, 40, 20, 47, 10, 6, 7000, 10000]을 return합니다.
20과 40은 거리가 같으므로 더 큰 40이 앞에 와야 합니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(numlist, n) {
    return numlist.sort((a,b) =&gt; b-a)
        .sort((a,b) =&gt; Math.abs(a-n)-Math.abs(b-n))
}</code></pre>
<p>처음에는 a에서 n을 뺀 절댓값과 b에서 n을 뺀 절댓값을 비교했는데, 그렇게 하니 거리가 같은 경우 큰 숫자가 앞쪽에 오지 않았다. 그래서 미리 내림차순 정렬해준 다음 길이를 비교하여 정리하였다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(numlist, n) {
  return numlist.sort((a, b) =&gt; Math.abs(a - n) - Math.abs(b - n) || b - a);
}</code></pre>
<p>이 풀이는 sort에서 값이 같은 경우 0을 return하는 성질을 이용해서 풀어준 것이다. 값이 같은 경우 0을 리턴하니 false 취급된다. 그래서 값이 같은 경우에는 내림차순 정리하도록 만들어 주었다. or 연산자는 두 가지의 값이 boolean 값인 경우 boolean값을 반환하지만, 아닌 경우 두 값중 하나를 반환하기 때문이다. 즉, Math.abs(a - n) - Math.abs(b - n)이 0, 즉, true인 경우 b-a 기준으로 값을 분류한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우테코 프리코스] 4주차 회고]]></title>
            <link>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 27 Nov 2022 08:08:18 GMT</pubDate>
            <description><![CDATA[<p>일단 이번 주차는 사실상 물음표가 가득한 주차였다. 가이드라인을 적용할 새도 없이 기능 구현에만 급급하여 만든 코드라 코드 리뷰를 요청하기도 어려운 정도이다. 내가 봐도 문제가 많은 코드이기 때문에. 😭 아파서 시간이 없었다고 변명하고는 있지만 사실상 3주동안 달려오면서 충분한 이해 없이 코드를 만들어오다 터졌다고 볼 수 있다. 그래서 이번에는 이전처럼 해온 과정을 쓰는 게 별 의미가 없다고 생각해서 나의 생각을 간단히 적어볼 생각이다.  </p>
<p>미천한 결과는 <a href="https://github.com/woowacourse-precourse/javascript-bridge/compare/main...ge-um:javascript-bridge:ge-um">여기</a>입니다. </p>
<p>제일 문제 구간은 일단 콜백이다. readLine에서 값을 받아오도록 만든 뒤 그 InputView의 메소드 내부에서 처리를 하는 건 가능하다. 그런데 InputView에서 값을 처리하지 않도록 하라는 요구사항이 있어서 분리하려고 시도해 봤는데 실패했다. 이걸 아직도 고민하고 있는데 시간이 좀 걸릴것 같아서 일단 회고록부터 쓰기로 했다. </p>
<p>그리고 두 번째 문제는 this이다. 나는 InputView에서 값을 받아온 다음 App에서 계산을 수행하고 싶은데 this로 값을 가져오는 게 쉽지 않다. 알아본 결과로는 bind라는 개념을 사용하면 될 것 같은데 아직 실행을 실패해서 알 수가 없다. </p>
<p>마지막 문제는 테스트코드이다. 테스트코드 작성하는 건 어느정도 이해했는데 아직도 jest.fn을 이용해서 값을 임시로 받아오는 것에 서툴다. 그래도 이건 서툰것 뿐이라 시간을 두고 찬찬히 작성해보면 될 듯 하다. </p>
<p>하여간 잊어버릴까봐 미리 쓴다. 이 문제를 해결한 다음 다시 한 번 전체 주차를 복습해볼 생각인데.. 시간이 될까 모르겠다. 하여튼 문제를 해결해 나가면서 몰랐던 개념들을 하나하나 따로 작성해 보려고 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우테코 프리코스] 3주차 회고]]></title>
            <link>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 16 Nov 2022 13:52:14 GMT</pubDate>
            <description><![CDATA[<h3 id="0-프로젝트-가이드라인-확인">0. 프로젝트 가이드라인 확인</h3>
<p>이번에 만들 것은 로또(<a href="https://github.com/woowacourse-precourse/javascript-lotto">우테코 2주차 깃허브 링크</a>)였다. 간단히 말하면 로또를 구매하고, 당첨 번호와 보너스 번호를 입력하여 로또에 당첨된 결과를 알려주는 것이었다. </p>
<p>추가된 요구 사항은 크게 정리하자면</p>
<ol>
<li>함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.</li>
</ol>
<ul>
<li>함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.</li>
</ul>
<ol start="2">
<li>else를 지양한다.</li>
</ol>
<ul>
<li>힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.</li>
<li>때로는 if/else, switch문을 사용하는 것이 더 깔끔해 보일 수 있다. 어느 경우에 쓰는 것이 적절할지 스스로 고민해 본다.</li>
</ul>
<ol start="3">
<li>도메인 로직에 단위 테스트를 구현해야 한다. 단, UI(Console.readLine, Console.print) 로직에 대한 단위 테스트는 제외한다.</li>
</ol>
<ul>
<li>핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.</li>
</ul>
<p>적고 보니 추가된 요구 사항을 제대로 지키지 않은 것 같다. 함수가 한 가지 일만 하도록 하는 것에 집중해서 길이가 15라인을 넘는지 아닌지는 체크하지 않았다. 다음에는 15라인을 확인해가면서 해야겠다. </p>
<p>else를 지양하는 것도 다소 논란이 되는 부분인 것 같긴 한데, else를 사용하면 함수의 depth가 깊어져서 가독성이 떨어지는 부분 때문에 early return을 권장한다고 생각한다. 물론 else구문이나 switch 구문을 사용하는 것이 나은 경우도 있겠지만, 이번 경우에는 if구문을 사용하는게 나아 보였다. </p>
<p>도메인 로직이라는 말은 잘 몰라서 검색을 해 봤다. 간단히 말하면 코드에는 크게 도메인 로직과 서비스 로직이라는 게 있는데, 도메인 로직은 실제 비즈니스에 상관 있는 코드, 서비스 로직은 그 비즈니스를 하기 위해서 도와주는 로직이다. 이론상으로는 간단한데 분리하는게 쉽지는 않았다. 관련된 자료를 찾아보던 중 도메인과 서비스를 분리하기 어렵다면 기능 단계의 재정의가 필요하다는 자료를 읽었고, 반복되는 재정의로 도메인과 서비스를 분리했다. 마지막까지 계속 도메인 로직과 서비스 로직 정의를 반복할 정도로 헷갈리는 부분이었다. </p>
<p>가이드라인을 확인한 후 </p>
<ol>
<li>기능 목록 정리하기</li>
<li>테스트 코드 작성(단위 테스트)</li>
<li>기능 구현</li>
<li>pull request 보내기</li>
<li>node로 구현 확인하기 
순으로 진행하였다.
이 글의 마지막에는 피드백과 소감을 적어 보았다.</li>
</ol>
<p>깃허브 레포지토리는 <a href="https://github.com/ge-um/javascript-lotto">여기</a>이니 코드 리뷰 남겨 주시면 감사하겠습니다. 😄 </p>
<h3 id="1-기능-목록-정리하기">1. 기능 목록 정리하기</h3>
<p>고심 끝에 정리한 최종 기능 목록은 다음과 같다. 처음부터 이렇게 작성한 건 아니고 계속 수정을 거듭했다. 이번 기능 목록은 앞부분을 체크박스로 만들었다. 커밋에서 어떤 부분을 작업했는지 명확하게 알려 주기 위해서다. 그리고 옆에 이 기능을 어떤 함수로 만들어 줬는지 적어 주었다. </p>
<pre><code class="language-markdown"># 로또

## 💼 기능 목록

### 📍 도메인

- [x] 유효한 로또 구입 금액을 입력받는다 - Purchase#validate()

  - [x] e) 로또 금액이 숫자가 아닌 경우
  - [x] e) 로또 금액이 0보다 작은 경우
  - [x] e) 로또 금액 금액이 1000원으로 나누어 떨어지지 않는 경우

- [x] 숫자를 랜덤하게 뽑아 오름차순 정렬한다. - MyLotto#generateRandom()

  - [x] 숫자는 중복되지 않는다.
  - [x] 숫자는 1 ~ 45 사이이다.
  - [x] 숫자는 6개이다.

- [x] 유효한 숫자 6개를 입력받는다. - Lotto#validate()

  - [x] e) 숫자 범위가 1 ~ 45가 아닌 경우
  - [x] e) 숫자가 6개가 아닌 경우
  - [x] e) 중복이 존재하는 경우

- [x] 유효한 보너스 번호를 입력받는다. - Bonus#validate()

  - [x] e) 숫자 범위가 1 ~ 45가 아닌 경우

- [x] 로또 번호와 당첨 번호를 비교한다. - Result#compare()

  - [x] 3개 일치 : 5,000원
  - [x] 4개 일치 : 50,000원
  - [x] 5개 일치 : 1,500,000원
  - [x] 5개 일치 + 보너스 번호 일치 : 30,000,000원
  - [x] 6개 일치 : 2,000,000,000원

### 📍 서비스

- [x] 로또 구입 금액/1000개를 구매했다는 메시지를 띄운다. -
      Service#printLottoCount()

- [x] 중복되지 않은 6개의 숫자를 로또 구매 개수만큼 출력한다. -
      Service#printLottoNumbers()

- [x] 당첨 번호 입력 메시지를 띄운다. - Service#printGetWinningNumber();

- [x] 보너스 번호 입력 메시지를 띄운다. - Service#printGetBonusNumber();

- [x] 당첨 통계를 출력한다. - Service#printResult()</code></pre>
<h3 id="2-테스트-코드-작성단위-테스트">2. 테스트 코드 작성(단위 테스트)</h3>
<p>테스트 코드 자체는 수월하게 작성했다. 다만 이번 테스트에서는 로또 번호의 유효성 검사를 할 때 Lotto 내부의 validate()함수를 부르지 않고 그냥 new Lotto()로 불러줬다. 그 이유는 Lotto 클래스 내부의 constructor에서 자동으로 validate()를 불러주도록 코드가 작성되었기 때문이다. 이 과정을 보면서 constructor 내부에 작성된 코드는 클래스를 부를 때 자동으로 실행되는 것을 알 수 있었다. </p>
<pre><code class="language-javascript">describe(&#39;로또 클래스 테스트&#39;, () =&gt; {
  test(&#39;로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.&#39;, () =&gt; {
    expect(() =&gt; {
      new Lotto([1, 2, 3, 4, 5, 6, 7]);
    }).toThrow(&#39;[ERROR]&#39;);
  });</code></pre>
<h3 id="3-기능-구현">3. 기능 구현</h3>
<p>기능을 구현할 때는 이러한 조건도 있었다. </p>
<ul>
<li>제공된 Lotto 클래스를 활용해 구현해야 한다.</li>
<li>numbers의 # prefix를 변경할 수 없다.</li>
<li>Lotto에 필드를 추가할 수 없다.</li>
</ul>
<pre><code class="language-javascript">class Lotto {
  #numbers;

  constructor(numbers) {
    this.validate(numbers);
    this.#numbers = numbers;
  }

  validate(numbers) {
    if (numbers.length !== 6) {
      throw new Error();
    }
  }
  // TODO: 추가 기능 구현
}</code></pre>
<p>일단 Lotto에 필드를 추가할 수 없다는 조건은 이 클래스에서 로또 당첨 번호, 내 로또 번호, 보너스 번호를 한 번에 받아오지 말라는 제약 조건을 만든다고 생각했다. 따라서 클래스를 분리해 각 번호를 받아오는 클래스를 만들기로 했다. </p>
<p># prefix라는 개념은 몰라서 알아보았다. 변수 앞에 #을 붙이면 private 필드가 되며, 이 변수는 클래스 내부에서만 접근 가능한 필드가 된다. 개념 자체는 이해했는데 #을 왜 붙여야 하는 지는 이해가 잘 되지 않았다. 어차피 이 값을 lotto.#numbers로 받아오지 않아도 다른 경로로 받아올 수 있는데 굳이 붙여야 하나 하는 생각이 들었다. 안전성 때문이라고는 하는데, 큰 오류를 발생시킬 수 있는 구체적인 예제를 아직 못 찾아서 아직까지는 잘 모르겠다. 자바 빈 설계 규약에 따르면 무조건 getter과 setter을 만들어야 한다는데, setter을 사용하지 않으면 굳이 만들어야 하나 싶기도 했다. </p>
<p>처음에 클래스를 분리하고 import해도 클래스를 다른 파일에서 사용할 수 없어서 당황스러웠다. 알고보니 module.exports를 하지 않아서였다. 이전까지는 module.exports가 뭔지 몰랐지만 기능을 사용하는데 문제가 없어서 무시하고 넘어갔는데, 클래스 분리를 하면 반드시 export를 해 줘야 import를 할 수 있다는 것을 알게 되었다. </p>
<p>또한 고민이 되었던 지점은 상수 분리였다. 하드코딩을 피하기 위해서 상수를 생성하고 상수를 한 폴더 constant에 모아 두었는데 메시지들을 통일성 없게 export 했다는 생각이 들었다. 메시지의 종류를 그룹화하면서도 통일성 있게 export 하는 방법의 고민이 필요해 보인다. </p>
<h3 id="4-pull-request-보내기">4. pull request 보내기</h3>
<p>이번에는 pull request를 보내고 나서도 부족한 부분이 계속 보여 수정을 거듭했다. 덕분에라고 하긴 뭐하지만 pull request를 보내고 나서도 내 레파지토리에 push하면 pull request에 반영된다는 것을 확인할 수 있었다. </p>
<h3 id="5-node로-구현-확인하기">5. node로 구현 확인하기</h3>
<p>저번 주차에는 node를 돌려 보라는 말이 npm test로 테스트 케이스를 돌려 보라는 이야기인줄 알았다. 그런데 숫자 야구 피드백 강의에서도 프로그램을 실행하는 걸 보니 아무래도 이상해서 찾아 보았다. 알고보니 터미널에 node src/App.js 를 입력하면 프로그램을 실행할 수 있었다. </p>
<p>터미널로 실행해 보니 내 프로그램은 입력을 전혀 받지 못하고 Console.print 부분만 실행되고 있었다. 저번 주차에도 예감하고 있었지만 아무래도 Console.readLine 부분에서 문제가 생긴 것 같았다. 깃허브 discussion을 뒤져본 결과 Console.readㅣine은 비동기 코드지만 async/await 구문을 사용하면 테스트 케이스에서 오류가 생기므로 동기적으로 처리해줘야 한다는 것을 알 수 있었다. 그래서 콜백 함수를 콜백 함수에 담아 주었다. </p>
<pre><code class="language-javascript">getLottoCount() {
    Console.readLine(ServiceMessage.PURCHASE_INPUT, (amount) =&gt; {
      this.printLottoCount(amount);
    });
  }</code></pre>
<p>이해를 돕기 위해 살짝 생략해 주었다. 이런 식으로 Console.readLine 함수 값이 있어야 다음 printLottoCount()가 호출이 되도록 연결해 주면 비동기 함수를 동기적으로 처리할 수 있다. </p>
<p>다만 이 과정을 거치면서 저번 주는 0점일수도 있겠다.. 라는 생각이 들었다. node에서 실행해 보니 제대로 작동하지 않았기 때문이다. ㅎㅎ 하.. 그래도 이제라도 node로 실행시키는 방법을 알아서 다행이라고 생각한다. </p>
<hr>
<h3 id="피드백-정리">피드백 정리</h3>
<h4 id="공통-피드백">공통 피드백</h4>
<p>함수(메서드) 라인에 대한 기준</p>
<ul>
<li><p>프로그래밍 요구사항을 보면 함수 15라인으로 제안하는 요구사항이 있다. 이때 공백 라인도 한 라인에 해당한다. 15라인이 넘어간다면 함수 분리를 위한 고민을 한다.</p>
<ul>
<li>이 부분은 시간에 쫓겨 작성하다 보니 잊어버린 부분이다.. 이번 주차에는 10라인으로 줄었으니 이 부분을 좀 더 신경 써야겠다. </li>
</ul>
</li>
<li><p>발생할 수 있는 예외 상황에 대해 고민한다</p>
<ul>
<li>다른 예외는 구현했는데 당첨 번호와 중복된 보너스 번호를 입력하는 경우는 생각하지 못했다. 예외 상황을 더 많이 고민해 봐야겠다. </li>
</ul>
</li>
<li><p>비즈니스 로직과 UI 로직을 분리한다</p>
<ul>
<li>비즈니스 로직과 UI로직을 분리하라는 이야기는 이해가 간다. UI로직은 쉽게 바꿀수도 있지만 비즈니스 로직은 거의 변하는 경우가 없기 때문이다. 하지만 아직 비즈니스 로직과 UI로직을 구분하는 것이 어렵다. 많은 경험과 연습으로 해결해야겠다. </li>
</ul>
</li>
<li><p>객체의 상태 접근을 제한한다
필드는 private class 필드로 구현한다. 객체의 상태를 외부에서 직접 접근하는 방식을 최소화 하는 이유에 대해서는 스스로 찾아본다.</p>
<ul>
<li>private 필드에 대한 이해가 처음에는 부족해서 private 필드를 무시하고 코드를 짰는데, 나중에 private 필드로 구현하려고 변경하였다. 이제는 private 코드에 대한 이해가 생겼으니 처음부터 고려해서 짜려고 한다. </li>
</ul>
</li>
<li><p>객체는 객체스럽게 사용한다</p>
<ul>
<li>class에서 메시지를 보내는 방법은 시도해본 적 없어서 아직까지 좀 헷갈리기는 한데 다음 과제에서 메시지를 보내 getter을 최소화시키려는 노력을 해봐야겠다. </li>
</ul>
</li>
<li><p>필드의 수를 줄이기 위해 노력한다</p>
<ul>
<li>리팩토링 할 때 필드가 중복되어 선언되지 않았는지도 확인해 볼 지점인 듯 하다. </li>
</ul>
</li>
<li><p>성공하는 케이스 뿐만 아니라 예외에 대한 케이스도 테스트한다</p>
<ul>
<li>오히려 예외에 대한 케이스만 테스트하고 성공하는 케이스를 테스트 안해봤다.. 성공하는 테스트는 node로 실행시키며 확인했는데 테스트 케이스를 보고 다른 사람이 어떤 테스트를 했는지 알 수 있어야 하므로 성공하는 케이스를 테스트해 봐야겠다. </li>
</ul>
</li>
<li><p>테스트 코드도 코드다</p>
<ul>
<li>테스트 코드에 대한 효율성은 전혀 생각하지 않고 짰기 때문에 굉장히 뜨끔하는 부분이다. 테스트 코드도 리팩토링 할때 효율성을 고려했는지 확인해 봐야겠다. </li>
</ul>
</li>
<li><p>테스트를 위한 코드는 구현 코드에서 분리되어야 한다</p>
<ul>
<li>테스트를 위한 코드는 그냥 짤 줄 몰라서 이런 건 만들지도 않았다.. </li>
</ul>
</li>
<li><p>단위 테스트하기 어려운 코드를 단위 테스트하기</p>
<ul>
<li>최대한 단위 테스트를 할 수 있도록 리팩토링을 고민 하라는 이야기이다. 다음 주차에는 일단 짜고 리팩토링하는 시간을 오래 가져야 할 것 같다. </li>
</ul>
</li>
</ul>
<h3 id="소감">소감</h3>
<p>이번에는 빨리 진행해서 다른 사람의 코드도 살펴보고 피드백도 받고 싶었는데 나에겐 빡빡한 과제였다.. 한 주가 끝나면 자신감이 생겨서 이 정도도 할수 있구나! 하고 뿌듯해지는데 다음주 과제를 시작하면 모르는 게 너무 많아서 다시 쪼그라든다. 코드를 작성하는 시간보다 모르는 개념을 찾아보고 이 개념을 왜 써야 하는지 이해하는 시간이 더 많은 것 같다. 모르는 게 많은 건 좀 슬프지만 그래도 공부하는 방법을 점점 더 알게 되고 있다. 아직 3주차지만 혼자 공부한 것보다 많은 것을 배우고 있다. </p>
<p>다른 사람의 피드백은 역시 중요하다는 생각이 든다. 내가 혼자 짰을 때는 꽤 괜찮은 코드인 기분이었는데 피드백을 받고 여러가지 기준을 적용해보니 부족한 점이 많이 느껴진다. 부족한 점을 지적받아서 오히려 기분이 좋다. 다른 사람에게 피드백 받아 더 나은 코드를 짤 수 있는 귀한 기회이기 때문이다!!! 다음 주면 끝난다는 사실이 많이 아쉽다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우테코 프리코스] 2주차 회고]]></title>
            <link>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-2%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-2%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 09 Nov 2022 17:28:25 GMT</pubDate>
            <description><![CDATA[<h3 id="0-프로젝트-가이드라인-확인">0. 프로젝트 가이드라인 확인</h3>
<p>이번에는 숫자 야구 게임(<a href="https://github.com/woowacourse-precourse/javascript-baseball">우테코 2주차 깃허브 링크</a>)이었다. 주 기능은 컴퓨터에서 3자리 숫자를 랜덤으로 생성한 후, 사용자의 입력값을 받아와 사용자에게 스트라이크/볼/낫싱으로 힌트를 주는 것이다. 추가된 요구 사항은 크게 정리하자면 </p>
<ol>
<li>함수를 분리해서 indent(들여쓰기)레벨을 2까지 맞추기</li>
<li>jest를 사용하여 테스트 코드를 구현하기</li>
<li>주어진 라이브러리를 사용하기</li>
</ol>
<p>가 되겠다. 가이드라인을 확인한 후</p>
<ol>
<li>기능 목록 정리하기</li>
<li>jest 사용 방법 익히기</li>
<li>테스트코드 작성</li>
<li>기능 구현</li>
<li>prettier/es lint 적용</li>
<li>pull request 보내기</li>
</ol>
<p>순으로 진행하였다. 
이번에 진행한 내 깃허브 레포지토리는 <a href="https://github.com/ge-um/javascript-baseball">여기</a>이다.</p>
<p>이 글의 마지막에는 피드백과 소감을 적어 보았다. </p>
<h3 id="1-기능-목록-정리하기">1. 기능 목록 정리하기</h3>
<p>처음에 정리한 이후 수정을 좀 거쳤지만 최종적인 기능 목록은 다음과 같다.</p>
<pre><code class="language-markdown">1. 게임 시작 문구 출력
2. 숫자 랜덤 생성
    - 3자리 자연수
    - 1부터 9까지의 숫자로 구성
    - 중복 불가
3. 사용자 입력 유효성 검사
    - e) 3자리 자연수가 아닌 경우
    - e) 0이하의 정수 불가
    - e) 중복된 숫자 불가
4. 사용자 입력 받아오기
5. 스트라이크/볼 카운트 세기
5. 정답 검사 결과 출력
    - 볼, 스트라이크 둘다 존재 : 볼 -&gt; 스트라이크 순서, 숫자 + 볼/스트라이크
    - 하나도 없는 경우 - 낫싱
    - 정답시 종료 문구 출력
    - 오답시 3. 사용자 입력 검사 반복
6. 종료 검사
    - 1 입력시 1. 게임 시작 문구 출력으로 돌아감
    - 2 입력시 종료
    - e) 나머지 숫자 입력시 오류 출력</code></pre>
<h3 id="2-jest-사용-방법-익히기">2. jest 사용 방법 익히기</h3>
<p>이번주에는 jest의 사용 방법을 익히고 테스트코드를 작성하는 데서 시간을 많이 썼다. 왜냐하면 나는 남들이 짜준 테스트코드만 사용해봤지 한 번도 테스트코드를 짜본 적이 없었기 때문이다. 처음에는 jest를 깔라는 이야기인줄 알고 깔았었는데 npm install을 하니 jest가 자동으로 설치되었다. 저번 주에 npm을 이미 깔았어서 안 깔아도 되는줄 알았는데 npm이라는 건 node 전체의 패키지가 아니라 프로젝트마다 달라지는 듯 하다. 제일 당황스러웠던 것은 이 jest did not exit one second after the test runs has completed라는 오류였다. 이 오류가 발생하면 터미널에서 다음 값을 입력할 수 없어서 강제종료를 시켜 주어야 했다. <img src="https://velog.velcdn.com/images/ge-um/post/dde595f9-8201-4234-a2d7-2435d7736081/image.png" alt="">
터미널에서는 jest를 시작할 때 --detectOpenHandles라는 옵션을 이용하라고 설명하긴 하지만 근본적인 원인을 해결하고 싶어서 검색을 한참 했다. 알고보니 어떤 비동기적 처리가 jest를 실행하고 나서도 종료되지 않아서 일어나는 오류라고 한다. </p>
<p>추정으로는, 아마도 숫자 야구 게임에서 사용자의 숫자값을 입력 받는데, 그 값을 1초안에 입력하지 않아서 이러한 문구를 띄워주는 듯 하다. (깃허브 디스커션에 자세한 설명이 적혀 있던데, 동기/비동기, async/await 개념에 대해 공부를 하고 와야 이해가 될 것 같다). </p>
<p>그래서 이 오류를 그냥 무시하고 진행하였고, 완성한 뒤에도 이 오류는 여전히 발생했지만 테스트 케이스 자체는 통과할 수 있었다. </p>
<h3 id="3-테스트-케이스-작성">3. 테스트 케이스 작성</h3>
<p>테스트 케이스 작성도 애를 많이 먹은 부분이다. jest를 사용해본 적이 아예 없으니 jest의 명령어에 대해 잘 몰랐기 때문이다. </p>
<p>간단하게 말하면 함수를 만든 다음 그 함수가 통과되면 테스트케이스가 통과되는 것이다. 제일 간단한 형식으로 쓰면 이런 식으로 쓸 수 있다. test뒤에 괄호를 열어준 다음, 첫 번째 인수로 테스트할 내용, 두번째 인수로 통과할 함수를 넣어준다. 그리고 expect안에 테스트할 값을 넣어 주고 뒷 부분은 그 테스트값이 어떨지 적절한 메소드를 넣어 주면 된다. 이 경우에는 .toContain이라는 메소드를 사용하면 테스트할 값이 괄호 안의 값을 포함하는지 알려 주는 것이다. </p>
<pre><code class="language-javascript">test(&#39;split 메서드로 구분자가 포함되지 않은 경우 값을 그대로 반환&#39;, () =&gt; {
    const input = &#39;1&#39;;
    const result = input.split(&#39;,&#39;);

    expect(result).toContain(&#39;1&#39;);
  });</code></pre>
<p>그리고 알아야 할 중요한 개념은 jest.fn()이라는 개념이다. </p>
<pre><code class="language-javascript">const mockRandoms = (numbers) =&gt; {
  MissionUtils.Random.pickNumberInRange = jest.fn();
  numbers.reduce((acc, number) =&gt; {
    return acc.mockReturnValueOnce(number);
  }, MissionUtils.Random.pickNumberInRange);
};

const randoms = [1, 3, 5];
mockRandoms(randoms);</code></pre>
<p>여기서 이 부분은</p>
<pre><code class="language-javascript">MissionUtils.Random.pickNumberInRange = jest.fn();</code></pre>
<p>라이브러리의 랜덤값을 추출해주는 메소드를 가짜 함수로 대체하겠다는 것이다. 가짜 함수로 만들어주었으니 대체할 값을 직접 만들어서 넣어 주어야 한다. 이 경우에는 하단에서 mockRandoms(randoms)라고 호출해 줌으로써 numbers라는 부분에 [1,3,5]를 넣어준다. 
이번 것은 얼추 이해는 했는데 아무래도 활용하려면 아직 시간이 좀 필요할 듯 하다. <a href="https://jestjs.io/docs/api">Jest 공식 API 설명 사이트</a>에서 필요한 기능을 찾아서 활용해 봐야겠다. </p>
<p>각 함수에 대한 테스트는 해봤는데 함수를 연결했을 때 제대로 작동하는지는 테스트 케이스를 짤 엄두가 안 나서 그냥 테스트 케이스를 짜지 않았다. 하지만 나중에 그 부분에서 에러가 나서 어떻게든 이해해서 테스트 케이스를 짤 걸 하는 생각이 들었다. </p>
<h3 id="4-기능-구현">4. 기능 구현</h3>
<p>기능 구현에서 어려웠던 점은 함수를 분리시키는 일이었다. 함수 분리 자체는 어렵지 않았지만 분리된 함수에서 얻은 값을 어떻게 다시 끌어오냐가 고민이 많이 되었다. 지역변수로 선언했기 때문에 그 함수를 나오면 값 자체가 유실되었기 때문이다. </p>
<p>이번에는 한 함수를 호출하고 그 함수 내에서 다른 함수를 호출하는 식으로 진행을 했다. 다른 방법을 찾을 시간이 모자랐기 때문이다. 다음에 진행할 때는 함수에서 값을 받아와서 그 값을 다른 함수 내에서 끌어올 수 있는 방법을 고민해 볼 생각이다. 아마 class 개념이 덜 잡혀서 그런 것 같다.</p>
<h3 id="5-prettieres-lint-적용">5. prettier/es lint 적용</h3>
<p>저번주 피드백을 반영해서, 이번에는 prettier과 eslint를 사용했다. 보통 처음에 프로젝트를 시작하는데 설치하라고 권장되는데, 나는 마지막에 사용했다. 왜냐하면 eslint를 사용하면 package.json파일이 변경되는데 이 파일을 변경하지 말라는 요구가 있었기 때문이다. 그래서 나중에 모두 작성한 뒤 es lint를 돌리고 package.json파일을 올리지 않는 방법으로 진행했다. </p>
<p>코딩스타일 가이드는 airbnb 코딩 스타일을 따르는 게 권장되어 airbnb 스타일로 prettier을 설정해 주었다. </p>
<pre><code class="language-javascript">arrowParens: &#39;always&#39;
bracketSpacing: true
jsxBracketSameLine: false
jsxSingleQuote: false
printWidth: 80
proseWrap: &#39;always&#39;
quoteProps: &#39;as-needed&#39;
semi: true
singleQuote: true
tabWidth: 2
trailingComma: &#39;es5&#39;
useTabs: false</code></pre>
<h3 id="6-pull-request-보내기">6. pull request 보내기</h3>
<p>한 번 해봐서 그런지 pull request는 쉽게 보냈다. </p>
<hr>
<h3 id="피드백-정리공통-피드백--코수타--추가-학습-자료">피드백 정리(공통 피드백 + 코수타 + 추가 학습 자료)</h3>
<h4 id="공통-피드백">공통 피드백</h4>
<ul>
<li><p>README.md를 상세히 작성한다</p>
<ul>
<li>프로젝트에 대한 설명은 기존 README.md에 잘 작성되어 있다고 생각해서 기능 목록을 작성하는 부분에서 적진 않았는데, 기능 목록 부분에서도 다시 설명을 해야 하는지 고민이 된다. 적는다면 이해하기 쉽겠지만, 반복적인 부분이 되기 때문이다. </li>
</ul>
</li>
<li><p>기능 목록을 재검토한다</p>
<ul>
<li>이 부분은 현재 잘 작성하고 있다고 생각한다. </li>
</ul>
</li>
<li><p>기능 목록을 업데이트한다</p>
<ul>
<li>기능목록을 처음부터 완벽하게 짜려고 해도 완벽하게 완성되지 않았다. 기능을 짜다 보면 여러 개의 기능인데 한 기능으로 너무 뭉쳐서 작성한 경우도 있었다. 그래서 큰 틀만 짠다는 생각으로 짠 다음 차차 업데이트할 생각이다. </li>
</ul>
</li>
<li><p>값을 하드 코딩하지 않는다</p>
<ul>
<li>사실 문자열 같은 경우는 굳이 상수로 빼서 코드를 늘릴 필요가 있나? 싶은 생각이 들었다. 의도를 나타내기 위해서 이름을 만들라고 하니 납득이 된다. 다음에는 상수를 만들어 값을 부여해야겠다. </li>
</ul>
</li>
<li><p>구현 순서도 코딩 컨벤션이다</p>
<ul>
<li>필드와 생성자가 뭔지 모르겠어서 알아보니 필드는 클래스 내에서 =으로 값을 할당하는 것, 생성자는 constructor, 즉 객체를 찍어내는 틀을 의미했다. 무의식적으로 사용은 하고 있으나 용어를 잘 몰라서 가끔 이해하기 어려운 부분이 있다. 용어를 모르면 의사소통하기 어려우니 용어 공부도 조금씩 해야겠다는 생각이 들었다. </li>
</ul>
</li>
<li><p>한 함수가 한 가지 기능만 담당하게 한다</p>
<ul>
<li>이번에 한 가지 일만 하도록 함수를 짜려고 노력했지만 마지막 부분에 다른 함수를 호출했으므로 한 가지 기능만 들어가진 않은 것 같다. 고민이 필요한 지점이다. </li>
</ul>
</li>
<li><p>함수가 한 가지 기능을 하는지 확인하는 기준을 세운다</p>
<ul>
<li>함수를 일단 15줄 이내로 짰는지 확인하고 마지막에 어떤 기능을 하는지 적음으로써 한 가지 기능을 하는지 확인해야 할 듯 하다. </li>
</ul>
</li>
<li><p>JavaScript에서 객체를 만드는 다양한 방법을 이해하고 사용한다</p>
<ul>
<li>자바스크립트의 메소드 이용만 해 봤지 객체에 대한 개념이 부족한 것 같다. 객체에 대한 개념이 부족해서 함수 분리에도 어려움을 겪은 것 같다. 이번 주에는 객체에 대해 자세히 공부해볼 예정이다. </li>
</ul>
</li>
<li><p>테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다</p>
<ul>
<li>이번에 시간 내에 완성을 못할까봐 마음이 급해서 테스트를 대충 짜고 다음으로 넘어갔는데, 결국 뒤쪽에서 문제가 생기고 어디서 문제가 발생했는지 한참 찾아봐야 했다. 미리 사용자 입력값에 대한 테스트를 진행했더라면 발생하지 않았을 문제라는 생각이 들었다. 그리고 이번 과제는 짧은 코드라 다행이지 긴 코드였다면 테스트 짜는 것 보다 문제 찾는 데 시간을 많이 허비했을 것 같다. 이번 주에는 필요한 테스트를 꼼꼼하게 작성하고 다음 단계로 넘어가고 싶다.</li>
</ul>
</li>
<li><p>처음부터 큰 단위의 테스트를 만들지 않는다</p>
<ul>
<li>테스트는 순차적으로 진행했는데, 피드백에서는 중요한 기능부터 테스트를 해 보라고 나와 있다. 기능 목록을 만들고 중요도를 매겨보는 일도 필요할 듯 하다. </li>
</ul>
</li>
</ul>
<h4 id="코수타">코수타</h4>
<ul>
<li><p>남들과 비교하기보다는 자신이 모르는 것에 집중하기</p>
<ul>
<li>단위 테스트를 잘 모른다면 TDD는 신경쓰지 말고 단위 테스트를 하는 것부터 집중하라고 하셨는데, 사실 단위 테스트 신경쓴다고 TDD는 머리 저편으로 사라졌었다.... 멘탈은 걱정 없을 것 같다...머쓱하네.. </li>
</ul>
</li>
</ul>
<h4 id="추가-학습-자료">추가 학습 자료</h4>
<ul>
<li><p>커밋 메시지를 쓸 때 괄호 안에 범위(scope)를 넣어 주기</p>
<ul>
<li>커밋 컨벤션을 읽었음에도 정신이 없다 보니 범위 부분을 잊어버렸다. 다음 주차에는 이 부분을 신경 써서 커밋 메시지를 써야겠다. </li>
</ul>
</li>
<li><p>처음 기능 목록을 작성할 때 이 기능을 어떤 함수에 넣어 줄지 적어주기</p>
<ul>
<li>보면서 내가 기능 목록을 시켜서 기계적으로 만들고 있다는 생각이 들었다. 나 혼자만 보는 게 아니라 다른 사람도 보는 부분이니, 어떤 함수에 어떤 기능이 들어갔다고 설명을 써 주면 더욱 이해하기 쉬울 듯 하다. </li>
</ul>
</li>
<li><p>기능 목록 구현 앞부분에 체크박스를 만들어 주기. </p>
<ul>
<li>위와 똑같은 맥락으로, 체크박스를 하나씩 채워주면 다른 사람이 읽었을 때 어떤 기능을 구현한지 쉽게 알 수 있다. 특히나 기능을 순서대로 만들지 않을 때 필요해 보인다. </li>
</ul>
</li>
<li><p>함수를 기능에 따라 그룹화해서 다른 파일로 분리시켜주기</p>
<ul>
<li>이런 식으로 작성하면 파일명만 보고도 크게 어떤 기능이 있는지 확인할 수 있다. 유지보수 관점에서도 유용할 것 같다. </li>
</ul>
</li>
<li><p>기능을 함수로 캡슐화 시켜준 다음, 마지막에 조합할 것</p>
<ul>
<li>사실 이번에는 함수를 만드는 것과 조합을 동시에 했었다. 그런데 이런 식으로 작성하니 함수 자체는 제대로 동작하나 조합이 잘못되어 추후에 에러가 발생하는 경우가 생겼다. 그래서 커밋 메시지를 구구절절 쓰긴 했는데, 따로 분리해 줘야 나중에 커밋 메시지만 보고도 어떤 일이 일어났는지 간략하기 이해하기 쉬울 것 같다. 다음에는 기능 구현만 커밋하지 말고 조합도 커밋 한 개로 분리해야겠다. </li>
</ul>
</li>
<li><p>기능 구현과 테스트 실행도 다른 커밋으로 분리</p>
<ul>
<li>이번에는 테스트가 제대로 짜졌는지 잘 모르겠어서 기능 구현과 관련 테스트 코드를 함께 커밋했는데, 다음에는 따로 커밋해 줘야겠다. </li>
</ul>
</li>
</ul>
<h3 id="소감">소감</h3>
<p>jest를 활용하여 테스트 케이스를 짜는 연습이 많이 필요하다고 생각이 들었다. 테스트 케이스 짜는게 서툴러서 적당히 짰더니, 나중에 생각지도 못한 문제가 발생했다. 테스트를 제대로 짰으면 이런 문제가 생기지 않았을 것 같다는 생각이 들었다. 함수 자체 테스트 뿐만 아니라 기능이 연결되는지에 대한 테스트도 필요할 듯 하다. </p>
<p>jest의 오류에 대해서 이해하지 못한 건 아쉬움이 크다. 현재로써 이해하기엔 너무 추가 학습이 많이 필요할 것 같아서 건너 뛰었지만 고생을 많이 한 부분이라서 언젠가 이해하고 싶다. </p>
<p>공부할 건 많고 시간은 부족해서 일단 중요해보이는 것 위주로 학습하고 크게 중요하지 않은 건 일단 패스했는데, 모르는 건 회고 글에 잔뜩 적어놨으니 시간이 될 때나 그 기능이 중요해질 때 차근차근 머리에 넣어 봐야겠다. </p>
<p>이번에는 첨부해준 영상이 많은 도움이 되었다. 물론 자바 강의라서 메소드가 다 다르긴 하지만 일단 객체지향 언어라서 유사한 점이 많아서 배울 점이 많았다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우테코 프리코스] 1주차 회고]]></title>
            <link>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-1%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@ge-um/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-1%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 02 Nov 2022 14:14:44 GMT</pubDate>
            <description><![CDATA[<h3 id="0-프로젝트-가이드라인-확인">0. 프로젝트 가이드라인 확인</h3>
<p>가이드라인을 확인하여</p>
<ol>
<li>깃허브와 터미널을 이용하여 내 컴퓨터에 파일 가져오기</li>
<li>기능 목록 만들기</li>
<li>코드를 작성하기</li>
<li>테스트를 실행해 보기</li>
<li>기능 단위로 커밋하기</li>
<li>내 원격 저장소에 올리기</li>
<li>Pull Request 보내기</li>
<li>우아한테크코스 지원 플랫폼에서 과제 제출하기</li>
</ol>
<p>순으로 진행하였다. </p>
<h3 id="1-깃허브터미널을-이용해서-내-컴퓨터에-파일을-가져오기">1. 깃허브/터미널을 이용해서 내 컴퓨터에 파일을 가져오기</h3>
<ol>
<li>Fork : 다른 사람의 저장소에서 자신의 github 저장소로 파일을 그대로 옮겨 오기.</li>
<li>Clone : 이 저장소를 자신의 컴퓨터(local)로 옮겨 오기.</li>
</ol>
<ul>
<li>명령 방법</li>
</ul>
<pre><code>git clone https://github.com/{본인_아이디}/{저장소 아이디}.git
ex) git clone https://github.com/ge-um/javascript-onboarding.git</code></pre><pre><code>// clone한 폴더로 이동하는 방법
cd {저장소 아이디}
ex) cd java-baseball</code></pre><p>여기서부터 이해가 안 됐지만 안 찾아보고 했다가 온통 뒤죽박죽 되어서 터미널의 여러가지 기능을 알 수 있었다.. 역시 지름길은 없나 보다.</p>
<p>여기서 cd는 change directory의 약자로, cd 뒤에서 입력한 폴더로 바로 이동할 수 있다. cd를 이용하여 폴더로 이동하는 방법에는 2가지 방법이 있다. </p>
<pre><code>1. 절대경로 입력

이것은 폴더 전체 경로를 입력해주는 방식이다. 터미널에 pwd를 입력해보면 현재 어느 위치에 있는지 확인해볼 수 있다. 확인해보면 현재는 Users/{컴퓨터 이름}에 있는 것을 알 수 있다. 복제도 이 위치에서 했으므로 경로는 Users/{컴퓨터 이름}/javascript-onboarding가 될 것이다. 따라서 cd Users/{컴퓨터 이름}/javascript-onboarding을 입력해주면 된다. 

아니면 open javascript-onboarding을 터미널에 입력하여 폴더를 열어 볼 수도 있다. 맥에서는 Users파일이 Finder에서 찾을 수 없도록 숨겨져 있기 때문에 터미널을 이용해 열어주어야 한다. 

2. 상대경로 입력

이 방식이 위에서 설명한 방식이다. 현재 Users/{컴퓨터 이름}에 있을 때 하위 폴더 중에서 javascript-onboarding 폴더를 찾아 주는 방식이다. 따라서 cd javascript-onboarding 이라고 입력해주면 된다. 이 때는 현재 터미널에서 Users/{컴퓨터 이름}에 있어야 오류가 발생하지 않는다. </code></pre><ol start="3">
<li>브랜치 생성</li>
</ol>
<pre><code>git checkout -b {본인 아이디}
ex) git checkout -b ge-um</code></pre><p>branch를 생성한 후에 visual basic studio에서 열어보면 왼쪽 하단에 브랜치가 생긴 것을 시각적으로 확인해 볼 수도 있다. </p>
<p><img src="https://velog.velcdn.com/images/ge-um/post/36314b83-d562-4fa4-a794-df7c9ca2b823/image.png" alt=""></p>
<p>혹은 git graph라는 확장파일을 설치해도 시각적으로 볼 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/ge-um/post/b8740695-27a1-49c6-be07-cfe1b042e8ce/image.png" alt=""></p>
<p>나는 이것저것 손대다 보니 폴더도 두 개나 복제된데다가 어느쪽 파일에 브랜치를 생성했는지 알 수가 없어서 삭제를 해 주기로 했다. </p>
<pre><code>git branch -d {브랜치 이름}
ex) git branch -d ge-um</code></pre><p><img src="https://velog.velcdn.com/images/ge-um/post/21f29092-a180-4d26-a167-5158dac13baa/image.png" alt=""></p>
<p>이것이 삭제하는 명령어인데, 브랜치를 삭제할 수 없다는 오류가 발생했다. 이것은 현재 ge-um이라는 브랜치에 있기 때문에 삭제할 수 없다는 의미이다. 따라서 </p>
<pre><code>git checkout main</code></pre><p>이라고 써준 다음 삭제해주면 오류가 해결된다. 다른 블로그를 참조하니 <code>git checkout master</code>이라고 써주래서 처음에는 그렇게 했는데, 위처럼 써야 제대로 작동한다. master과 main은 똑같은 역할을 하는 똑같은 개념인데, master이라는 표현이 노예와 주인을 연상시킨다는 이유로 master 대신 main이라고 쓴다고 한다. </p>
<ol start="4">
<li>프로젝트 열기</li>
</ol>
<p>이 부분에서도 폴더를 찾을 수가 없어서 한참 해맸는데, 앞에서 기술했다시피 맥에서 Users파일을 숨겨 놓았기 때문에 찾을 수가 없던 것이었다. 터미널에서 open javascript-onboarding 폴더를 한 번 열어주면 visual studio code에서도 파일을 찾아서 열 수 있다. </p>
<h3 id="2-기능-목록-만들기">2. 기능 목록 만들기</h3>
<p>온보딩 미션의 진행 방식을 보면,</p>
<blockquote>
<p>특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다.</p>
</blockquote>
<p>이라고 나와 있다. 주석으로 코드의 흐름을 적어본 적은 있지만, 기능 단위로 커밋한 적은 없기 때문에 기능은 어느 정도로 나누면 좋을지 고민이 많이 되었다. 고민 끝에 작성한 기능은 다음과 같다. </p>
<pre><code class="language-markdown"># 📌 기능 목록
### Problem1 : 페이지 번호 게임
- (e) - 예외 상황

1. 예외상황을 제거한다.(-1 출력)
    (e) 포비와 크롱의 페이지가 연속되지 않는 숫자
    (e) 왼쪽 페이지가 홀수, 오른쪽 페이지가 짝수가 아닌 경우
2. 포비와 크롱의 점수를 구한다.
3. 비교 후 결과를 출력한다.(포비 승 1, 크롱 승 2, 무승부 0)

### Problem2 : 중복 문자 삭제
1. 연속하는 중복 문자를 삭제한다.

### Problem3 : 369 게임하기
1. 숫자(3/6/9)의 등장 횟수를 센다.

### Problem4 : 문자열 바꾸기
1. 규칙에 맞게 문자를 변환한다. 

### Problem5 : 돈을 화폐로 교환
1. 금액권의 갯수가 가장 작도록 돈을 교환한다.

### Problem6 : 연속적인 글자를 포함하는 닉네임 확인
1. 같은 글자가 연속으로 포함되는 닉네임을 찾는다.
2. 해당하는 닉네임의 메일을 출력한다.

### Problem7 : 친구 알고리즘 구현
1. 사용자의 친구를 찾는다.
2. 친구의 친구를 찾아 점수를 추가한다.(10점)
3. 방문자의 점수를 추가한다(1점)
4. 추천 점수에 따라 정렬한 후, 점수 순으로 (5명을) 출력한다.
    -e) 추천 점수가 0점인 경우 추천하지 않는다
    -e) 추천 점수가 같은 경우는 이름 순</code></pre>
<p>기능을 나눌 때 고려한 점은 다음과 같다. </p>
<ol>
<li>수정을 고려하여 단계를 나눈다.<ul>
<li>문제 1번 같은 경우, 예외사항, 점수 체계, 결과값이 바뀔 수도 있다고 생각하여 예외사항 제거, 점수 구하기, 결과값 구하기의 3단계로 나누어 주었다.</li>
</ul>
</li>
<li>기능에 특정 내장 함수 명을 적지 않는다.<ul>
<li>그 함수를 사용하는 것 이외에 다른 좋은 방법이 생각날 수도 있기 때문이다.</li>
</ul>
</li>
<li>상세 값은 괄호 안에 적어 준다.<ul>
<li>리턴 값이나 점수는 변경될 수 있기 때문에 세부적인 내용이라고 판단하였고, 괄호 안에 적어 주었다.</li>
</ul>
</li>
</ol>
<h3 id="3-코드를-작성하기">3. 코드를 작성하기</h3>
<p>여태까지는 개인 작업이 대부분이었기 때문에 주로 내가 읽기 편한 대로 코드를 작성해왔다. 하지만 우테코에서는 협업 작업을 할 것이기 때문에, 다른 사람이 이해하기 쉬운 코드가 필요하다. 고민 끝에, 여러 가지 코딩 컨벤션을 찾아보고 참고하여 일정한 코드를 짜려고 노력하였다. </p>
<p>특히나 신경 쓴 부분은</p>
<ol>
<li>변수 이름은 길어도 기능이 제대로 드러나게 짓는다.</li>
<li>한 줄의 끝에는 반드시 세미콜론으로 종결해준다. </li>
<li>tab이나 space bar을 혼용하지 않는다. </li>
<li>삼중 등호 연산자(!== or ===)를 사용한다. </li>
<li>삼항 연산자는 간단하게 나타낼 수 있을 경우에만 사용한다.</li>
<li>if 뒤에는 반드시 중괄호를 써 준다.</li>
<li>연산자나 콤마 뒤에 반드시 공백을 넣어 준다.</li>
</ol>
<p>이다. 팀이나 기업에 따라 세부적으로 달라질 수는 있겠지만, 이 정도로도 코드가 훨씬 깔끔하고 읽기 편하다고 느꼈다. 또한 나는 습관적으로 map이나 filter의 변수를 v라고 주는데, 그 변수에 일부러 이름을 붙여 코드를 이해하기 쉽게 만들어주었다. </p>
<p>코드 컨벤션을 보다 보면 변수명 짓는 부분에 카멜 케이스, 스네이크 표기법이라는 단어가 나오기도 한다. 카멜 케이스는 두 번째 단어부터 단어의 첫 글자를 대문자로 표기해주는 방법이고, 스네이크 케이스는 띄어쓰기 대신 _를 사용해주는 방법이다. </p>
<h3 id="4-테스트를-실행해-보기">4. 테스트를 실행해 보기</h3>
<p>나는 보통 프로그래머스를 활용하여 알고리즘 문제를 풀어보기 때문에, 터미널과 node를 사용하여 테스트해본 것은 처음이었다. 터미널에 install npm을 입력하면 node.js의 패키지를 관리하는 프로그램을 설치해 준다. npm test라고 입력하면 코드를 테스트해 결과를 알려준다. 테스트 할 때  반드시 현재 디렉토리가 javascript-onboarding이어야 테스트가 제대로 실행된다. </p>
<p>node 14에서 제대로 작동해야 한다는 조건이 있었기 때문에 node를 14로 다운그레이드해 주었다. 처음에는 터미널에 n 14.0을 입력하여 14.0 버전을 깔아 주었는데 제대로 구동되지 않았다. 이 때는 터미널에 n 14 lts를 입력해주면 된다. lts는 장기 지원 버전이라는 뜻이다. </p>
<h3 id="5-기능-구현-후-기능-단위로-커밋하기">5. 기능 구현 후 기능 단위로 커밋하기</h3>
<p>기능 단위로 코드를 짠 후 커밋하는 방법을 알아보았다. 커밋을 하려면 크게 git add 와 git commit이라는 명령어가 필요하다. </p>
<p>git add 같은 경우 파일을 staging area에 넣어주는 명령어이다. 바로 커밋하지 않고 중간 단계가 있는 것이다.</p>
<pre><code>git commit add .(-A)</code></pre><p>우테코 안내서에서는 위 방법을 사용하라고 하지만 나는 기능 구현을 전부 한 후에 커밋하고 싶어서 다른 방식을 사용했다. 위의 방법은 모든 변경사항을 한 번에 커밋하는 명령어이기 때문이다. 그래서</p>
<pre><code>git commit add 파일명</code></pre><p>을 써 주면 파일을 개별적으로 커밋할 수 있다. 대신 파일의 경로를 잘 적어 주어야 한다. docs/README.md 이런 식으로 말이다. </p>
<p>add로 staging area에 넘긴 후 git commit 명령어를 이용하면 커밋을 할 수 있다. 여기에 메시지를 쓰려면 </p>
<pre><code>git commit -m ‘message 내용’ </code></pre><p>이라고 써 주어야 한다. 메시지를 작성한 후 직전의 커밋메시지를 변경하고 싶다면 </p>
<pre><code>git reset HEAD^</code></pre><p>를 사용하여 이전의 커밋을 취소한 다음 다시 커밋메시지를 써줄 수 있다. </p>
<pre><code>git commit --amend</code></pre><p>를 사용하여 수정할 수도 있다고 하던데 나는 계속 뭔가 오류가 뜨는데다가 뭘 바꿔야 한다고 해서 일단 미뤄뒀다. 다음에 꼭 필요한 일이 있으면 다시 한 번 고민해 봐야겠다. </p>
<p>커밋메시지도 처음 써보는 터라 어떻게 써야 할지 고민이 많았다. 커밋 문구는 보통 제목/본문/바닥글로 분리하여 쓴다고 하지만 이번 문제 같은 경우에는 기능의 설명이 크게 필요하지 않다고 느꼈다. 따라서 제목만을 작성하였다. </p>
<p>제목을 작성할 때 보통 <code>기능 : 제목</code> 이런 식으로 표시한다고 하는데, 나는 기능 설명을 하는 README파일이 있었고, 수정이 없었어서 docs와 feat만 사용해 주었다. 그리고 기능별로 커밋했기 때문에 문제 번호도 따로따로 적어 주었다. 결론적으로,</p>
<p>이런 식으로 적어 주었다. <img src="https://velog.velcdn.com/images/ge-um/post/fd33e65f-2388-4ca4-a286-9ec2fa519a2d/image.png" alt=""></p>
<h3 id="6-내-원격-저장소에-올리기">6. 내 원격 저장소에 올리기</h3>
<p>이제는 간단한 일만 남았다고 생각했는데, push할 때 문제가 또 발생했다. 원래는 </p>
<pre><code>git push origin 브랜치이름</code></pre><p>을 써주면 push되어 내 깃허브에 올라간다. id와 password를 입력하라는 창이 나오는데, 정책이 바뀌어서 패스워드를 사용하면 저장소에 접근이 안 된다. 따라서 깃허브에 가서 토큰을 발급 받아 주어야 한다. </p>
<blockquote>
</blockquote>
<p>profile - setting - developer setting - personal access token - Tokens(classic) - generate new token</p>
<blockquote>
</blockquote>
<p>에 들어가면 토큰을 발급 받을 수 있으며, 아래의 체크박스에서 repo에 반드시 체크해 주어야 한다. repository 권한에 관한 항목이라서 체크 안해주면 토큰을 받아도 접근이 안 된다. 토큰 번호는 한 번 보면 다시 볼 수 없기 때문에 어디 메모를 해 두어야 한다. </p>
<p>나는 처음에 repo 체크를 안 해서 403오류가 발생했는데, 이 403 오류는 해당 주소에 대해 권한이 없어서 발생하는 것이라고 한다. 혹시나 토큰을 받았는데 403오류가 뜬다면</p>
<pre><code>git remote set-url origin https://github-username@github.com/github-username/github-repository-name.git</code></pre><p>명령어를 통해 기존 원격 저장소의 위치를 바꾸어 보길 바란다. </p>
<h3 id="7-pull-request-보내기">7. Pull Request 보내기</h3>
<h3 id="8-우아한테크코스-지원-플랫폼에서-과제-제출하기">8. 우아한테크코스 지원 플랫폼에서 과제 제출하기</h3>
<p>7과 8은 큰 문제가 없었으므로 생략한다. </p>
<hr>
<h3 id="피드백-정리포수타--공통-피드백--코드-리뷰">피드백 정리(포수타 + 공통 피드백 + 코드 리뷰)</h3>
<h4 id="1주-차-공통-피드백">1주 차 공통 피드백</h4>
<ul>
<li><p>요구사항을 정확히 준수한다</p>
<ul>
<li>2주부터는 요구사항을 꼼꼼히 읽지 않으면 실수하는 부분이 많다고 한다. </li>
</ul>
</li>
<li><p>커밋 메시지를 의미 있게 작성한다</p>
<ul>
<li>커밋 메시지를 의미 있게 작성했다고 생각하나, 다른 사람의 피드백이 아직 없어 고민되는 지점이다. </li>
</ul>
</li>
<li><p>git을 통해 관리할 자원에 대해서도 고려한다</p>
<ul>
<li>node modules 는 package.json 파일이 있으면 설치할 수 있고 버전 관리를 직접 하지 않으므로 git으로 관리하지 않아도 된다. <ul>
<li>아마 git에 node modules 폴더를 올리지 말라는 이야기 같다. 포크한 레포지토리의 .gitignore 파일에 node modules라고 적혀있는데, 이것은 node modules를 git에서 관리하지 않겠다는 의미이다. </li>
</ul>
</li>
<li>Intellij의 .idea 폴더, VS Code의 .vscode 폴더 또한 개발 도구가 자동으로 생성하는 폴더이기 때문에 굳이 git으로 관리하지 않아도 된다. <ul>
<li>이 또한 .vscode 폴더를 깃에 올리지 말라는 이야기 같다. 혹시나 .vscode 폴더가 깃에 올라간다면 .gitignore 파일에 이 폴더를 추가하면 될 듯 하다. </li>
</ul>
</li>
</ul>
</li>
<li><p>Pull Request를 보내기 전 브랜치를 확인한다</p>
<ul>
<li>PR을 한 번 보내면, 굳이 닫지 않아도 커밋함으로써 업데이트가 반영된다고 한다.  </li>
</ul>
</li>
<li><p>이름을 통해 의도를 드러낸다</p>
<ul>
<li>의미 있는 네이밍에 관한 자료 정리가 필요할 듯 하다. 이 부분은 다른 분들의 코드 리뷰로 더욱 뼈저리게 느꼈다. </li>
<li>예를 들어, 나는 pobi = [123,124]일 때, pobi[1]-pobi[0]으로 페이지 유효성 검사를 해줬는데 배열 디스트럭처링 할당으로 좀 더 의미 있는 변수명 형성이 가능하다. 예를 들어 const [PobiLeftPage,PobiRightPage] = pobi 라고 할당을 해주면 숫자가 각각 이름이 붙어 PobiRightPage-PobiLeftPage 처럼 의미 있는 변수 형성이 가능하다. </li>
<li>나는 369게임에서 369의 갯수를 나타내는 변수를 sum이라고 지어줬는데, 369count라고 쓰면 더욱 변수가 이해하기 쉽다. </li>
</ul>
</li>
<li><p>축약하지 않는다</p>
<ul>
<li>의도를 드러낼 수 있으면 변수가 길어저도 괜찮다고는 하는데, 긴 변수들이 밀집되어 있으면 가독성이 너무 떨어져서 긴 변수를 사용하더라도 가독성 있게 표현하는 것에 신경을 쓰려고 한다. </li>
</ul>
</li>
<li><p>공백도 코딩 컨벤션이다</p>
<ul>
<li>이 부분은 이미 잘 지키고 있다고 생각한다. </li>
</ul>
</li>
<li><p>의미 없는 주석을 달지 않는다</p>
<ul>
<li>웬만하면 주석을 달지 않으려고 노력 중이다. 주석을 다는 대신 기능별로 분리하여 커밋 내용에서 그 기능을 담으려고 노력했다. </li>
</ul>
</li>
<li><p>linter와 Code Formatter의 기능을 활용한다</p>
<ul>
<li>linter와 prettier 설치는 했는데, 자동으로 검사해 주는 줄 알았다... 실행을 했어야 했다.. 다음에는 꼭 사용해야겠다.🥲</li>
</ul>
</li>
<li><p>EOL(End Of Line)
최종 제출하는 코드에서 EOL을 확인한다. 환경에 따라 의도한 바와 다르게 개행 문자 처리가 되지 않도록 EOL 설정을 확인한다.</p>
<ul>
<li>이 부분이 좀 이해가 되지 않는 부분인데.. 운영체제 별로 개행 문자가 달라져서 설정을 통해 확인해 줘야 한다는 것까진 이해가 된다. 그런데 현재는 코치님 컴퓨터가 어떤 운영체제인지 모르는데 설정을 해줄 수 있나..? 고민이 좀 필요한 지점이다. </li>
</ul>
</li>
<li><p>불필요한 console.log를 남기지 않는다</p>
<ul>
<li>이 부분도 잘 지키고 있다고 생각한다. </li>
</ul>
</li>
<li><p>JavaScript에서 제공하는 API를 적극 활용한다</p>
<ul>
<li>항상 내장함수를 우선적으로 사용하려고 노력하고 있다. 보통 코드가 좀 더 가독성 있게 바뀌기 때문이다. </li>
</ul>
</li>
<li><p>기능 목록을 구현할 때는 </p>
<ol>
<li>최대한 빠르게 피드백 받을만하게 작게 쪼갠다.</li>
<li>쪼갠 다음 나만의 기준을 세워 묶는다.</li>
<li>작게 쪼갤 수록 문제를 해결하기 쉽다.</li>
<li>순서대로가 아니라 핵심적인 것을 먼저 구현해 나간다.</li>
</ol>
</li>
<li><p>읽어보고 이해하기 쉬우면 좋은 커밋이다. </p>
</li>
<li><p>+) 다른 분의 코드를 보니까 @parm 이라는 것을 계속 사용하시던데 이것에 대한 공부도 필요해 보인다. </p>
</li>
</ul>
<hr>
<h3 id="소감">소감</h3>
<p>코드 작성에서 오랜 시간이 걸릴 줄 알았으나, 터미널을 잘 몰라서 터미널 쪽에서 문제가 많이 생겼다. 터미널은 여러 가지 문제를 겪으면서 익숙해졌으니 다음에는 시간이 좀 덜 걸릴 것이라고 생각한다.</p>
<p>기능 목록을 작성하고 변수 이름을 정하고, 커밋 메시지를 정하는 것이 가장 시간이 오래 걸렸다. 다른 사람 눈에 어떻게 보일지 고민이 많이 되었기 때문이다. 고민하는 것도 중요한데, 다른 사람의 피드백을 받으니 확실히 개선될 수 있을 것 같다. </p>
<p>혹시 도움을 주실 수 있다면 <a href="https://github.com/woowacourse-precourse/javascript-onboarding/pull/138/commits/492f238c7cc91af0eb9b46101c121a0e3baf569d">PR LINK</a>로 코드 리뷰 한 번 부탁드립니다😄</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[삼총사(Javascript)]]></title>
            <link>https://velog.io/@ge-um/%EC%82%BC%EC%B4%9D%EC%82%AC</link>
            <guid>https://velog.io/@ge-um/%EC%82%BC%EC%B4%9D%EC%82%AC</guid>
            <pubDate>Tue, 25 Oct 2022 06:22:10 GMT</pubDate>
            <description><![CDATA[<p>한국중학교에 다니는 학생들은 각자 정수 번호를 갖고 있습니다. 이 학교 학생 3명의 정수 번호를 더했을 때 0이 되면 3명의 학생은 삼총사라고 합니다. 예를 들어, 5명의 학생이 있고, 각각의 정수 번호가 순서대로 -2, 3, 0, 2, -5일 때, 첫 번째, 세 번째, 네 번째 학생의 정수 번호를 더하면 0이므로 세 학생은 삼총사입니다. 또한, 두 번째, 네 번째, 다섯 번째 학생의 정수 번호를 더해도 0이므로 세 학생도 삼총사입니다. 따라서 이 경우 한국중학교에서는 두 가지 방법으로 삼총사를 만들 수 있습니다.</p>
<p>한국중학교 학생들의 번호를 나타내는 정수 배열 number가 매개변수로 주어질 때, 학생들 중 삼총사를 만들 수 있는 방법의 수를 return 하도록 solution 함수를 완성하세요.</p>
<h4 id="제한사항">제한사항</h4>
<ul>
<li>3 ≤ number의 길이 ≤ 13</li>
<li>-1,000 ≤ number의 각 원소 ≤ 1,000</li>
<li>서로 다른 학생의 정수 번호가 같을 수 있습니다.</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>number|result
|:-:|:-:|
[-2, 3, 0, 2, -5]|2
[-3, -2, -1, 0, 1, 2, 3]|5
[-1, 1, -1, 1]|0</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1
문제 예시와 같습니다.</p>
<p>입출력 예 #2
학생들의 정수 번호 쌍 (-3, 0, 3), (-2, 0, 2), (-1, 0, 1), (-2, -1, 3), (-3, 1, 2) 이 삼총사가 될 수 있으므로, 5를 return 합니다.</p>
<p>입출력 예 #3
삼총사가 될 수 있는 방법이 없습니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(number) {
    let sum = 0;
    for(let i = 0; i &lt; number.length; i++){
        for(let j = i+1; j &lt; number.length; j++){
            for(let k = j+1; k &lt; number.length; k++)
                if(number[i]+number[j]+number[k] === 0)
                    sum += 1;
        }
    }
    return sum;
}</code></pre>
<p>3개를 골라내면 되니까 반복문 3개를 중첩해서 순열을 골라 주었다. 순열을 고른다고 하면 왼쪽에서 골랐던 것을 제외하고 오른쪽에서만 고르면 되기 때문에 시작을 각각 i+1, j+1에서 해주면 된다. 만약 합이 0이라면 sum에 1을 더해 주었다. </p>
<p>for문 3개 정도는 중첩해 줬지만 이런식으로 조합을 구하면 골라야 할 수가 커질 때 너무 많은 for문을 중첩하게 된다. 따라서 골라야할 숫자가 커지면 재귀함수를 이용하는것이 좋다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(number) {
    let result = 0;

    const combination = (current, start) =&gt; {
        if (current.length === 3) {
            result += current.reduce((acc, cur) =&gt; acc + cur, 0) === 0 ? 1 : 0;
            return;
        }

        for (let i = start; i &lt; number.length; i++) {
            combination([...current, number[i]], i + 1);
        }
    }
    combination([], 0);
    return result;
}</code></pre>
<p>재귀함수를 이용한 풀이이다. 재귀함수가 실행되는 과정을 하나하나 살펴보겠다.</p>
<p>number이 [-2, 3, 0, 2, -5]라고 가정해 보자. combination = 
(current,start) 부분은 함수를 정의하는 부분이기 때문에 쭉 넘어간 다음, combination([],0) 부분에서 함수를 호출한다. current.length === 1이므로 for문을 돌게 된다.</p>
<p>그리고 for문(i=0)을 돌며 combination([-2],1)을 호출한다. 호출된 combination([-2],1)은 다시 combination([-2,3],2)를, combination([-2,3,0],3)을 호출한다. current.length가 3이므로 result값에 배열의 합이 0이라면 1을 더해 주고 리턴해 준다. 그래서 combination([-2,3,0],3)을 종료하고 다시 combination([-2,3],2)로 돌아간다. </p>
<p>다음 for문으로 돌아가면 i는 1을 증가시킨 3이 되므로, 
1을 증가시켜서 [-2,3]에 number[3], 즉 2를 결합한combination([-2,3,2],4)를 호출하고, 순차적으로 combination([2,3,-5],5)를 호출한 다음 반복문을 종료시킨다. 이 반복문이 종료되었기 때문에 이번에는 combination([-2],1)로 돌아가게 된다. </p>
<p>이번에도 i가 1 증가하기 때문에 combination([-2,0],3)를 호출하고, combination([-2,0,2],4), combination([-2,0,5],5)를 차례차례 호출하여 모든 조합을 검사하게 만들어 준다. 이렇게 재귀적으로 자기 자신을 호출하다가 모든 for문이 끝나면 종료된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[예상 대진표]]></title>
            <link>https://velog.io/@ge-um/%EC%98%88%EC%83%81-%EB%8C%80%EC%A7%84%ED%91%9C</link>
            <guid>https://velog.io/@ge-um/%EC%98%88%EC%83%81-%EB%8C%80%EC%A7%84%ED%91%9C</guid>
            <pubDate>Mon, 24 Oct 2022 13:24:22 GMT</pubDate>
            <description><![CDATA[<p>△△ 게임대회가 개최되었습니다. 이 대회는 N명이 참가하고, 토너먼트 형식으로 진행됩니다. N명의 참가자는 각각 1부터 N번을 차례대로 배정받습니다. 그리고, 1번↔2번, 3번↔4번, ... , N-1번↔N번의 참가자끼리 게임을 진행합니다. 각 게임에서 이긴 사람은 다음 라운드에 진출할 수 있습니다. 이때, 다음 라운드에 진출할 참가자의 번호는 다시 1번부터 N/2번을 차례대로 배정받습니다. 만약 1번↔2번 끼리 겨루는 게임에서 2번이 승리했다면 다음 라운드에서 1번을 부여받고, 3번↔4번에서 겨루는 게임에서 3번이 승리했다면 다음 라운드에서 2번을 부여받게 됩니다. 게임은 최종 한 명이 남을 때까지 진행됩니다.</p>
<p>이때, 처음 라운드에서 A번을 가진 참가자는 경쟁자로 생각하는 B번 참가자와 몇 번째 라운드에서 만나는지 궁금해졌습니다. 게임 참가자 수 N, 참가자 번호 A, 경쟁자 번호 B가 함수 solution의 매개변수로 주어질 때, 처음 라운드에서 A번을 가진 참가자는 경쟁자로 생각하는 B번 참가자와 몇 번째 라운드에서 만나는지 return 하는 solution 함수를 완성해 주세요. 단, A번 참가자와 B번 참가자는 서로 붙게 되기 전까지 항상 이긴다고 가정합니다.</p>
<h4 id="제한사항">제한사항</h4>
<p>N : 21 이상 220 이하인 자연수 (2의 지수 승으로 주어지므로 부전승은 발생하지 않습니다.)
A, B : N 이하인 자연수 (단, A ≠ B 입니다.)</p>
<h4 id="입출력-예">입출력 예</h4>
<p>N|A|B|answer
|:-:|:-:|:-:|
8|4|7|3</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1
첫 번째 라운드에서 4번 참가자는 3번 참가자와 붙게 되고, 7번 참가자는 8번 참가자와 붙게 됩니다. 항상 이긴다고 가정했으므로 4번 참가자는 다음 라운드에서 2번이 되고, 7번 참가자는 4번이 됩니다. 두 번째 라운드에서 2번은 1번과 붙게 되고, 4번은 3번과 붙게 됩니다. 항상 이긴다고 가정했으므로 2번은 다음 라운드에서 1번이 되고, 4번은 2번이 됩니다. 세 번째 라운드에서 1번과 2번으로 두 참가자가 붙게 되므로 3을 return 하면 됩니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(n,a,b){
    let sum = 0;
    for(let i = 0; a !== b; i++){
        a = Math.ceil(a/2)
        b = Math.ceil(b/2)
        sum += 1;  
    }
    return sum;
}</code></pre>
<p>반복문을 사용하여 a와 b를 2로 나눈 다음 올림한 값을 비교하여, 그 값이 같다면 반복문을 종료해 준다. 처음에는 a !== b 대신 두 값을 뺐을 때 절댓값이 1이라면 반복문을 종료해 줬는데(Math.abs(a-b)&gt;1), 이런 식으로 조건을 주면 4와 5일 때는 3번째에 만나지만 반복문 자체가 돌지 않는다. 따라서 굳이 절댓값을 쓰자면 종료 조건에 Math.abs(a-b)를 써줄 수도 있고, 간단하게 a!==b를 써줄 수도 있다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(n,a,b)
{
    let answer = 0;
    while(a !== b) {
        a = Math.ceil(a/2);
        b = Math.ceil(b/2);
        answer++;
    }

    return answer;
}</code></pre>
<p>아무 생각 없이 For문을 써줬는데, 어차피 인덱스가 중요하지 않으므로 while문으로 써 주면 필요없는 값을 써주지 않아도 된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[숫자의 표현(Javascript)]]></title>
            <link>https://velog.io/@ge-um/%EC%88%AB%EC%9E%90%EC%9D%98-%ED%91%9C%ED%98%84</link>
            <guid>https://velog.io/@ge-um/%EC%88%AB%EC%9E%90%EC%9D%98-%ED%91%9C%ED%98%84</guid>
            <pubDate>Sat, 22 Oct 2022 10:14:38 GMT</pubDate>
            <description><![CDATA[<p>Finn은 요즘 수학공부에 빠져 있습니다. 수학 공부를 하던 Finn은 자연수 n을 연속한 자연수들로 표현 하는 방법이 여러개라는 사실을 알게 되었습니다. 예를들어 15는 다음과 같이 4가지로 표현 할 수 있습니다.</p>
<ul>
<li>1 + 2 + 3 + 4 + 5 = 15</li>
<li>4 + 5 + 6 = 15</li>
<li>7 + 8 = 15</li>
<li>15 = 15
자연수 n이 매개변수로 주어질 때, 연속된 자연수들로 n을 표현하는 방법의 수를 return하는 solution를 완성해주세요.</li>
</ul>
<h4 id="제한사항">제한사항</h4>
<ul>
<li>n은 10,000 이하의 자연수 입니다.</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>n|result
|:-:|:-:|
15|4</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예#1
문제의 예시와 같습니다.</p>
<pre><code class="language-javascript">function solution(n) {
    let sum = 1;
    for(let i = 2; i * (i+1) / 2 &lt;= n; i++){
        if((n - i * (i+1) / 2) % i === 0)
            sum += 1;
    }
    return sum;
}</code></pre>
<p>i개의 연속된 숫자로 이루어져 있는지 판별하려면 1에서 i까지의 합을 숫자 n에서 빼준 다음, 그 숫자가 i로 나누어지는지 확인해 보면 된다. 예를 들어, 15를 2개의 연속된 수로 이루어진 합으로 이루어지는지 확인해보고 싶다면, 1+2(3) 을 15에서 빼 준 다음(12), 12가 2로 나누어지는지 확인해 보면 된다. 그 배열은 2로 나눠진 값 6에 각각 1, 2를 더한 7,8이 될 것이다. 이것을 활용하여 i개의 연속되는 합으로 만들수 있다면 1을 더해 주었다. 만약 1에서 i까지의 합이 n보다 크다면 성립할 수 없기 때문에, 합이 n보다 작을떄까지 i를 검사해 주었다. </p>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function expressions(num) {
    var answer = 0;

  for(var i=1; i&lt;=num; i++) {
    if (num%i == 0 &amp;&amp; i%2 == 1)
      answer++
  }
    return answer;
}</code></pre>
<p>정수론에 따르면, 수가 홀수일 때 약수의 갯수를 구하면 연속된 수의 합의 갯수를 구할 수 있다고 한다. 15를 예를 들어 생각해 보면, 15의 약수는 1,3,5,15가 있다.</p>
<ul>
<li>1 : 하나의 자연수 15로 이루어져 있다.</li>
<li>3 : 약수가 3이므로 15는 5+5+5이다. 여기서 조작을 살짝 가하면 연속되는 수의 합 4+5+6이 된다.</li>
<li>5 : 약수가 5이므로 15는 3+3+3+3+3이다. 여기서 조작을 살짝 가하면 연속되는 수의 합 1+2+3+4+5가 된다.</li>
<li>15 : 2n+1(홀수)는 항상 n+n+1 이라는 연속적인 합으로 나타낼 수 있다. 여기서는 7+8이다. </li>
</ul>
<p>이것을 활용하여 연속되는 숫자 합의 갯수를 세 줄 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[짝지어 제거하기(Javascript)]]></title>
            <link>https://velog.io/@ge-um/%EC%A7%9D%EC%A7%80%EC%96%B4-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ge-um/%EC%A7%9D%EC%A7%80%EC%96%B4-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 22 Oct 2022 09:17:26 GMT</pubDate>
            <description><![CDATA[<p>짝지어 제거하기는, 알파벳 소문자로 이루어진 문자열을 가지고 시작합니다. 먼저 문자열에서 같은 알파벳이 2개 붙어 있는 짝을 찾습니다. 그다음, 그 둘을 제거한 뒤, 앞뒤로 문자열을 이어 붙입니다. 이 과정을 반복해서 문자열을 모두 제거한다면 짝지어 제거하기가 종료됩니다. 문자열 S가 주어졌을 때, 짝지어 제거하기를 성공적으로 수행할 수 있는지 반환하는 함수를 완성해 주세요. 성공적으로 수행할 수 있으면 1을, 아닐 경우 0을 리턴해주면 됩니다.</p>
<p>예를 들어, 문자열 S = baabaa 라면</p>
<p>b aa baa → bb aa → aa →</p>
<p>의 순서로 문자열을 모두 제거할 수 있으므로 1을 반환합니다.</p>
<h4 id="제한사항">제한사항</h4>
<ul>
<li>문자열의 길이 : 1,000,000이하의 자연수</li>
<li>문자열은 모두 소문자로 이루어져 있습니다.</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>s|result
|:-:|:-:|
baabaa|1
cdcd|0</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>입출력 예 #1
위의 예시와 같습니다.</p>
<p>입출력 예 #2
문자열이 남아있지만 짝지어 제거할 수 있는 문자열이 더 이상 존재하지 않기 때문에 0을 반환합니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(s){
    let arr = [s[0]]
    for(let i = 1; i &lt; s.length; i++){
        if(arr[arr.length-1] === s[i])
            arr.pop()
        else
            arr.push(s[i])
    }
    return arr.length === 0 ? 1 : 0;
}</code></pre>
<p>처음에는 match와 replace를 사용해서 문자열에서 겹치는 부분을 제거해 주었는데, 효율성 부분에서 탈락했다. 이렇게 푸는 것 보다 스택을 이용하면 효율적으로 문제 풀이가 가능하다. </p>
<h4 id="실패한-풀이">실패한 풀이</h4>
<pre><code class="language-javascript">function solution(s){
   while(s.match(/(\w)\1/) !== null){
        s = s.replace(/(\w)\1/g,&#39;&#39;);
    }
    return s.length ? 0 : 1;
}</code></pre>
<p>시간초과가 되었다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[피보나치 수(Javascript)]]></title>
            <link>https://velog.io/@ge-um/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%EC%88%98</link>
            <guid>https://velog.io/@ge-um/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%EC%88%98</guid>
            <pubDate>Fri, 21 Oct 2022 14:28:29 GMT</pubDate>
            <description><![CDATA[<p>피보나치 수는 F(0) = 0, F(1) = 1일 때, 1 이상의 n에 대하여 F(n) = F(n-1) + F(n-2) 가 적용되는 수 입니다.</p>
<p>예를들어</p>
<ul>
<li>F(2) = F(0) + F(1) = 0 + 1 = 1</li>
<li>F(3) = F(1) + F(2) = 1 + 1 = 2</li>
<li>F(4) = F(2) + F(3) = 1 + 2 = 3</li>
<li>F(5) = F(3) + F(4) = 2 + 3 = 5
와 같이 이어집니다.</li>
</ul>
<p>2 이상의 n이 입력되었을 때, n번째 피보나치 수를 1234567으로 나눈 나머지를 리턴하는 함수, solution을 완성해 주세요.</p>
<h4 id="제한-사항">제한 사항</h4>
<ul>
<li>n은 2 이상 100,000 이하인 자연수입니다.</li>
</ul>
<h4 id="입출력-예">입출력 예</h4>
<p>n|return
|:-:|:-:|
3|2
5|5</p>
<h4 id="입출력-예-설명">입출력 예 설명</h4>
<p>피보나치수는 0번째부터 0, 1, 1, 2, 3, 5, ... 와 같이 이어집니다.</p>
<h4 id="나의-풀이">나의 풀이</h4>
<pre><code class="language-javascript">function solution(n) {
    let arr = [0,1];
    for(let i = 2; i &lt;= n; i++){
        arr.push((arr[i-1]+arr[i-2]) % 1234567)
    }
    return arr[n] 
}</code></pre>
<p>배열을 활용하여 피보나치수열을 하나씩 배열에 넣어 주었다. 여기서 테스트 7번부터 전부 오류가 떴다. 알고보니 자바스크립트에서 원시값 Number이 표현할 수 있는 수는 2^53 - 1까지인데 피보나치수열은 그 값을 넘어가기 때문인듯 했다. 그래서 애초에 1234567로 나눈 나머지의 값을 배열에 넣어주고, 그 값을 리턴해 주었다. </p>
<h4 id="틀린-풀이">틀린 풀이</h4>
<pre><code class="language-javascript">function solution(n) {
    let arr = [0,1];
    for(let i = 2; i &lt;= n; i++){
        arr.push(arr[i-1]+arr[i-2])
    }
    return arr[n] % 1234567
}</code></pre>
<h4 id="참고할-풀이">참고할 풀이</h4>
<pre><code class="language-javascript">function solution(n) {
      var a = 0, b = 1, f = 0;
  for (var i = 2; i &lt;= n; i++) {
    f = (a + b) % 1234567;
    a = b % 1234567;
    b = f % 1234567;
  }
  return f;
}</code></pre>
<p>이런 식으로 배열에 넣지 않고 값을 하나하나 1234567로 나눈 값을 더해서 검사할 수도 있다. 이 위에서는 사용하지 않았지만, <code>(A + B) % C = ( ( A % C ) + ( B % C) ) % C</code> 라는 성질도 있어 값이 좀 더 커진다면 최종값을 1234567로 한 번 더 나눠줘도 똑같은 결과가 나온다. </p>
]]></description>
        </item>
    </channel>
</rss>