[Info]Tags categorized posts and contents patterns..

[AJAX] Ajax Code E xamples.. [Book] About the book.. [CSS] CSS Code E xamples.. [DB] Sql Code E xamples.. [DEV] All development stor...

2016년 3월 18일 금요일

[jQuery].prop() 을 이해하기..

바로 앞에 포스팅에서 .hasClass(), .addClass(), .removeClass() 에 대해서 얘기를 했다.. 그런데 마지막에 약간의 여운을 남겨두었지.. 후후.. 좀 헷갈릴수도 있지만, 이렇게 분할해서 각각에 대한 것을 설명하고, 나 스스로도 이해를 해가야 더 기억에 남는다.. 나중에는 좀 더 좋아지것지..

소스는 동일하다 왜냐면, 앞에 포스팅에서는 10라인까지만 설명을 한것이고, 지금은 11라인을 위주로 설명을 하려고 한다..

jQuery
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$('#agree_all').click(function() {
 if($('#agree_all').hasClass('agron')) {
  $('#agree_all').removeClass('agron');
  $('#agree_all').addClass('agr');

 } else {
  $('#agree_all').addClass('agron');
  $('#agree_all').removeClass('agr');

 }
 $('.chk_agr_main').prop('checked'), $('#agree_all').hasClass('agron'));
 
});

HTML
1
2
3
4
5
6
<a href="#none" class="btn type2 agr" id="agree_all">모두 동의합니다.</a>

<input class="chk_agr chk_agr_main" id="chk_agr1" type="checkbox" />
<input class="chk_agr chk_agr_main" id="chk_agr2" type="checkbox" />
<input class="chk_agr chk_agr_main" id="chk_agr3" type="checkbox" />
<input class="chk_agr chk_agr_main" id="chk_agr4" type="checkbox" />

프로세스는 앞에 포스팅에서 언급한 것처럼 if else 를 통과한 후에 11라인을 실행해서 모두 동의합니다를 클릭하면 모두동의 모두동의 취소를 반복한다고 보면 된다..

그런데 위 jQuery 소스에서 11 라인의 의미를 모르니 다음에 더 복잡한 소스에서 상황을 직면하면, 분명 해메일것이다..

.prop() 는 JavaScript 의 프로퍼티[property]를 취급한다.. 

11 라인은 class 명칭이 chk_agr_main 것들에 대해서 checked 를 하라는 것이다.. 단, $('#agree_all').hasClass('agron') 에 따라서 true 또는 false 로 바꾸라는 것이다.. 바꿔말하면, $('.chk_agr_main').prop('checked'), ture); 또는 $('.chk_agr_main').prop('checked'), false); 인것이다..

조금만 알면, 진짜 간단하게 알 수 있는것이지만, 그래도 나에게는 어렵다라기보다 음.. 머라고 해야되지.. 의미를 좀 알아야 좋은것들..??

항상 개발을 하다보면, 세부적인것들에 대해서 이해를 하기보단 전체적인 흐름 및 그 상황을 자체로 이해하고 넘어갔다.. 그러다보니 다음에 또 그 상황을 만나더라도 상황만 알지 세부사항을 모르니 좀 문제가 생기곤 하더라..

더욱 문제는 다시 똑같은 상황을 만나면, 그 때라도 조금씩 세부적인것을 집고 넘어갔어야 이런일이 안생길텐데 또 똑같이 그냥 상황 자체만 이해하고 넘어가버린다.. 그래서 발전이 없는건가.. ㅠㅜ..

무튼!! 그렇기 때문에 아마도 이런 좀 소소한 것들에 대해서 포스팅을 종종하게 될듯한 느낌이다..


[jQuery].hasClass(), .addClass(), .removeClass() 를 접하다..

음.. 업무를 하다가 의미를 몰라서 검색해보고, 찾아봤던 jQuery 를 좀 얘기하려고 한다.. 패턴 자체는 아주 단순한것이지만, 의미를 모르는 것이어서 검색을 했던 것이다..

근무하면서 jQuery 를 사용 해오긴 했지만, 머라고 해야될까 좀 단순한 패턴..?? 항상 하던 패턴..?? 으로만 사용하기도 하고, 개발을 하면서 API 를 찾아본다던지 어떠한 기능이 있는지 사전 공부를 안하니 더욱 모르는 듯 하다.. [그래서 햄처럼 미리 관심을 갖고 공부를 하고, 하는것이 새삼 대단한것이라고 생각을 하게 된다..] 

그리고 만약 애초에 몰랐을 때 몰랐던 부분을 포스팅을 하면서 기록을 하고, 개발을 했었더라면, 지금의 상황과는 많이 틀렸을지도 모르겠다.. 그러니 앞으로 아무리 기초적인것이라도 우선 내가 몰랐다면, 인정하고 정리해서 올리고 넘어가면 된다.. [모르는것이 부끄러운게 아니고, 모르는 것을 아는척하는게 부끄러운 것이라더라..] 정리를 하는 순간 내가 더 집중해서 보고, 몇 차례 더 읽어보고, 업무에서 했던 것이 뼈대가 대기 때문에 더욱 각인이 되고 좋은 듯하다.. 햄의 글을 가져오는 것과는 차원이 틀리다..

오메.. 상황을 얘기하다보니 쓸데없이 너무 길어진 감이 좀 있는듯하다.. 그러면 내가 몰랐던 것을 풀어볼까나..

바로 .hasClass(), .addClass(), .removeClass() 세 가지다..
아래가 해당 소스 부분인데 일부만 가져왔다..

jQuery
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$('#agree_all').click(function() {
 if($('#agree_all').hasClass('agron')) {
  $('#agree_all').removeClass('agron');
  $('#agree_all').addClass('agr');

 } else {
  $('#agree_all').addClass('agron');
  $('#agree_all').removeClass('agr');

 }
 $('.chk_agr_main').prop('checked'), $('#agree_all').hasClass('agron'));
 
});

이해를 돕기 위해서 HTML 파트도 일부만 가져왔다..

HTML
1
2
3
4
5
6
<a href="#none" class="btn type2 agr" id="agree_all">모두 동의합니다.</a>

<input class="chk_agr chk_agr_main" id="chk_agr1" type="checkbox" />
<input class="chk_agr chk_agr_main" id="chk_agr2" type="checkbox" />
<input class="chk_agr chk_agr_main" id="chk_agr3" type="checkbox" />
<input class="chk_agr chk_agr_main" id="chk_agr4" type="checkbox" />

기본적인 패턴을 보자.. HTML 을 보면 눈치가 오는가..?? 모두 동의합니다를 누르면, 아래 4개의 checkbox 가 모두 체크되었다가 풀리고 하는 것이다..
그런데 위 jQuery 소스에서 2, 3, 4 라인에 .hasClass(), .removeClass(), .addClass() 가 보일 것이다.. 1라인에 .click(function() 은 아는 부분이지만, click 이벤트가 발생했을 때 그 안에 부분이 이해가 안갔던 것이다..

2 라인 .hasClass() 를 풀어서 생각하면, 선택한 id="agree_all" 의 class 에 agron 이라는 것이 있느냐 없느냐 하는 것이다.. 즉, 존재 여부에 대한 true/false 의 개념이다.. 고로 $('#agree_all').hasClass('agron') 는 false 다..

3라인 .removeClass() 는 선택한 id="agree_all" 의 class 에 agron 을 삭제하라는 것이다..

4라인 .addClass() 는 3라인과 반대로 선택한 id="agree_all" 의 class 에 agr 을 추가하라는 것이다..

결국 전체적으로 보면, click function 이 발생하면, if else 문에서 true/false 를 확인 한 후에 false 면 if 문으로 true 면 else 로 빠지도록 하는 것이다..

처음에 소스를 봤을 때도 당연히 if else 에 대한 흐름은 파악했지만, 문제는 속성들을 몰랐다.. 그래서 찾아보게 되었고, 몰랐던 것이기에 이렇게 포스팅을 하였다..

아!!! 그리고.. 다음에 11라인을 설명해야 되지만, 이 부분은 별도로 설명을 해야된다는 필요성을 느끼기에 다음 포스팅으로 찾아오겠다..


[Linux]리눅스 기본 명령어 모음..

또또또또!!! 카테고리를 추가했다.. [Linux] 인데 사용한지는 오래됬지만, 항상 기본적인 것 위주로 사용하고, 내가 블로그 한지가 얼마 안되서 이제 카테고리를 추가해서 올려본다..

당장은 기본적인 명령어를 올리지만, 나중에는 조금 더 깊이 있는 것을 사용하게 되면, 또 다른 포스팅을 할 수 있기를 기대해본다.. 뒤에 옵션을 붙인다던지.. ㅋㅋ.. 무튼 검색을 해보니 luna1x 님 블로그에 정리 된 자료가 있어서 가져왔다..

설치
  • wget [URL] : URL에 있는 파일을 다운로드 받는다.
  • rpm
    • rpm -Uvh [rpm] : 패키지를 설치하거나, 업그레이드 한다.
    • rpm -qi [rpm] : 패키지가 설치 되어있는지 확인한다.
    • rpm -e [rpm] : 패키지를 삭제 한다.
  • yum(의존성이 있는 패키지 그룹 단위)
    • yum -y install [패키지] : 패키지를 설치한다.
    • yum -y erase [패키지] : 패키지를 삭제한다.
    • yum list : 설치 가능한 패키지 목록.
    • yum list updates : 업데이트가 가능한 패키지 목록.
    • yum list installed : 설치된 패키지 목록.
    • yum update [패키지] : 패키지명이 없으면 전체 업데이트 있으면 해당 패키지만 업데이트
  • make
    • configure : 컴파일 옵션이 되는 설정파일을 만든다.
    • make : 소스코드를 컴파일 해서 binary 파일을 만든다.
    • make install : 만들어진 binary 파일을 지정된 경로로 이동 시킨다.
    • make uninstall : 설치된 binary 파일을 삭제 한다.

디렉토리
  • pwd : 현재 위치한 디렉토의 절대경로를 출력한다.
  • cd
    • cd [디렉토리] : 디렉토리를 이동할 때에 사용한다.
    • cd .. : 상위 디렉토리로 이동한다.
    • cd ~ : 자신의 홈 디렉토리로 이동한다.
    • cd ~[사용자명] : 특정 사용자의 홈 디렉토리로 이동한다.
  • ls
    • ls : 파일의 목록을 간단히 출력한다.
    • ls -al : 숨겨진 파일을 포함해 자세히 출력한다.
  • mkdir [디렉토리] : 디렉토리를 생성한다.
  • rmdir -p [디렉토리] : 디렉토리를 삭제한다.

파일
  • touch [파일명] : 파일을 만든다.
  • cp [원본] [사본] : 파일을 복사한다.
  • mv [원본] [목적지] : 파일을 이동한다. 이것을 응용해 파일명도 바꿀수 있다.
  • rm
    • rm [파일] : 파일을 삭제한다.
    • rm -rf [파일] : 삭제 동의를 묻지 않고, 파일은 그냥 지우고 디렉리면 하위경로 파일까지 모두 지운다.
  • cat [파일] : 파일의 내용을 출력한다.
  • | : 명령어의 출력결과를 다른 명령어의 입력으로 전환한다. 파이프라고 부른다.
  • less [파일] : 파일의 내용을 한줄씩 출력하고, 위 아래로 이동할수 있다. 출력이 많을때 파이프로 연결해서 많이 사용한다. ex) cat a.log | less
  • find
    • find / -name *linux* : linux가 파일명에 포함된 모든 파일을 찾는다.
    • find / -user linux : 소유자가 linux인 모든 파일을 찾는다.
    • find / -perm 755 : 퍼미션이 755인 모든 파일을 찾는다.
  • grep : 파일 또는 입력값내에서 특정 패턴을 검색한다. 파이프와 조합해서 출력에서 검색하고 싶을때 사용한다. ex) yum list | grep jdk, ps -ef | grep java
  • [명령어] > [파일] : 명령어의 출력을 파일에 저장한다. 덮어쓴다.
  • [명령어] >> [파일] : 명령어의 출력을 파일에 저장한다. 추가한다.
  • [명령어] < [파일] : 파일에서 표준 입력을 받는다.
  • chmod [퍼미션] [파일] : 소유자, 그룹, 다른 사용자가 가지는 퍼미션(읽기, 쓰기, 실행)을 설정한다. 퍼미션은 읽기4, 쓰기2, 실행1을 조합해서 표시한다.
    • chmod 750 [파일] : 소유자 읽고 쓰고 실행 가능, 그룹 읽고 실행 가능
    • chmod 4xxx [파일] : 실행될때 root권한으로 실행된다.
    • chmod 2xxx [파일] [그룹] : 파일에 설정된 그룹명으로 실행된다.
    • chmod 1xxx [디렉토리] : 해당 디렉토리에 누구나 쓰기는 가능하지만, 자신이 만든 파일에 대해서는 자신과 root만이 수정과 삭제가 가능하다.
  • chown [소유자:그룹] [파일] : 파일 소유자와 사용자 그룹을 설정한다.
  • chgrp [그룹] [파일] : 파일 사용자 그룹을 설정한다.
  • chattr +i [파일] : 파일을 수정, 복사, 삭제 할 수 없게 한다.
  • tar
    • tar -cvzf [파일] [경로] : tar로 파일을 압축한다.
    • tar -xvzf [파일] [경로] : tar로 파일을 압축 해제한다.

파일 시스템
  • fdisk -l : 현재 시스템의 파티션 목록과 파티션이 생성안된 disk를 보여준다.
  • fdisk [disk] : disk에 파티션을 생성한다.
  • badblocks -v  [disk] : disk의 배드블록을 체크한다.
  • mkfs -V -t ext4 [장치] : 파일 시스템을 생성한다.
  • mount
    • mount : 현재 마운트된 목록을 보여준다.
    • mount [장치] [디렉토리] : 장치를 디렉토리에 마운트 시킨다.
    • vi /etc/fstab : /etc/fstab을 수정해야 재부팅이 되어도 마운트 설정이 유지된다.
  • umount [디렉토리] : 마운트를 해제한다.
  • df -h : 디스크의 남은 용량을 본다.
  • du
    • du -sh [디렉토리] : 디렉토리의 전체 사용량을 보여준다.
    • du -h [디렉토리] : 모든 하위 디렉토리들의 사용량과 합계를 보여준다.

사용자
  • useradd [사용자명] : 사용자를 생성한다.
  • userdel [사용자명] : 사용자를 제거한다.
  • passwd [사용자명] : 사용자의 비밀번호를 설정한다.
  • groupadd [그룹명] : 그룹을 생성한다.
  • groupdel [그룹명] : 그룹을 삭제한다.
  • id [사용자명] : 사용자의 uid, gid, group을 보여준다.
  • usermod
    • usermod -d [원본홈] -m [변경홈] : 홈디렉토리를 변경하고 파일을 이동한다.
    • usermod -L [사용자명] : 계정을 잠궈서 로그인이 불가능해 진다.
    • usermod -U [사용자명] : 잠긴 계정을 푼다.
  • su – [사용자명] : 다른 사용자의 권한으로 shell을 실행해서, 사용자 전환을 한다.

시간
  • clock
    • clock -r : CMOS 시간을 출력한다.
    • clock -w : 리눅스 시스템 시간으로 CMOS 시간 설정한다.
    • clock -s : CMOS 시간으로 리눅스 시스템 시간 설정한다.
  • date
    • date : 현재 시스템 시간을 출력한다.
    • date [MMDDhhmmYY] : 현재 시스템 시간을 변경한다.

프로세스
  • ps -ef : 현재 실행중인 프로세스의 목록을 보여준다.
  • pgrep -fl [단어] : 해당 단어를 이름으로 가지거나 인자로 받는 프로세스 목록을 보여준다.
    • ex) $pgrep -fl chef
      967 /opt/chef/embedded/bin/ruby /usr/bin/chef-client -d -j /etc/chef/first-boot.json
            970 chef-client worker: ppid=967;start=09:41:34;
           1075 /opt/chef/embedded/bin/ruby /usr/bin/chef-client
           1086 chef-client worker: ppid=1075;start=09:41:37;
  • pkill -f [단어] : 해당 단어를 이름으로 가지거나 인자로 받는 프로세스를 모두 종료 시킨다.
  • pstree : 프로세스 정보를 트리형태로 보여준다.
  • kill
    • kill [PID] : 프로세스를 종료 시킨다.
    • kill -9 [PID] : 프로세스를 강제로 종료 시킨다.
  • top : 프로세스의 CPU, MEMORY 사용량등을 실시간으로 모니터링 해준다.

데몬
  • chkconfig
    • chkconfig –list : 런레벨에 따라 자동으로 실행되는 데몬을 보여준다.
    • chkconfig –add [데몬] : 데몬을 추가한다.
    • chkconfig –del [데몬] : 데몬을 삭제한다.
    • chkconfig –level [런레벨] [데몬] on : 데몬의 런 레벨을 활성화 시킨다.
    • chkconfig –level [런레벨] [데몬] off : 데몬의 런 레벨을 비활성화 시킨다.
  • service
    • service [데몬] status : 데몬 상태를 보여준다.
    • service [데몬] start : 데몬을 시작한다.
    • service [데몬] stop : 데몬을 정지한다.
    • service [데몬] restart : 데몬을 재시작한다.

시스템
  • crontab
    • crontab -e : crontab 설정을 연다.
    • 형식 : 분(0~59) 시간(0~23) 일(1~31) 월(1~12) 요일(0~6) 명령
    • 01 * * * * [명령] : 매시간 1분에 명령 실행한다.
    • 02 4 * * * [명령] : 매일 4시 2분에 명령을 실행한다.
    • 22 4 * * 0 [명령] : 매주 월요일 1일 4시 22분에 명령을 실행한다.
    • */10 * * * * [명령] : 10분마다 명령을 실행한다.
  • uname -a : 커널 버전을 보여준다.
  • poweroff : 종료시킨다.
  • reboot : 재부팅 시킨다.

네트워크
  • ping [호스트] : 다른 시스템의 네트워크가 현재 동작중인지 확인한다.
  • ifconfig
    • ifconfig : 현재 네트워크 인터페이스의 정보를 보여준다.
    • ifconfig [인터페이스] down : 인터페이스를 중지한다.
    • ifconfig [인터페이스] up : 인터페이스를 작동 시킨다.
    • curl ifconfig.me : public ip를 보여준다.
  • nslookup [도메인] : 도메인 정보를 보여준다.
  • netstat
    • netstat -anp  : 네트워크 연결, 라우팅 테이블, 네트워크 장치의 통계정보등 네트워크에 관련된 여러 정보를 보여준다.
    • netstat -anpl : LISTENING 중인 정보만 보여준다.
  • hostname
    • hostname : 현재 시스템의 호스트네임을 보여준다.
    • hostname [변경할네임] : 호스트네임을 변경한다.
    • vi /etc/sysconfig/network : HOSTNAME 항목을 변경해야 리부팅 후에도 변경된 호스트 네임이 유지된다.
  • iptables
    • iptables -A INPUT -s [발신지] –sport [발신지 포트] -d [목적지] –dport [목적지 포트] – j [정책] : 방화벽 정책을 추가한다.
    • iptables -D INPUT [필터링 번호] : 방화벽 정책을 삭제한다.
    • iptables-save : 설정한 방화벽을 저장해서, 재부팅시에도 적용되게 한다.
    • iptables -A INPUT -s 1.1.1.1 -p tcp –dport 8080 -j ACCEPT : 1.1.1.1에서 8080 포트로 tcp 요청하는것을 허락한다.
    • iptables -A INPUT -p tcp –dport 8080 -j DROP : 8080포트로 tcp 요청하는것을 막는다.
    • iptables -A INPUT -p rcp –dport 1:65535 -j DROP : 서비스 이외의 서비스포트 모두 거부한다.
  • nmap [ip] : 현재 오픈되어 있는 포트를 보여준다.

후아 많기도 하다.. 내가 실제 쓰는것은 저기서 몇 개 뿐이 안되지만, 나에게 도움을 주기 위해서..


[Book] Clean Code 클린 코드..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

Clean Code 클린 코드 - 8점
로버트 C. 마틴 지음
박재호.이해영 옮김
케이앤피북스

보통 엉클밥이라는 애칭으로 더 유명한 로버트 C 마틴이 쓴 클린코드에 대한 책입니다. 깨끗한 코드가 무엇이냐라는 부분에서는 부분적으로는 모두 동의는 할 수 없다고 하더라도 전체적으로는 개발자라면 염두에 두어야 할 만한 내용으로 채워져있습니다. 일부부분에 대해서는 약간의 방어막을 치긴 하지만 전체적으로는 강력한 어조로 클린코드가 얘기하는 것들을 지킬 것을 얘기하고 있습니다. 표지디자인은 원서랑 동일하게 맞춘 것으로 알고 있는데 책의 내부 디자인은 약간 교과서처럼 좀 딱딱한 느낌이고 내용을 이해하는 데는 문제가 없지만 중간중간 단어의 사용이나 표현에서 약간씩 어색한 부분이 있는 편입니다. 내용이 아닌 책으로 보자면 세련된 느낌은 아닙니다.(내용을 죽이는것 같아 약간 아쉬운 부분입니다.)

책의 초반부에는 누구나 공감하고 간단히 적용할 수 있는 내용을 위주로 하고 있습니다. 의미있는 네이밍이나 의미가 분명한 한가지 일을 하는 함수, 소스를 설명하는 필요악인 주석은 지워버리라는 등의 얘기들이 있습니다. 중반부부터는 추상화와 예외를 다루고 단위테스트 등 약간 객체지향적인 부분을 설명하고 있습니다. 초반에는 난이도가 있는 부분이 아니라서 상당히 명퀘하게 받아들였지만 뒤로가면서 OOP에 대한 부분도 나오고 동시성에 대한 얘기도 나와서 이해하기 좀 어려운 부분도 있습니다. 뒤로가면 소스도 많이 나오는데 많은 소스에 적은 설명으로 흐름을 쫓아가기 어려워서 후분부에는 상당히 집중하면서 읽기가 어렵기도 했습니다.  뒷부분은 사실 코딩을 해보면서 하면 정말 많은 도움이 될 것 같았는데 아쉽게도 저는 그럴만한 여유는 없었습니다.

인상적인 부분을 몇가지 꼽자면...

  • 자신이 짠 쓰레기 코드를 쳐다보며 나중에 손보겠다고 생각한 경험이 있다. "나중은 결코 오지 않는다."
  • 일정에 쫓기더라도 대다수 관리자는 좋은 코드를 원한다. 그들이 일정과 요구사항을 강력히 요구하는 것은 그들의 책임이기 때문이다.  좋은 코드를 사수하는 것은 바로 우리 프로그래머들의 책임이다.
  • 주석은 나쁜 코드를 보완하지 못한다. 코드로 의도를 표현하라.
  • "돌아가는 코드"가 전문 개발자의 일차적인 의무라 여길지도 모르겠지만 의사소통이 일차적인 의무다.
  • 학습테스트에 드는 비용은 없다. 어쨌든 API를 배워야 하므로 오히려 필요한 지식만 확보하는 손쉬운 방법으로 투자하는 노력보다 얻어지는 성과가 더 크다.
  • 소프트웨어의 가독성은 90% 이름이 결정한다.

편집상태가 약간 아쉽더라고 하더라도 저자의 명성답게 책에 내용은 계속 꼽씹어야 될 만한 내용들로  채워져있습니다.


리딩모임
사실 이 책은 혼자 읽은 것이 아니라 KSUG에서 클린코드 리딩모임을 8월에 진행한다고 해서 같이 참여해서 읽었습니다. 책은 혼자서 읽고 4주동안 매주 모여서 2시간정도의 모임시간동안 읽은 분량에 대해서 이야기를 나누는 방식으로 진행되었었습니다. 사실 책 리딩모임은 처음 참여해 보는 것이었고 모임이 있다길래 책이 혼자보기는 좀 어려울것 같기도 해서 참여하게 되었었습니다. 4주만에 다 읽는다고 해서 약간 부담되기도 했지만 참여하기를 참 잘했다고 생각하고 있습니다.(회사가 멀어서 퇴근하고 열심히 가도 30분 이상씩 지각을 해야해서 다른 참가자분들께는 좀 죄송하기도 했지만요....)

리딩모임이 좋았던 것은 여러가지 어려운 내용도 있었지만 책을 처음부터 계속 같은 집중력으로 읽기는 어렵기 때문에 놓치는 부분이 있기 마련인데 각자 경험이 다르니까 인상깊게 보던 부분도 좀 달랐기 때문에 가볍게 지나친 부분도 리딩모임에서 다시금 볼 수 있었던데다가 다른 사람들의 경험을 같이 공유하다보니 전체적으로 더 깊게 이해할 수 있었던것 같습니다. 혼자 읽었다면 가볍게 읽고 넘어갔을 것 같은데 같이 보다보니까 많은 부분에서 더 깊게 생각하고 고민해 봤기 때문에 더 많이 기억에 남을것 같습니다.

덧) 책의 표지에 "제임스 O. 코플리엔 추천도서"라고 써있는데 저는 사실 누군지 잘 모르겠더군요. 엉클밥이 훨씬 유명한것 같은데요. ㅎㅎㅎ



[EP]테스트 주도 개발(TDD) 실전 프로그래밍 세미나..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

작년에 켄트 벡의 TDDBE를 감명깊게 보았지만 막상 해보지는 못하다가 얼마전에 출간한 테스트 주도 개발 : 고품질 쾌속개발을 위한 TDD 실천법과 도구를 읽고 다시 자극받아 올해는 TDD를 좀 제대로 수련해보자고 요즘 생각하고 있던터에... 주말용 프로젝트에 TDD해보려다가 삽질 좀 해주고 한빛미디어에서 위 책의 저자이신 doortts님세미나를 갔다왔습니다.

세미나는 크게 TDD와 Pair Programming을 나눠서 설명해 주셨습니다. 멀지는 않았지만 퇴근이 7시인데 세미나가 7시라서 사실 반차신공을 발휘하려고 하였으나 요즘 그럴만한 상황이 아니었기에 별수 없이 정상근무를 하고 열심히 갔더니 TDD에 대한 설명은 앞에 40분 정도는 놓쳐버리고 말았습니다.(곧 발표자료도 올려주신다고 하셨고 책에 다 설명해 주신 내용이리라 위안해 봅니다.)

TDD 설명뒤에 간단하게 실습을 하였습니다. 요구사항은 다음과 같았습니다.


- 배열로 받은 수중에 0에 가장 가까운 수를 보여준다.
- 2와 2가 있으면 양수를 가까운 수로 정한다.

이건 TDD로 작성하지 않고 메서드를 바로 작성하게 시키셨습니다. 다 작성한후 제공받은 JUnit 테스트소스를 돌리게 하셨는데 6개 중 2개만 pass했습니다. ㅠㅠ 간단히 수정하긴 했지만 약간 구현하면서 약간 아리까리했던 음수처리 부분에서 문제가 역시나 있었군요.

Pair Programming
두번째 시간은 짝프로그래밍에 대한 부분이었습니다. 짝 프로그래밍에 대해서 알야할 점들을 설명해 주신뒤 50분 정도의 실습에 들어갔습니다만 결론부터 말하자면 저의 짝프로그래밍은 실패였습니다.(처음 해봤는데 안좋은 기억을 가지게 되었군요. ㅠㅠ) 모르시는 분과 했는데 처음해본 터라 To-DO정의부터 구현할 To-Do라기 보다는 Flow를 작성해버린 것이 커뮤니케이션이 어려웠던 가장 큰 이유였던것 같습니다.

제가 네비게이터를 맞았는데 모르는 분이라서 그랬는지 커뮤니케이션도 부족했고 제가 할려는건 제대로 전달되지 않았고 그분이 코딩하려는 것은 뭘하시려고 하는건지 제가 잘 이해를 못하다 보니 처음 네이게이터를 해보면서 급당황하기 시작했고 마이크로 컨트롤하지 말고 인내심을 가지라는 조언에 보다가 얘기하고 하다보니 결국 구현을 못했습니다. 원래는 TDD로 작성했어야 했는데 그냥 구현부터 들어가게 되었음에도 구현은 계속 산으로만 갔습니다. ㅠㅠ

머 아쉽지만 다음에 또 연습해볼 좋은 기회가 있으리라 생각합니다. 앞부분을 못듣기는 했지만 인원수가 좀 적고 실습이 포함된 현실적인 내용들이 있어서인지 많은 도움이 되는 세미나였습니다. 개인적으로는 지난번 JCO세미나때 보다 더 좋았던 것 같습니다.

집에 와서 허니몬님이 하신 것을 보고 저도 연습삼아 혼자서 해봤습니다. 짝프로그래밍은 아니지만 TDD 연습은 될 수 있으니까요..


- 자판기 예제입니다. 거스름돈을 계산하는 부분을 계산합니다.
- 1000원을 넣고 650원짜리 음료수를 선택하면 300원 3개, 50원 1개로 거스름돈을 반환해 줍니다.
- 지폐는 하나만 넣는다고 가정합니다.


Java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// VendingMachine.java
package kr.ne.outsider.tdd;

public class VendingMachine {
    int currentMoney = 0;
    int[] coinUnit = {500, 100, 50, 10};

    public void insertCoin(int money) {
        this.currentMoney = money;
    }

    public int displayMoney() {
        return this.currentMoney;
    }

    public void selectBerage(int priceOfBeverage) {
        this.currentMoney -= priceOfBeverage;
    }

    public String calculateCharge(int chargeCoin) {
        String resultCharge = "";
        
        int coinCount = this.calculateCoinCount(chargeCoin);;
        this.currentMoney -= (chargeCoin * coinCount);
        
        if (coinCount > 0) {
            resultCharge = Integer.toString(chargeCoin) + "*" + Integer.toString(coinCount) + " ";
        }
        return resultCharge;
    }
    
    private int calculateCoinCount(int chargeCoin) {
        int coinCount = this.currentMoney / chargeCoin;
        return coinCount;
    }

    public String returnCharge() {
        String resultCharge = "";
        
        for(int coin: coinUnit) {
            String temp = this.calculateCharge(coin);
            resultCharge += temp;
        }
        return resultCharge;
    }

}

Java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// VendingMachineTest.java
package kr.ne.outsider.tdd;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

public class VendingMachineTest {
    VendingMachine vending;
    
    @Before
    public void setUp() {
        vending = new VendingMachine();
    }
    
    @Test
    public void testDisplayMoney_isDefaultZero() {
        assertEquals(0, vending.displayMoney());
    }
    
    @Test
    public void testInsertCoin_Insert1000() {
        vending.insertCoin(1000);
        assertEquals(1000, vending.displayMoney());
    }
    
    @Test
    public void testSelectBeverage_Insert1000andSelect650() {
        vending.insertCoin(1000);
        vending.selectBerage(650);
        assertEquals(350, vending.displayMoney());
    }
    
    @Test
    public void testCaculateCharge_of500_When_money_is_1000(){
        vending.insertCoin(1000);
        assertEquals("500*2 ", vending.calculateCharge(500));
        assertEquals(0, vending.displayMoney());
    }
    
    @Test
    public void testCaculateCharge_of500_When_money_is_350(){
        vending.insertCoin(350);
        assertEquals("", vending.calculateCharge(500));
        assertEquals(350, vending.displayMoney());
    }
    
    @Test
    public void testCaculateCharge_of500_When_money_is_650(){
        vending.insertCoin(650);
        assertEquals("500*1 ", vending.calculateCharge(500));
        assertEquals(150, vending.displayMoney());
    }
    
    @Test
    public void testReturnCharge_Insert_1000_Select_650() {
        vending.insertCoin(1000);
        vending.selectBerage(650);
        assertEquals("100*3 50*1 ", vending.returnCharge());
    }
    
    @Test
    public void testReturnCharge_Insert_1000_Select_410() {
        vending.insertCoin(1000);
        vending.selectBerage(410);
        assertEquals("500*1 50*1 10*4 ", vending.returnCharge());
    }
}

리펙토링을 해야할게 좀 더 눈에 보이기는 하지만 일단 여기서 마무리 합니다. 하다보니 궁금중이 생기더군요....
  1. 테스트를 만들고 메서드를 만들고 테스트도 더 추가했는데 하고나서 보니 private로 되는게 맞는것 같아서 private로 수정을 하게되니 깨져버린 테스트들은 삭제를 해야하는 것인가 궁금했습니다.(private은 기본적으로는 테스트를 하지 않는다는 데 접근을 public으로 하고 method추출을 했어야 했는데 접근 자체를 잘못한건가 싶기도 하고요. fupfin님은 protected로 테스트한다고 들었는데 어느쪽이 좋을지는 연습을 더 해봐야 할것 같습니다.)
  2. fail과 pass가 주기적으로 반복되어야 하는데 이게 쉽지 않더군요. 처음 실패하는 테스트를 만들고 간단히 성공하는 테스트를 만든 후에는 (간단한 로직이라서 그런지) 그냥 성공상태에서 계속 로직을 작성하게 되더군요. 물론 잘못짰을 때는 failure가 뜨지만요. 배운대로라면 테스트와 로직구현이 반복되어야 하고(이상적으론 30초 주기로 바뀌는게 좋다더군요.) 실패와 성공이 반복되어야 하는데 아직은 감이 잘 안왔습니다. 테스트를 만든 후 성공으로 계속 작성하게 되거나 로직작성후 여러가지 경계조건에 대한 테스트들을 계속 만들게 되더군요.

수련을 더 해야할 것 같습니다. 사실 얼마전에도 주말용 프로젝트인 Javascript코딩에서 TDD를 해보려고 하였지만 상당히 많은 난관에 부딪히면서 결국 좌절하고 말았습니다. 이 부분도 한번 정리는 해보려고 합니다만 너무 무지한 부분이 있어서 좀더 고민해보고 기회가 되면 포스팅을 해야할 것 같습니다.


[HTML]HTML5 마크업 템플릿..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html> 
<html lang="ko"> 
    <head> 
        <meta charset="utf-8" />
        <title>Untitled Document</title>
        
        <link rel="shortcut icon" href=""/>
        <link rel="apple-touch-icon" href=""/>
        
        <link rel="stylesheet" href="" />
        <style>
            
        </style>
        
        <script src=""></script>
        <script>
            
        </script>    
    </head> 
    
    <body>
        
    </body> 
</html>

HTML4나 XHTML 1.0에 비해서는 아주 간결해 졌지만 또 막상작성하려면 헷갈리고 찾아봐야 해서 적어둡니다. 개인적인 용도이기 때문에 HTML5의 많은 기능이나 모바일에 대한 부분까지 모두 고려한 기본 HTML은 아닙니다.

좀 더 자세한 HTML을 원하시면 HTML5 Reset이나 HTML5 BOILERPLATE를 참조하시면 될 것 같습니다.



[JS]자바스크립트 클로저(Closure)에 대해서..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

자바스크립트에는 클로저(Closure)라는 개념이 있습니다. (랭귀지에 따라 클로저가 있는 언어도 있고 그렇지 않은 언어도 있습니다.) 오랫동안 잘 이해하고 있다가 어느정도 이해는 되었지만 아직 몸에 익지 않았다가 최근에 두번이나 클로저로 해결할 문제를 누가 물어와서 정리를 합니다.

클로저는 자신의 범위(Scope) 밖에 있는 변수들에 접근할 수 있는 함수를 의미합니다.

사실 이 말만 가지고는 잘 감이 오지 않고, 보통 자바스크립트내에서는 함수의 생명주기는 끝이났지만 함수내의 변수를 내부함수가 참조하고 있기 때문에 유지되어 접근할수 있는 함수를 클로저라고 합니다.



Html
1
2
3
4
<input type="button" id="btn1"/>
<input type="button" id="btn2"/>
<input type="button" id="btn3"/>
<input type="button" id="btn4"/>

위와 같이 버튼이 4개 있고, 각 버튼을 클릭했을때 각 버튼당 1,2,3,4가 찍히게 하고 싶다고 하겠습니다. 당연히 가장 쉬운 방법은 각 버튼에 인라인으로 onclick="alert('1')" 처럼 각 버튼당 파라미터를 주는 것이 쉽겠지만, 이럴 경우 요즘 일반적인 구조와 동작을 불리하는 Unobtrusive Javascript에도 맞지 않고 유지보수에도 별로 좋지 않습니다. 

일반적으로 사람들이 위와같은 구현을 하기 위해서 가장 먼저 시도하는 코드는 아래와 같을 것입니다.



Html
1
2
3
4
5
6
7
window.onload = function() {
    for(var i=1; i < 5; i++ ) {
        document.getElementById("btn" + i).addEventListener("click", function() {
            alert(i);
        }, false);
    }
}

모두는 아니겠지만 보통 위와같은 코드를 시도하리라고 생각하고 정상적으로 동작할 것을 기대하지만 위 코드는 제대로 동작하지 않습니다. for문을 돌면서 각 버튼에 click이벤트리스너를 등록하고 각 루프에서의 i를 alert으로 보여줍니다. 이렇게 할경우 의도한 것은 1,2,3,4의 alert()을 의도한것이지만 alert()에 넘겨준 파라미터는 i의 값이 아닌 i의 참조이기 때문에 실제 버튼을 클릭하면 모든 버튼을 클릭할 때 i의 최종값이 5가 모두 찍혀버립니다. 

이 상황이 클로저가 적합한 상황인데 클로저를 사용하는 것은 이해만 하면 그렇게 어렵지 않습니다.



Html
1
2
3
4
5
6
7
8
9
window.onload = function() {
    for(var i=1; i < 5; i++ ) {
        (function(m) {
            document.getElementById("btn" + m).addEventListener("click", function() {
                alert(m);
            }, false);
        })(i);
    }
}

위와 같이 작성합니다. for문안에 실행할 구문을 익명함수( (function() {})와 같은 형태)로 만들고는 i를 파라미터로 넘기면서 실행시켜버립니다.(익명함수에 (i)를 붙혀서 바로 실행시켰습니다.) 이렇게 하면 익명함수안의 내부변수인 m에 i의 값이 할당되어 버리고 구조상은 실행뒤에 소멸되어야 하지만 클로저로 인하여 각 값으로 할당된 멤버변수를 각 이벤트리스너에서 그대로 사용할 수 있게 됩니다. 위 코드로 실행하면 각 버튼을 클릭시 1,2,3,4의 원하던 값이 찍히게 됩니다.

덧) 그냥 예제코드이기 때문에 표준인 addEventListener만을 사용했습니다. IE에서 돌려보실 계획이라면 attachEvent를 사용하셔야 합니다.

덧2) 제가 클로저의 개념을 아주 명확히 파악하지 못한관계로 설명이 명확치 않았습니다. 위 소스에 대한 명확한 설명은 아래 댓글에 odyss님이 해주셨으므로 참고해주시기 바랍니다. 공부를 더 열심해야겠군요. ㅠㅠ


odyss | 2010/08/21 23:58

약간 보충설명을 하자면, 첫번째 예제는 클로저의 생성으로 인한 부작용을 보여줍니다.

원래 의도는 각 버튼마다 alert시에 1,2,3,4를 결과로 보여주려는 의도이나 이벤트 핸들러 함수의 i값이 바깥쪽 변수인 i값에 대한 참조를 유지하고 있어, 즉 클로저의 생성으로 인해 최종값인 5를 모두 가리키게 되는 예제입니다.


사실 두번째 예제는 클로저의 부작용을 막기위한 처리로 제시한 예제인데, 이 예제도 클로저가 생성되긴 합니다만 익명함수의 인자로 값을 넘겨버림으로써 바깥쪽 변수인 i에 대한 변수스코프를 끊어버리고, 이벤트 핸들러에서는 익명함수의 인자값에 접근함으로써 의도한 대로 처리가 되게 됩니다.


괄호로 둘러싼 함수표현식 안에서는 바깥쪽 변수에 접근하지 못한다는 것을 여기서 아실 수 있습니다.


My Comment..

해당 글은 Closure [클로저] 에 대한 설명이라서 조금 더 자세하게 읽어보았다.. 이유는 과거 면접 충격 및 블로그 시작 이유 때문이다.. 그런데 내 특성상 그런것인가 직접 사용을 하고 있는게 아니다보니 전체적으로 이해가 안간다.. 아무래도 내가 찾아보고, 나 스스로 이해를 해서 클로저에 대한 글을 다시 올려야겠다.. 햄한테는 미안하지만, 내가 포스팅을 하려고 했던 목록중에 하나이기도 하고, 목록에 포함 되었던 것이기에 기왕이면 이해를 하고서 올리기를 원하기 때문이다.. 자료점 찾아봐야거썽.. ~_~..