[초보자들] S70 스터디 세번째 후기


자바스크립트 언어의 기초인 함수를 알아가보는 S70 세번째 강의가 진행되었습니다. 캡슐화와 은닉이라는 개념과 함수를 통해 이를 어떻게 활용하는지 코드 리팩토링을 해보는 시간이었습니다. 아직까지 여전히 어려운 함수지만 새로운 것을 알게되는 재미가 솔솔하죠~ 계속 배우고 배워도 너무 새로운 것은 함정! 이번엔 어떤 개념들이 있었는지 후기를 통해 공유해봅시다^^

Refactoring 1top

프로그램 개발은 큰 덩어리를 가져와 깎아 나가는 조각에 가깝습니다. 그래서 2강에서 만들어보았던 To-Do 프로그램 코드를 리팩토링하면서 좀 더 좋은 코드로 깎아 나가보도록 합니다.

To-Do 프로그램의 문제 중에 하나는 ‘할 일’을 담고 있는 tasks 배열과 각 ‘할 일’이 가질 수 있는 state(상태)인 STATE_P와 STATE_C가 밖에 노출되어 있다는 것입니다.
사용자는 tasks에 ‘할 일’ 객체를 추가하는 것을 addTask 함수를 통해서 하고, tasks에서 ‘할 일’ 객체를 삭제하는 것을 removeTask 함수를 통해서 하고, ‘할 일’의 state를 STATE_P 또는 STATE_C와 같은 값으로 바꾸는 것을 changeState 함수를 통해서 하길 원합니다.
하지만 함수를 통하지 않고 console에서 직접 건드릴 수 있게 노출 되어있죠.

이 문제부터 해결해봅시다. 우리는 To-Do 프로그램 입장에서 바깥으로 알려주고 싶지 않은 것은 숨기고 싶습니다. tasks, STATE_P, STATE_C를 알지 못 하게, 직접 접근할 수 없도록 말이죠.

몸은 안 보여줄거야~
<영화 ‘해리포터와 비밀의 방’의 투명망토>

1강 때 scope를 배웠었습니다. <click! 1강 후기 보러가기>
scope에 값들을 가둬두고 그 외부의 그 누구에게도 알려주지 않도록 했고, javascript에서는 함수로 scope를 만든다고 했습니다.
지금 이 문제를 해결하기 위해 To-Do 프로그램 코드를 IIFE(즉시 실행 함수)로 감싸겠습니다. <click! 전체 코드 보기>

(function(){
    var tasks = [];
    
    var STATE_P = '진행';
    var STATE_C = '완료';
    
    var addTask = (function(){ ... })();
    var removeTask = function(id){ ... };
    var changeState = function(id, state){ ... };
    var warning = console.log;
    var render = function(){ ... };
})();

tasks와 STATE_P, STATE_C를 IIFE로 인해 생긴 스코프에 가두어 바깥으로부터 숨겨버렸습니다. 이를 은닉이라고 합니다. 은닉을 통해 To-Do 프로그램안에서만 이 값들에 직접 접근할 수 있는 권한을 갖게된 것입니다.
그런데 바깥에서 addTask, removeTask, changeState 함수도 접근할 수 없게 되었네요ㅠㅠ IIFE에서 바깥쪽으로 저 함수들만 노출할 방법이 필요합니다.

함수의 반환값으로 노출시키면 되지 않을까요? 그러나 함수는 하나의 값만 반환할 수 있는데 우리가 노출하고 싶은 것은 적어도 3개(함수 3개)입니다.
이 때 object를 사용합니다. IIFE에서 마지막에 반환할 때 object 하나를 반환하고, 그 object에는 우리가 노출하고 싶은 함수 3개를 넣어놓는 것이죠. 그리고 반환된 object는 변수 todo에 받도록 합니다. <click! 전체 코드 보기>

var todo = (function(){
    var tasks = [];
    
    var STATE_P = '진행';
    var STATE_C = '완료';
    
    var addTask = (function(){ ... })();
    var removeTask = function(id){ ... };
    var changeState = function(id, state){ ... };
    var warning = console.log;
    var render = function(){ ... };
    
    return {
        addTask : addTask,
        removeTask: removeTask,
        changeState: changeState
    }
})();

변수 todo에 함수 3개가 담겨져 있는 object가 할당되어 To-Do 프로그램 바깥쪽에서 함수들을 호출할 수 있게되었습니다.

사람의, 사람에 의한, 사람을 위한top

To-Do 프로그램에서 은닉을 위해 IIFE로 감싸고 3개의 함수를 담은 object를 반환했습니다. 이 때 반환되는 값을 todo 변수로 받았죠. 이를 실제로 사용하는 코드를 볼까요?

todo.addTask('S70 복습!');

addTask라는 함수명은 ‘할 일을 추가한다’라는 의미로 지어진 것입니다. 하지만 이미 변수명 todo가 무엇을 추가하는지에 대한 의미를 대신하고 있기때문에 오히려 함수명의 Task라는 단어가 의미의 중복을 만들고 있습니다.

이름을 짓는 것은 사람을 위한 것입니다.
그래서 사람이 어떻게 인식할 것인지를 많이 고민하여 이름을 지어야합니다. 특히 함수명은 함수를 가져다 사용할 사람을 위해서 지어야겠죠. 즉 addTask 함수를 노출할 때 함수명은 add만으로 충분하다는 것입니다.
함수의 진짜 이름과 바깥으로 노출하는 이름을 달리하겠습니다. 이와 마찬가지로 removeTask 함수도 노출할 때 remove로 하면 되겠네요.

//코드에서 object를 반환하는 부분만 보겠습니다.
return {
    add: addTask,
    remove: removeTask,
    changeState: changeState
};

Refactoring 2top

좀 더 좋은 코드로 깎아 보기 위해 changeState 함수를 보겠습니다. changeState 함수는 ‘할 일’의 state(상태)를 변경하기 위한 함수입니다.

var changeState = function(id, state){
    var ID = false, STATE;
    for(var i = 0; i < tasks.length; i++){
        if(tasks[i].id === id){
            ID = id;
            break;
        }
    }
    if(ID === false) {
        warning('changeState : invalid id - ' + id);
        return;
    }
    if(STATE_P !== state && STATE_C !== state){
        warning('changeState : invalid state - ' + state);
        return;
    }else{
        STATE = state;
    }
 
    for(var i =0; i< tasks.length; i++){
        if(tasks[i].id === ID){
            tasks[i].state = STATE;
            break;
        }
    }
    render();
};

우리는 사용자에게 state 값을 입력받습니다. 입력받은 state는 두개의 상수(STATE_P, STATE_C) 중 하나의 값과 일치해야하구요. 즉 ‘진행’ 또는 ‘완료’라고 정확하게 입력해야하는 거죠.
그런데 ‘할 일’의 state값은 두개의 상수(STATE_P, STATE_C) 중에 하나로 밖에 바꾸지 못 합니다. 상태를 켰다(진행) 껐다(완료)하는 toggle 키같은 것이죠. 그렇다면 굳이 사용자에게 state라는 값을 받을 필요가 있을까요? 입력받은 ‘할 일’에 state가 진행이라면 완료로 바꿔주고, 완료라면 진행으로 바꿔주면 되지 않을까요?

우리는 사용자의 편리성을 위해 changeState 함수는 은닉하고, 추상적인 레벨에서 사용할 수 있는 함수를 노출시키겠습니다. ‘이 함수명은 사람이 잘 인식할 수 있도록 toggle이라고 이름 짓는게 좋겠죠?!’

return {
    add: addTask,
    remove: removeTask,
    toggle: function(id){
        for (var i = 0; i < tasks.length; i++) {
            if (tasks[i].id === id) {
                if (tasks[i].state === STATE_P) changeState(id, STATE_C);
                else changeState(id, STATE_P);
 
                break;
            }
        }
    }
};

changeState 함수는 굉장히 기계적인 레벨이었습니다. 이를 기저레벨, 저수준레벨 이라고 부르기도 합니다.
이제는 실제 바깥쪽에 toggle 함수를 노출시켜 To-Do 프로그램의 사용성을 높였습니다. 심지어 사용자가 state를 잘 못 입력할 가능성도 없어졌죠.
즉 절차적이고 복잡한 것은 은닉시키고 추상화 레벨에서 사용할 수 있는 인터페이스를 제공하는 것을 캡슐화라고 합니다.

캡슐화 성공 사례

코드의 의도top

changState 함수는 입력 인자 state의 유효성을 검사합니다. 그 이유는 외부로 부터 받는 값이 STATE_P, STATE_C 값과 일치하게 입력된다고 확신할 수 없기 때문이었죠.

var changeState = function(id, state){
    ...
    if(STATE_P !== state && STATE_C !== state){
        warning('changeState : invalid state - ' + state);
        return;
    }else{
        STATE = state;
    }
    ...
};

하지만 이제 캡슐화로 changeState 함수는 toggle 함수에서만 호출되어집니다. 그리고 toggle에서 보내는 state 값은 하드코딩되어 있죠. 따라서 유효성 검사를 할 이유가 없습니다. ‘근데… 남겨둬도 구동에 문제가 없는데?! 수정을 해도 되고 안해도 되는거 아냐??’

놉!

이는 절대 옵션이 아닙니다. 코드는 정확한 의도를 갖고 거기에 맞춰서 짜야합니다. 이 코드를 읽는 사람이 의도를 알 수 있도록 말이죠.

var changeState = function(id, state){
    var ID = false, STATE;
    for(var i = 0; i < tasks.length; i++){
        if(tasks[i].id === id){
            ID = id;
            break;
        }
    }
    if(ID === false) {
        warning('changeState : invalid id - ' + id);
        return;
    }
    STATE = state;
    for(var i =0; i< tasks.length; i++){
        if(tasks[i].id === ID){
            tasks[i].state = STATE;
            break;
        }
    }
    render();
};

입력 인자 state의 유효성 검사 코드를 제거했습니다. 이를 숙련된 개발자가 본다면 ‘어? state는 유효성 검사를 안했네? 오류인가?’라고 의심을 하고 ‘아~ 내부함수였네!’라고 깨달음을 얻으며 의도에 맞는 해석을 할 수 있습니다.
그런데 여기서 state의 유효성 검사 코드를 빼지 않았다면, 이 코드의 의도를 잘 못 해석할 수 있습니다. ‘어? state 유효성 검사를 하네? 외부로 노출되는 함수인가보다. 그래서 유효성을 검사하는구나.’라고 해석할 수 있는거죠.

역할이 바뀌었음에도 잘 구동된다고해서 코드를 수정하지 않는 것은 절대 안됩니다. 역할이 바뀌고 의도가 바뀐다면 그 모든 것이 다 반영되어야한다는 것을 명심해야겠습니다.

은닉 ≠ 캡슐화top

많은 사람들이 은닉과 캡슐화를 매우 비슷한 단어 또는 동일한 개념이라고 혼동하기도 합니다. 아마도 ‘캡슐화하는건 감춰놓는거니까 은닉되는거 아냐?’ 라는 생각때문일 것입니다.
물론 캡슐화는 은닉을 통해서 만들어 지는 경우가 많습니다. 하지만 은닉되었다고 해서 캡슐화가 달성된 것도 아니며, 은닉과 캡슐화는 목적 자체가 다릅니다.

위에서 To-Do 프로그램은 tasks라는 값을 은닉했습니다. 왜 은닉했을까요?
To-Do 프로그램 입장에서 바깥쪽은 tasks를 직접 만질 권한이나 자격이 없다고 생각했기 때문입니다. ‘tasks는 나만 만들 수 있어! 그러니까 너희는 addTask 사용해서 만들어 달라고 해~’ 라고 말이죠.
즉 은닉은 가지고 있는 자원에 대한 접근 권한을 설정하는 행위를 말합니다. 저의 몸무게를 의사에겐 알 권한을 주고 애인에겐 감추는 것처럼요ㅠㅠ…

그런데 캡슐화도 은닉을 하던데.. 캡슐화는 무슨 목적을 가졌을까요?
위에서 changeState 함수를 대신해 toggle 함수를 노출한 것. 그것이 바로 캡슐화입니다. 여기서 changeState 함수를 은닉했었는데, 이 때 은닉한 이유는 권한을 제어하기 위해서가 아니었습니다.
사용자가 이해할 수 있도록, 사용자가 안전하게 또는 편리하게 또는 일관성 있게 사용할 수 있도록 이라는 다양한 목적에 의해 추상화된 인터페이스를 공개하는 것입니다.
모든 자동차가 좀 더 캡슐화되서 자동운전이 되었으면…

네이티브 함수 분리top

native와 native가 아닌 것이 무엇인지 기억나시나요? 전 2강 후기를 적으며 이 부분이 힘들었어서.. 기억이 났어요ㅠㅠ
native가 아닌것은 일반적으로 인메모리(메모리 안에 있는) 객체라고 부릅니다. 변수를 선언하거나 배열, 객체를 만들면 현재 실행 중인 메모리에 로드되니까요. 이렇게 인메모리 객체만을 다루는 함수를 순수한 로직 함수라고 부르고, 인메모리 객체가 아닌 다른 객체까지 건드리는 함수를 native 함수라고 부른다고 했습니다.
native 함수의 대표적인 예가 console.log인데요. 우리가 console.log 함수를 만들지 않았지만 시스템에서 제공해주고 있죠. 그래서 console.log의 동작 과정은 모르지만 무언가를 주면 브라우저 콘솔창에 출력을 해준다는 인터페이스만을 알고 사용하는 것입니다.

To-Do 프로그램 코드를 보면 철저하게 native 함수를 분리해 render 함수로 빼놓았습니다. 그리고 addTask, removeTask, changeState, Toggle 함수에서 순수하게 인메모리 객체인 tasks만 다루도록 하고 native 함수가 개입하려고 한다면 render 함수를 호출하는 것입니다.
즉 render 함수는 순수 함수와 native 함수를 연결짓는 가교 역할을 하는 것이죠.

Native 월드로 가는 다리! Render교

현재 To-Do 프로그램은 console에만 출력하는 프로그램입니다. 이를 html로도 출력할 수 있는 프로그램으로 발전시켜보고 싶습니다. 그럼 render 함수의 역할이 바뀔 것입니다. console에 그릴지 html에 그릴지를 결정할 mode라는 값을 만들고, 그 값에 따라 native 함수를 연결해주는 것으로 재정의 해야합니다.
따라서 기존 render 함수는 console에만 출력해주므로 renderConsole이라고 바꾸고, html에 출력해주는 renderHtml 함수를 만들고, render 함수를 재정의 해봅시다!

// render 함수가 어떤 native 함수로 연결할지 판단하기 위한 mode라는 값을 만듭니다.
var mode = 'console'; // mode의 기본값은 console로 세팅!

// render 함수를 재정의합니다.
var render = function(){
    if(mode === 'console') renderConsole();
    else if(mode === 'html') renderHtml();
};

//기존 render 함수를 renderConsole로 바꿨습니다.
var renderConsole = function(){
    var task;
    console.log('진행');
    for(var i = 0; i < tasks.length; i++){
        task = tasks[i];
        if(task.state === '진행'){
            console.log(task.id+'.', task.title+'('+task.state+')');
        }
    }
    console.log('완료');
    for(var i = 0; i < tasks.length; i++){
        task = tasks[i];
        if(task.state === '완료'){
            console.log(task.id+'.', task.title+'('+task.state+')');
        }
    }
};

// html에 출력해줄 함수를 만듭니다.
var renderHtml = function(){
    // html에 tasks 값을 예쁘게 출력할 곳입니다.
};

이렇게 하면 인메모리 함수(addTask, removeTask 등..)은 render 함수만을 알면되고, 진짜 render 기능을 수행하는 함수(renderConsole, renderHtml)은 render 함수만 알고 있으면 됩니다.
어?! 방금 내용에 한번 더 집중해 봅시다. renderConsole, renderHtml 함수는 오직 render 함수만이 그 존재를 알고 있으면 된다라는 내용이요. 이 내용대로 즉시 반영해야겠죠?

var mode = 'console';
var render = (function(){
    var renderConsole = function(){
        // console에 tasks 값을 예쁘게 출력하는 코드입니다.
    };
    var renderHtml = function(){
        // html에 tasks 값을 예쁘게 출력하는 코드입니다.
    };
    return function(){
        if(mode === 'console') renderConsole();
        else if(mode === 'html') renderHtml();
    };
})();

addTask, removeTask와 같은 함수들은 renderConsole을 호출하고 싶어도 호출할 수가 없습니다. 존재를 모르도록 render 함수 안으로 은닉했으니까요.

mode 값만 바꾸면 원하는 곳(console 또는 html)에 출력할 수 있어요!!

근데 mode는 어떻게 바꿀 수 있죠? 바깥쪽에서도 mode를 변경할 수 있어야하는데..
아하! 뭘 노출해야될지 알게되었습니다. 바깥쪽에서도 mode의 값을 변경할 수 있도록 캡슐화 단계에서 modeConsole, modeHtml 함수를 만들어 노출하죠.
근데 왜 mode 바꾸는 함수를 두 개나 만드냐구요? 인자없는 함수가 제일 좋은 함수랍니다~ 그래서 인자 받아서 모드를 어떻게 바꿀지 결정하는 것보단 인자없는 함수 2개를 만들어요~

// To-Do 프로그램에서 바깥으로 노출하는 return 문 부분입니다.
return {
    add: addTask,
    remove: removeTask,
    toggle: function(id){
        ...
    },
    modeConsole: function(){
        mode = 'console';
    },
    modeHtml: function(){
        mode = 'html';
    }
};  

짠! 남은 것은 html로 예쁘게 출력해보는 일만 남았네요~ renderHtml 함수를 만들어서 출력하면 되겠죠?
하지만 renderHtml 함수를 바로 만들 순 없어요. 왜냐면 어떤 모양으로 출력할지도 모르니까요ㅠㅠ

예쁜 htmltop

그럼 어떤 모양으로 출력을 할지 정해봅시다. 모양을 잡아보는 방법에는 여러가지가 있지만 index.html이라는 진짜 html 문서를 작성해서 모양을 잡아보도록 했습니다. 먼저 html의 기본형태부터 적어보죠.

<html>
<head></head>
<body>
	<!-- 여기에 html 태그로 작성할거에요. -->
	<script src=“script.js”></script>
</body>
</html>

우리가 짠 코드는 script.js 파일로 분리해 html 문서에서 불러오도록 하죠. 이 때 body 태그 끝부분 직전에 script를 불러오도록 합니다. 이유는 생략해요~

이제 body 안에 section을 만들고, 바로 이 section이 우리의 To-Do 프로그램을 예쁘게 그려줄 캔버스가 됩니다.
그래서 section에는 ‘To-Do 프로그램 캔버스야!’라고 id로 표시합시다. id를 정할 때 주의할 점! 일반명사로 id를 정하면 중복될 가능성이 커요. 그래서 고유명사로 이름을 지어요~

<html>
<head></head>
<body>
    <section id="todo">
        <!-- 여기가 바로 To-Do 프로그램 구역입니다~ -->
    </section>
    <script src=“script.js”></script>
</body>
</html>

console로 출력할 때 모양이 기억나시나요? 진행중인 할 일의 목록과 완료된 할 일의 목록을 출력했었죠. 그리고 그 목록에 출력된 할 일에는 순서(번호)가 없었어요. 즉 적어도 2개의 목록이 필요하고, 그 목록은 번호가 없어요.
번호가 없는 목록을 그릴 땐 ul 태그를 사용합니다. 그리고 각 목록이 어떤 목록인지를 표시하기 위해 id를 줄게요~

<body>
    <section id="todo">
        <ul id="progress">
        </ul>
        <ul id="complete">
        </ul>
    </section>
    <script src=“script.js”></script>
</body>

html 식별자(id, class)top

section 태그, ul 태그에 이게 무엇인지를 식별할 수 있도록 id를 부여했습니다. 위에서 잠깐 언급했듯이 일반명사로 식별자로 주면 안됩니다. 그래서 section 태그에는 todo라는 식별자를 부여했습니다.
그런데 ul 태그의 progress, complete라는 식별자는 To-Do 프로그램용이라고 할 수 있을까요? 다른 프로그램에도 이런 식별자를 사용하지 않을까요?
이 두개의 ul을 To-Do 프로그램용으로 식별자를 주려면 todo_progress, todo_complete가 어떨까요?
id가 점점 길어지고 서술적으로 변하네요.. 사실 처음부터 ul 태그는 todo에 포함되어 있는 것들로 봐야합니다. 즉 todo 소속의 progress, todo 소속의 complete인거죠. 그래서 id가 아닌 class를 사용해야합니다.

<body>
    <section id="todo">
        <ul class="progress">
        </ul>
        <ul class="complete">
        </ul>
    </section>
    <script src=“script.js”></script>
</body>

이번 강의 이전에도 실습을 통해서든 업무를 통해서든 많지는 않지만 html 문서를 작성해왔습니다. id와 class를 사용해봤죠. 하지만 id와 class를 식별자로써 고민하며 정하지 않았습니다.
앞으로 html 문서에서 식별자인 id에 대한 깊은 고민을 할 줄 알아야겠습니다.

시멘틱 태그top

여기까지 목록에 대한 html 코드를 작성해보았습니다. 이제 할 일을 추가하는 인터페이스와 목록 안의 할 일 하나하나의 모양에 대해 생각하고 코드를 구성해보겠습니다.

할 일 추가하는 인터페이스는 어디에 있는 것이 좋을까요? 목록이 길어질 수도 있기 때문에 목록보다는 위에 있는 것이 좋겠죠. 그리고 그 안에는 텍스트 입력창과 추가버튼(add) 정도가 있겠네요.

<body>
    <section id="todo">
        <form>
            <input type="text" />
            <input type="submit" />
        <form>
        <ul class="progress">
        </ul>
        <ul class="complete">
        </ul>
    </section>
    <script src=“script.js”></script>
</body>

여기서 텍스트 입력창과 추가 버튼이 있는 할 일을 추가하는 영역은 section이 아닌 form 태그를 사용했습니다. 또한 추가버튼은 왜 button 태그를 사용하지 않고 input 태그를 사용했습니다. 왜일까요?
태그를 짤 때는 각 역할에 맞게끔 짜야합니다. 이를 시멘틱 태그라고 하죠.
할 일을 추가하는 것은 사용자와 텍스트를 입력하고 그 값을 프로그램으로 제출하는 곳입니다. 이렇게 사용자가 프로그램 사용하면서 상호간 작용하는 것을 인터렉션이라 하며 이들은 section이 아닌 form 태그로 묶는 것입니다.
추가버튼 또한 값을 제출하는 의미를 담을 수 있도록 button 태그가 아닌 input 태그의 submit 타입으로 만들어졌습니다.

할 일 추가 인터페이스를 넣었으니 다음으로 추가한 할 일을 보여줄 목록의 아이템의 견본을 시멘틱하게 보겠습니다.
진행중인 할 일에는 할 일 내용과 완료버튼(toggle)과 삭제버튼(remove)이 있을 것이고, 완료된 할 일에는 할 일 내용과 진행버튼(toggle)과 삭제버튼(remove)이 있을 것입니다.

<body>
    <section id="todo">
        <form>
            <input type="text" />
            <input type="submit" />
        <form>
        <ul class="progress">
        <li>
            <p>S70 복습하기!</p>
            <input type="button" value="완료" />
            <input type="button" value="삭제" />
        </li>
        </ul>
        <ul class="complete">
        <li>
            <p>S70 강의듣기!</p>
            <input type="button" value="진행" />
            <input type="button" value="삭제" />
        </li>
        </ul>
    </section>
    <script src=“script.js”></script>
</body>

이를 실행해 화면이 어떻게 출력되고 있는지 확인해보았습니다.

각 목록의 구분이 가지 않습니다. h1태그를 사용해 목록의 이름이 보이도록 하고, h1태그와 ul 태그를 section으로 감싸도록 할게요.

<body>
    <section id="todo">
        <form>
            <input type="text" />
            <input type="submit" value="추가" />
        </form>
        <section>
            <h1>진행</h1>
            <ul class="progress">
            <li>
                <p>할일</p>
                <input type="button" value="완료" />
                <input type="button" value="삭제" />
            </li>
            </ul>
        </section>
        <section>
            <h1>완료</h1>
            <ul class="complete">
            <li>
                <p>할일</p>
                <input type="button" value="진행" />
                <input type="button" value="삭제" />
            </li>
            </ul>
        </section>
    </section>
    <script src=“script.js”></script>
</body>

드디어 To-Do 프로그램의 html로 출력한 모양이 완성되었습니다.

html 태그를 짤 때는 디자인을 어떻게 생길지 고려하면 안됩니다. ‘디자인은 태그를 짠 후 나중에 css로 모두 가능해요!
html 태그는 무조건 바른 의미에 맞춰 짜도록 합시다!

renderHtml 기초공사top

renderHtml 함수는 항상 일관성있게 데이터를 화면에 재갱신 하는 일을 합니다. 이 때 화면에서 section 전체가 아닌 ul안에 내용만 갱신하면됩니다. 설계도를 짜볼까요?

var renderHtml = function(){
    console.log('// 각 목록(진행, 완료)을 비운다.');
    console.log('// 진행 목록(ul)에 li를 채운다.');
    console.log('// 완료 목록(ul)에 li를 채운다.');
    console.log('// 할일 입력창을 비운다.');
};

renderHtml 함수는 ul태그 안을 비우고 나면 우리가 견본으로 만들어 놓은 모양대로 li태그를 채워야합니다. 그러기 위해서는 li태그 본이 필요하고 progressLi, completeLi 라는 변수를 만들어 이를 저장해 놓아야합니다.

본을 빼서 저장하는 것은 rendering 시 매번 할 필요는 없죠. 프로그램을 시작할 때 처음 한번만 하면됩니다. 이처럼
프로그램 동작의 최초에 필요한 값(progressLi, completeLi)들을 사용가능 상태로 만드는 것을 초기화(initialize)라고 부릅니다.
초기화 과정을 실행하는 함수가 필요합니다. 함수명은 의미있게 init 이라고 하죠.
현재 init 함수는 console에 출력할 때는 필요하지 않고 html로 출력할 때만 필요합니다. 즉 mode 값에 맞춰서 실행하는 것이죠. 전체적인 틀은 render 함수와 비슷한 것 같지 않나요?

var init = (function(){
    var initHtml = function(){
        // initialize
    };
    return function(){
        if(mode === 'html') initHtml();
    }
})();

init 함수가 할 일은 li의 본을 빼내서 저장해 놓는 것입니다. 이 본은 renderHtml 함수에서도 사용되어야 하므로 init 함수 바깥쪽으로 노출해야하지만, 그 외의 다른 함수는 알 필요가 없습니다. 그래서 init 함수와 render 함수를 새로운 스코프로 묶어버리는 것이 좋겠습니다.

var init, render;
(function(){
    var completeLi, progressLi;
    init = (function(){
        var initHtml = function(){
            // 본 저장
            progressLi = document.querySelector(‘#todo .progress li’);
            completeLi = document.querySelector(‘#todo .complete li’);
            // ul태그에서 본 빼기
            progressLi.prarentNode.removeChild(progressLi);
            completeLi.prarentNode.removeChild(completeLi);
        };
        return function(){
            if(mode === ‘html’) initHtml();
        }
    })();
 
    render = (function(){
        ...
    })();
})();

renderHtml 코드를 작성하기 위한 모든 준비가 끝난 것 같습니다. 와우!!!!!!!!!! 위에서 미리 짜놓은 설계도대로 코드를 작성해보면 되겠습니다!!!!!!!!!!
다음 강의 시간에 작성해보도록 하죠.

Cuzz you are my girl~~🎶🎶

프로그래밍은 조각하는 것top

이번 후기 처음 시작부분에 ‘프로그램 개발은 큰 덩어리를 가져와 깎아 나가는 조각에 가깝습니다’라고 얘기했습니다.
‘왜죠? 조각보다는 오히려 소조에 가깝지 않나요?’ 라고 생각하시는 분들이 있을겁니다. 빈 문서에서 코드를 작성하면서 무언가를 만들어 나가니까요.
하지만 그렇지 않습니다. 이번 강의에서만 봐도 2강때 만든 To-Do 프로그램 코드를 계속 리팩토링하며 조금 더 은닉을 높이기도 하고 캡슐화를 하면서 더 좋은 코드로 변화 시키고 있죠. 소조처럼 무에서 찰흙을 붙여가며 모양을 만드는 것보다 덩어리(처음 To-Do 프로그램 코드)를 가져다가 좀 더 예쁜 모양으로 깎아 나가는 과정이 더 많았습니다. 예쁘게 깎아 나간다는 것은 코드는 안정화되고 인터페이스가 간단해져 입력값도 단순해지고 은닉이 더 많이 된다는..
그래서 프로그래밍은 예쁜 모양이 나올때까지 깎아가는 과정이라고 보는 것입니다.

그럼 언제까지 깎을까요?? 그건 만족할 때까지 입니다. 언제 만족할 것이냐는 본인이 수준에 따라 다르겠지만요. 그래서 개발자가 최종적으로 깎아 낸 모습으로 노출했을 때 얼마나 예쁜가에 따라 그 사람의 레벨도 알 수 있겠죠.
이번 강의에서 깎아낸 것은 많은 내용을 담고 있었습니다. 후기를 쓰면서 느꼈죠. 이는 절대 저의 레벨에서 깎아낸 것이 아닙니다..

언젠가는 이 정도로 코드를 조각하는 것이 저의 레벨이 될 수 있도록 많은 연습을 해야겠습니다.

멋있고 예쁜고 귀엽고 아름답고 우아하게 깎을거야!

——–S70 스터디 3강 영상 공유

s70 자바스크립트 함수와 객체 3강 – 1

s70 자바스크립트 함수와 객체 3강 – 2



dimanche | bsidesoft 신입사원
좋은 개발자가 뭔지도 모르고 좋은 개발자가 되고 싶은 초보 개발자입니다.
회사에서는 열심히 교육받고 발전하는 운 좋은 개발자로 일하고 있습니다