2011년 12월 8일 목요일

vi 에서 ^M 지우기.

파일을 FTP 로 올리고 리눅스 vi 로 확인하면 문장 각 끝에 ^M 기호가 붙어 있는 것을 볼 수 있다.

이건 개행문자(줄바꿈문자) 가 깨진 것이다.

별로 실행되는데는 문제가 되지는 않지만 보기 싫으니 지워 버리자.

esc 키를 눌러 명령어 모드로 한후


:%s/^M$//g

마지막 까지 지워진걸 확인 할 수 있다. 

여기서 ^M  문자 입력시 ctrl + V , ctrl+M 키를 눌러야 한다.

찾아보니 윈도우 vi 에서는 ctrl + V가 붙여넣기 단축기라 동작 하지 않는다고 한다. 윈도우 에서는 ctrl+ Q

까먹지 말자.

vi comment





1,n s/^/#/g   앞에 #을 붙임




n,$ s/^#//g   주석 삭제


n은 임의의 라인



2011년 12월 6일 화요일

FlashBuilder 실행 시 failed to create the java virtual machine 가 뜨면,

C:\Program Files\Adobe\Adobe Flash Builder 4.5에 있는 FlashBuilder.ini


열고 -vmargs의 윗라인에 추가한다


-vm
C:\Program Files\Adobe\Adobe Flash Builder 4.5\jre\bin\javaw.exe


2011년 12월 4일 일요일

알아두면 손 발이 편한 du 명령어

디렉토리별로 집계해서 용량순으로 표시하기
du -S | sort -n

지정한 디렉토리만 표시
du -h -s 디렉토리

지정한 디렉토리의 전체 표시
du -h -a 디렉토리

GB이상의 디렉토리를 표시
du -h | grep [0-9]G

100MB이상의 디렉토리를 표시
du -h | grep [0-9][0-9][0-9]M

2011년 11월 30일 수요일

marked as crashed and should be repaired

Problem
디비 서버를 운영하다보면 아래와 같은 에러와 함께 db서버가 죽어버리는 경우가 있다.
091030 13:40:29 [ERROR] /usr/libexec/mysqld: Table ‘.some_table’ is marked as crashed and should be repaired
Solution
mysql> analyze table some_table;
mysql> repaire table some_table;
//위에서 실패하면 아래 실행
]# myisamchk -r some_table;
위와 같이 repair를 하면 쉽게 해결되기는 하지만, 그 원인은 뭘까?
mysql Reference에서 How to Repair MyISAM Tables 페이지에서 찾을 수 있었다.
위의 문제는 다음과 같은 충돌들로 일어날 수 있다.
  • tbl_name.frm이 변경에 대해서 락이 걸려있는 경우
  • tbl_name.MYI(Errcod:nnn)을 찾을 수 없는 경우
  • 파일이 unexpected end일 경우
  • 저장 파일이 충돌했을 경우
  • 테이블 핸들러로부터 nnn에러를 받았을 경우
위에서 말하는 nnn 에러는 system error로 다음 커맨드로 그 의미를 알아볼 수 있다.
]# perror 126 127 132 134 135 136 141 144 145
MySQL error code 126 = Index file is crashed
MySQL error code 127 = Record-file is crashed
MySQL error code 132 = Old database file
MySQL error code 134 = Record was already deleted (or record file crashed)
MySQL error code 135 = No more room in record file
MySQL error code 136 = No more room in index file
MySQL error code 141 = Duplicate unique key or constraint on write or update
MySQL error code 144 = Table is crashed and last repair failed
MySQL error code 145 = Table was marked as crashed and should be repaired
위의 145 번 에러 코드가 이번 경우에 해당 되었다.
참고로 135번과 136번에러는 테이블의 MAX_ROWS와 AVG_ROW_LENGTH를 수정해서 고칠 수 있다.
mysql>ALTER TABLE tbl_name MAX_ROWS=xxxAVG_ROW_LENGTH=yyy;
현재 테이블 옵션이 어떻게 되어 있는지 보려면 아래 명령어로 보자.
mysql>SHOW CREATE TABLE some_table;
다른 에러들에 대한 대처는 myisamchk르 대부분이 찾아내서 고칠 수 있다.
이 작업을 하기 전에 디비 테이블 파일들에 대한 권한을 확인한다.(없으면 부여)
먼저 mysqld서버를 중지한다.(유의: 중지 후 바로 디비 서버가 바로 죽지 않는다. 모든 index 변경사항이 디스크에 플러시 될때까지가 중지되는 시점이다)
Stage 1: 테이블 검사
]# myisamchk *.MYI
이 작업으로 error라고 판별된 테이블에 대해서만 Stage 2에서 고쳐질 수 있으며, 이 커맨드 과정에서 에러(e.g. out of memory)가 나면 Stage 3로 너어가면 된다.
Stage 2: Easy safe repair
]# myisamchk -r -q tbl_name (-r -q 은 “빠른 복구 모드”)
이는 data file을 건들지 않고 index file을 고치는 커맨드이다.
  1. Make a backup of the data file before continuing.
  2. Use myisamchk -r tbl_name (-r means “recovery mode”). This removes incorrect rows and deleted rows from the data file and reconstructs the index file.
  3. If the preceding step fails, use myisamchk –safe-recovertbl_name. Safe recovery mode uses an old recovery method that handles a few cases that regular recovery mode does not (but is slower).
나는 여기까지로 대부분이 해결이 되었다.
stage 3에 대한 방법, 그 외의 방법은 How to Repair MyISAM Tables를 참고하면 되겠다.

MySQL/PgSQL 웹 연동시 too many connection 에러 처리

MySQL이나 PgSQL을 아파치/PHP와 연동하여 사용할 때 db와 연결이 잘 되지 않는 경우가 종종 발생하며 사용자가 많지 않은데도 접속 에러가 뜨는 경우가 많이 있습니다.

이는 db 서버와 웹서버, 그리고 PHP의 설정 파라미터를 조정해 줌으로서 쉽게 해결할 수 있습니다. 점검해볼 항목은 다음과 같습니다.

PgSQL의 경우 /etc/postgresql/postgresql.conf 에 보면

max_connections = 64

와 같은 부분이 있습니다. 이는 PgSQL이 동시에 받아들일 수 있는 최대 접속 수입니다.

아파치 웹서버 설정 파일인 httpd.conf에는

MaxClients 90

과 같은 부분이 있습니다. 이는 아파치 웹서버가 동시에 처리할 수 있는 클라이언트의 숫자입니다.

PgSQL을 예로 들자면, php.ini에 다음과 같은 내용이 있습니다.

pgsql.allow_persistent = On 
pgsql.max_persistent = 2 #max persistant links per process
pgsql.max_links = 16 # max pers/non-pers links per process

여기서 웹서버(PHP)가 PgSQL에 정의된 숫자보다 더 많은 접속을 시도할 경우 접속을 하지 못하고 에러가 발생하게 됩니다.

그러므로 MaxClients * pgsql.max_persistent < max_connections 가 되도록 설정값을 조정해 주어야 합니다.

지금 적힌 대로 시스템이 설정되어 있다면 90 * 2 > 64 이므로 위의 식을 만족하지 못하기 때문에 금방 db 커넥션 관련 에러가 발생하게 됩니다.

웹서버가 좀더 많은 사용자를 커버할 수 있도록 튜닝을 하더라도 위의 공식을 염두에 두고 튜닝을 해야 사용자가 얼마 없는 상황에서 db 접속을 하지 못하는 현상을 방지할 수 있습니다.

만약 위의 경우에서 웹서버와 db서버가 분리된 상태라면 각각의 MaxClients * pgsql.max_persistent 값을 더한 것이 db서버측의 max_connections를 넘지 않도록 튜닝해야 합니다.

MySQL의 경우 wait_timeout값을 매우 짧게 설정함으로서 idle 프로세스를 최대한 줄이는 방법도 있습니다만 db서버와 웹서버의 관계를 잘 고려하여 튜닝을 한다면 같은 하드웨어 사양으로도 좀더 효율적인 튜닝이 가능할 것입니다.

저도 이문제 때문에 한참을 고민하다가 postgresql 메일링 리스트에서 힌트를 얻었습니다. 위의 글은 PgSQL기준이지만 MySQL에서도 기본은 같으므로 따로 설명을 하지는 않겠습니다.

도움이 되었기를 바랍니다....

[mysql]too many connections 해결

mysql을 설치하여 사용하다보면, 서버부하가 없음에도 불구하고 "Warning...too many connections...."라는 메시지와 함께 MySQL 이 뻗어버리는 경우가 있습니다.
원인은 Mysql의 실행환경변수 설정에 있다 .
우선 Mysql설치홈의 bin디렉토리에서 "./mysqladmin -u -p variables"라고 해보시면 다음과 유사한 결과를 얻으실수 있다.

위의 결과에서

max_connections            | 1000
wait_timeout               | 300  

와 같은 것을 볼수 있습니다 .

max_connections는 mysql에 connect할수 있는 최대 갯수를 지정해 둔것이다.
"too many connections"라는 메시지는 이 갯수를 초과해서 connect하려고 할때 발생하는 메시지이다.

결론부터 말씀드리자면 이 갯수를 적절히 조절해야한다고 말씀드릴수 있다.
하지만, max_connections 아래에 있는 wait_timeout이란 variable은 connect된 후에 몇초간 지속적으로 연결을 유지할 것인가를 지정해 둔 것이다.

이를 설명하기 위해서는 mysql_connect()와 mysql_pconnect의 차이점 그리고, mysql_close()함수에 대한 정확한 이해가 필요하다.

간단히 설명해 보자면, mysql_connect()함수로 DB connect를 했다면 해당스크립트가 종료됨과 동시에 mysql_close()함수를 호출하지않아도 자동으로 연결이 종료된다.

하지만, mysql_pconnect()함수는 해당스크립트가 종료된후 mysql_close()함수가 호출되었더라도 연결이 끊어지지않은채로 계속 연결을 유지하고 있다.

따라서, 얼핏보기에는 "too many connections"라는 에러메시지는 mysql_pconnect()라는 함수의 사용때문에 발생하는 것 같지만, 그런 이유도 있을수 있지만, 직접적인 이유는 그것이 아니라 MySQL의 메뉴얼을 보면 mysql_connect()함수를 사용하면 해당스크립트의 종료와 함께 연결이 종료된다고 되어있지만
./mysqladmin -u -p processlist"라는 명령어를 통해서 살펴보면 그대로 살아 있음을 알수 있다.


맨위에서 살펴보았던 "mysqladmin -u -p variables"의 결과로서 볼수 있는 여러가지 시작옵션들중 "wait_timeout"의 값만큼 서버에 그대로 연결을 유지한채로 남아 있는 것이다.

따라서, 이것이 "too many connections"의 직접적인 이유인 것이다.

그렇다면 문제의 해결은 간단하다.

실행옵션을 주어서 이들 값들을 자기가 운용하고 있는 서버의 성능과 용도에 알맞게 수정해 주면 되는 것이다.

MySQL실행시에 주는 실행옵션값은 다음과 같다.

./safe_mysqld -O max_connections=1000 -O table_cache=256 -O wait_timeout=300 &

일반적으로 실행시킬때에는 기본옵션을 그대로 사용하는 "./safe_mysqld"라는 옵션을 사용했다.

이렇게 실행하면 36개의 MySQL시작옵션중에서 위의 3가지 옵션들만 값들을 임의로 지정하여 실행시킨 것이다.
이렇게 실행시킨후에 다시 "mysqladmin -u -p variables"로 옵션들값을 확인해 보면 변경되어 있음을 알수 있을 것이다.

그리고, 참고로 리눅스 실행시에 mysql을 자동으로 시작하도록 설정해둔 /etc/rc.d/rc.local파일에도
위와 같이 옵션을 함께 주어서 실행하도록 설정하는 것을 잊지말기 바란다.

[MYSQL] MySQL 설치/사용시 나는 에러 유형별 대처방법

1. ./configure 시에 에러증상1
checking for tgetent in -lncurses... no
checking for tgetent in -lcurses... no
checking for tgetent in -ltermcap... nochecking for termcap functions library... configure: error: No curses/termcap library found[root@localhost mysql-4.0.13]# makemake: *** No targets specified and no makefile found. stop.
Q1 : 왜 이런 메세지가 뜨냐?
A1: gcc가 없던지 PATH가 안잡혀 있는 경우

Q2 : configure: error: no acceptable C compiler found in $PATH
 설치를 잘못 한건가?
[root@localhost mysql-4.0.13]make 실행 시
make: *** No targets specified and no makefile found.  멈춤.
메세지 뜨는데 어케?

A2 : 리눅스에 gcc가 설치됐는지 확인하라.
# rpm -qa| grep gcc

2. 소스 설치시 "NOTE: This is a MySQL binary distribution." 라는 메시지의 경우Q : It's ready to run, you don't need to configure it! 나옵니다. 이유가?

A : 컴파일이 필요없는 바이너리를 받은거 같다. 이미 컴파일한 거다.
  압축풀고 적당한 위치로 이동시켜라.

tar zxvf mysql-xx.xx.tar.gz
mv mysql-xx.xx /usr/local/
ln -s /usr/local/mysqlxx.xx /usr/local/mysql

3. mysql을 실행하면 (2)번 에러
Q : ERROR 2002: Can't connect to local MySQL server through socket '/var/lib/mysql/m
ysql.sock' (2) 무슨 에러인지요?

A : 데몬 구동시 ./safe_mysqld --user=mysql & 실행 시켜보라.
그래도 에러가 날 경우 ln -s /tmp/mysql.sock /var/lib/mysql/mysql.sock 해보라.

4. mysql.sock 중에 (40)번에러
Q : ERROR 2002: Can't connect to local MySQL server through socket '/var/lib/mysql/m
ysql.sock' (40)

A : chown mysql.mysql -R /var/lib/mysql 를 하기 바란다.
그리고 참고로 php에서의 mysql socket 은 /etc/php.ini 에서 경로를 수정할 수 있다.

5. mysql 데몬이 죽어버릴때
Q : # ./mysqld_safe &
    chown mysql .. <-- 비슷한 오류가 뜨면서 데몬이 죽어버린다.어케?

A : 레드햇 리눅스라면 groupadd 와 useradd 에 '-r' 옵션을 사용하라.
# useradd -r -d /usr/local/mysql mysql
이렇게 하면 500 보다 작은 UID, GID를 가진 mysql 그룹과 사용자가 생성된다.
6. mysql 실행시 데몬 바로 죽음
Q :
030527 22:33:39  mysqld started
030527 22:33:39  Can't start server: Bind on TCP/IP port: 주소가 이미 사용 중
030527 22:33:39  Do you already have another mysqld server running on port: 3306 ?
030527 22:33:39  Aborting
030527 22:39:50  /usr/local/mysql/libexec/mysqld: Shutdown 이 완료됨!
030527 22:39:50  mysqld ended

A : 3306 포트에 이미 다른 mysqld 가 실행되고 있다.
# vi /mysql/scripts/mysql_config 을 열어서 포트번호 수정.

7. mysql-4.0.12 설치후 데몬이 안띄워지고 바로 죽을 경우.
Q 정상적으로 소스 설치하고 나서,,
  /usr/local/mysql/bin/mysqld_safe & 실행하면,,, 데몬이 시작하자 마자 바로 죽는다.
 ./safe_mysqld Starting mysqld daemon with databases from /usr/local/mysql/var
   mysqld ended
에러 메세지를 보기 위해 /usr/local/mysql/var 로 이동  vinnylover.err 파일을 열어보니
아래와 같은 메세지가 있더군.
mysqld started
InnoDB: Started
Fetal error: Can't open privilege tables: Can't find file: ' ./mysql/host.frm'(errno: 13)'
Aborting

A : mysql_install_db 스크립트를 실행해서 초기 테이블을 생성.
   # ./mysql_install_db 하면 된다. (/usr/local/mysql/bin 아래에서 하라)

8. mysql sock 에러 문제의 확실한 해결법
Q : 접속하면 >/var/lib/mysql/mysql.sock ... (111)

A : 디렉토리 퍼미션 문제
# killall mysqld
# chmod 755 -R /var/lib/mysql
# chown mysql.mysql -R /var/lib/mysql
# mysqld_safe --language=korean &

9. make 명령어를 실행하면 설치가 해제
Q : make[2]: *** No rule to make target `ctype-euc_kr.lo', needed by `bmove_upp.lo'. 멈춤.
make[2]: 나감 `/usr/local/down/mysql-3.23.38/libmysql' 디렉토리
make[1]: *** [all-recursive] 오류 1
make[1]: 나감 `/usr/local/down/mysql-3.23.38' 디렉토리
make: *** [all-recursive-am] 오류 2
A : 먼저 LD_LIBRARY_PATH에 모든 라이브러리 경로가 들어가 있어야 한다.
이런 경우때문에 필요한 라이브러리를 찾지못해 에러가 발생.
거의 필요한 패키지를 설치했는데도 에러가 나면 LD_LIBRARY_PATH를 확인해볼 필요가 있다.

10. mysql 설치시 gcc에러나는데 해결책
Q :
# ./configure --prefix=/usr/local/mysql --with-charset=euc_kr
checking for c++... c++
checking whether the C++ compiler (c++   ) works... no
configure: error: installation or configuration problem: C++ compiler cannot create executables.
A : rpm으로 찾아서 다 설치하고 나서 컴파일 하면 된다.
rpmfind.net에서 찾으실 수 있습니다. 에러 보고 하나하나 다 설치하면 된다.

11. 인스톨 설치도중 103 에러
Q : an error occured move data process: -103
compenent : server

A : mysql 설치된 폴더를 완전시 삭제 후 재설치

12. mysql설치 시 invalid user 오류
Q : chown: mysql: invalid user
Starting mysqld daemon with databases from /usr/local/mysql/data
030417 11:42:35  mysqld ended

A : mysql 이란 유져가 유효하지 않다라는 에러로써 현재 mysql이란 계정이 존재하지 않기때문에 나는 에러
# /usr/sbin/useradd mysql -M -s /bin/false
# chown -R root /usr/local/mysql
# chown -R mysql /usr/local/mysql/var
# chgrp -R mysql /usr/local/mysql

13. mysql 4.0.12 설치 시 "Check your system clock" 오류
Q
# ./configure --prefix=/usr/local/mysql --with-charset=euc_kr
이렇게 했는데 다음과 같은 메세지의 경우....
checking build system type... i686-pc-linux
checking host system type... i686-pc-linux
checking target system type... i686-pc-linux
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... configure: error: newly created file is older than distributed files!
Check your system clock

A : mysql이 개발된 시간보다 현재시간 차이로 생기는 문제
인터넷(네트웍)이 되는 상황이라면
# date
# rdate -s time.bora.net   => rdate -s time.nuri.net와 같이 다른서버로 해도 된다.
# date


14. 설치시 configure: error: no acceptable cc found in $PATH 에러
Q :
configure: error: no acceptable cc found in $PATH

A : cc 즉 c complier 가 없다
c 컴파일러가 PATH에 안잡혀 있을 수 있다. path를 추가하거나 gcc를 재설치
# vi /etc/profile
PATH=$PATH:.:/usr/local/mysql/bin

15. config시 ERROR: 1062 Duplicate entry 'localhost-root' for key 1
Q : mysql 소스설치 config시 에러의 경우
rpm버전 삭제했는데 데몬이 살아 있나? ps -ax | grep mysql 하면 암것도 안나온다.
ERROR: 1062 Duplicate entry 'localhost-root' for key 1
ERROR: 1062 Duplicate entry 'localhost-root' for key 1
030312 14:58:03 ./bin/mysqld: Shutdown Complete

A : 캐시에 이전데몬이 살아있기 때문이다.
kill  또는 killall 명령으로 프로세스를 완전히 죽이고 설치하라

16. configure 에러로 "error : No curses/termcap library found" 에러?
Q : checking for termcap functions library...
configure: error : No curses/termcap library found

A : libtermcap-devel-xxx 패키지가 필요해서 발생하는 에러
설치시디를 넣으시고 설치를 하면 해결된다.

2011년 11월 22일 화요일

vim tip

Vim diff 잘써보기
두개의 파일을 비교하는 방법은
vimdiff a.c b.c
이렇게 바로 실행하거나,
1) vim a.c
2) :diffs b.c              (:diffsplit b.c  로도 사용할 수 있습니다.)
3) ^wJ
이렇게 수평으로 열어서 세로로 맞출 수도 있구요.
1) vim a.c
2) :vert diffs b.c         (:vertical diffsplit b.c 로도 사용할 수 있습니다.)
이렇게 한 번에 열수도 있습니다.
1) vim a.c
2) :sp b.c
3) :diffthis
4) ^ww
5) :diffthis
위 방법은 두 개를 열어 놓고, diff 에 참여시키는 방법입니다.
vimdiff 는 vim의 softlink에 불과한데, vim은 구동시에 어떤 이름으로 시작되느냐에 따라 readonly, vi compatible, diff mode 등으로 전환되는 trick을 가지고 있습니다.
이상은 어떻게 하면 비교할 파일을 열어서 보는 다양한 방법을 설명한 것이고, 다음은 비교하는 파일을 편집하는 것을 알아 보겠습니다.
비교하는 파일의 편집이란, 한쪽의 내용을 다른쪽으로 copy하는 것을 말합니다.
:diffget

:diffset
명령입니다. 현재 cursor가 위치한 반대편의 내용으로부터 가져오거나 보내는 것이지요.
단, 복사하자 마자 같은 내용이 되기때문에 diff 화면에서는 사라집니다.
안보이는 거 보이게 하려면
zR
zM
을 사용하세요...
간단한 팁.. 정리해보면..
:diffsplit
:diffget
:diffput
세가지 명령어와
:vertical diffsplit
:diffthis
정도 알아 두시면 더 유용합니다.

Punctuation

쩜(.):period(US), full stop(EN)
샾(#): number sign
언더바(_): underscore
역따옴표(`): grave accent. 여기서 grave는 무덤, 새기다 뜻이 아닌 무겁다, 엄숙하다의 뜻임. grave accent를 우리말로 번역하면 저음 액센트
파이프(|): vertical bar
꺽쇠(^): caret
골뱅이(@): at sign
부등호(<): less-than sign
물결표(~): tilde. 발음은 틸드/틸더
작은따옴표('): apostrophe
부등호(>): greater-than sign
대괄호([]): square brackets 또는 brackets
중괄호({}): curly brackets 또는 braces
소괄호(()): round brackets 또는 parentheses
역슬래쉬(\): Backslash

2011년 11월 20일 일요일

Aptana Studio 2.0 에서 EUC-KR 설정이 안 될 경우.

보통 Eclipse 나 Aptana 에서 한글 설정을 위해

Window->Preferebces 에서

encoding으로 검색하거나 General-> Workspace에서 UTF-8로 해주거나

강제로 셀렉트 박스에다가 EUC-KR을 입력해준다.

그런데 EUC-KR을 해줘도 Apply가 활성이 안 될 경우에는

Aptana 설치 폴더로 가서 JRE 폴더를 삭제 해주면 된다.

아마 Aptana 와 함께 설치 된 Java Machine 에 euckr encoding 이 포함되어 있지 않아 문제


가 발생한 것 같다

2011년 10월 18일 화요일

Git 입문하기

via - http://www.hanb.co.kr/network/view.html?bi_id=1664


Advanced Flash Tactics 또는 AFT(역자주: Advanced Flash Tactics-필자는 오라일리에 짧은 플래시 관련 기사들을 AFT라는 태그로 작성하고 있다.)는 Flash Art Of War(역자주: 플래시 개발에 관한 필자의 블로그)의 깊은 곳에서 꺼낸 기술이다. 이번 AFT로 살펴볼 것은 "Git 입문"이다. 어디서나 플래시 개발자들이 구글 코드(Google Code)를 버리고 저 푸른 GitHub의 초원으로 이주해 가는 것을 볼 수 있다. 지금으로 부터 얼마전에 Git는 그저 버전 관리 도구로 내 시야에 들어왔다 하지만 GitHub가 제공해 주는 멋진 기능들 때문에 결국 Git으로 전환하게 되었고 완전히 정착하게 되었다. 이제, Git를 시작하기 위한 팁들과, 어떻게 github를 사용해야 하는지, 그리고 내가 Git로 전환하기를 권하는 이유를 말 해 보겠다.

그림Git가 무엇인가?

Git는 자유 소프트웨어이며 빠른 속도가 강점인 분산 리비전 관리 또는 소프트웨어 소스 관리 프로젝트이다. Git는 리눅스 커널 개발에 사용하기 위해 리누스 토발츠가 처음 디자인과 개발을 하기 시작했다. 모든 Git 워킹 디렉터리는 완벽하게 독립적인 저장소로 전체 변경 내역과 모든 리비전 트래킹 능력을 갖추고 있으며, 네트워크 접근이나 중앙 서버에 의존적이지 않다. - 위키백과

SVN 대비 장점

Git 는 분산 버전 관리 시스템이다. 기반 코드를 체크아웃하고 변경내용을 커밋하여 돌려주는 여러 방법이 존재한다. 이런 방법의 주요 장점은 여러분의 수정 내용을 매번 마스터 저장소에 커밋해서 올리는 대신 저장소 전체의 로컬 복사본을 사용한다는 것이다. 전통적인 SVN 설정에서는 버전 관리를 하기 위해서는 여러분의 작성한 코드를 반드시 커밋해야 하고, 이 수정 내용이 다른 사람의 작업을 깨트리거나 문제를 일으키기도 한다. Git을 사용하면 각 개발자가 작업을 진행할 수 있는 자신만의 샌드박스를 가지고 있으며, 작업을 마친 뒤에 변경내역을 -마스터 저장소에- 올려 보낼 수(push) 있다.

Git은 프로젝트 정보를 저장하기 위해 하나의 디렉터리를 사용한다. SVN은 모든 디렉터리에 .svn 폴더를 가지고 있어야 하는 반면, Git은 체크아웃 한 루트 디렉터리에 하나의 .git 폴더를 사용하도록 단순화 하였다. 이런 방법은 파일의 내역을 깨지 않은 채로 파일을 이동할 때 큰 장점이 된다. 게다가 Git는 파일을 프로젝트 폴더 안에 어디에 있는지가 아니라 파일의 내용을 분석하는 구분할 만큼 똑똑하기 때문에 이름을 바꾸거나 위치를 이동하는 것으로 파일 내역이 깨지는 일이 없다.

브랜치가 가볍게 만들게 만들어 진다. SVN의 경우 Trunk(주 작업 공간)와 Branch들이 있고 각 브랜치가 소스의 복사본인 것과 달리 Git에서는 모든 것이 브랜치다. Git에서는 새 브랜치가 아주 빠르게 만들어 지며 브랜치 간의 이동도 빠르게 수행된다. Tag를 만드는 것도 놀라울 정도로 쉽다.

Git 은 실제로 SVN 저장소와 함께 운용할 수 있다. Git에는 커밋들을 SVN 저장소로 재 동기(re-sync) 하는 기능이 있고, Git의 속도와 기능들을 사용하고 싶지만 SVN을 사용할 수밖에 없는 환경에 있는 사람들은 이 기능을 사용할 수 있다. 나는 이 기능을 사용하고 있지 않지만 정말로 매끄럽고, 기대한 대로 동작한다고 읽고/들었다. (옮긴이 주: git-svn 이라는 패키지로 검색해 보면 이 기능의 사용법을 찾을 수 있다. 역자의 경우 git-svn을 매우 만족스럽게 매일 사용한다.)

단점

Git는 SVN이나 CVS을 미리 사용해 보지 않았다면 익히기가 쉽지 않다. 복잡한 명령어들의 단축어가 그다지 많지 않으며, revert처럼 SVN에도 같은 이름이 있는 명령어가 Git에서는 다른 동작 행하기도 한다.

Git는 폭넓게 지원되지 않는다. 명령어를 타이핑 하는걸 무서워하는 사람들을 위해 SVN에 있는 것 같은 간단하게 다룰 수 있는 GUI가 Git에는 거의 없다.

Github가 멋진 이유

Github는 코드 저장소일 뿐만 아니라 개발자들 간의 소셜 네트워크 역할을 한다. 나는 생각했던 것만큼 커뮤니티에서 이득을 얻지 못하고 있지만 Github로 만들어진 커뮤니티는 대단하다. 커뮤니티에서는 관심이 가는 개발자를 팔로(follow)할 수 있을 뿐 아니라, 그들의 코드를 포크 (복사한 원본으로의 연결을 간직한 여러분 소유의 브랜치)를 하고 프로젝트에 공헌을 할 수도 있다. 코드베이스(codebase)의 소유자는 여러분이 변경한 내용을 보고 메인 프로젝트에 머지할 수 있다. 또는 여러분만의 독자적인 방향을 잡아 나가는 것도 가능하다.

Github에서는 여러분의 코드에 관심을 가지는 사람들이 다양한 방법으로 코드를 받아 갈 수 있다. 프로젝트를 그들의 로컬 컴퓨터에 클론(clone)할 수도 있고 download를 클릭하여 git 디렉터리를 제외한 프로젝트의 압축파일을 받을 수도 있다. 이 기능은 git를 배우고 싶지 않은 초보자들도 프로젝트의 소스를 받아갈 수 있으며, 프로젝트를 직접 압축해서 올리지 않아도 되기 때문에 기존의 저장소들에 대비해 장점이 된다.

Git 커닝 페이퍼

다음은 내가 매일 기본적으로 사용하는 git 명령어들이다.

  • git init - git 저장소(repo) 만들기
  • git pull - 저장소에서 변경 내용 끌어오기
  • git push - 커밋들을 마스터 저장소에 밀어 넣기. 나는 메인 프로젝트에 밀어 넣기 위해 push origin master를 사용하거나, 태그를 포함해서 모두 밀어넣는 용도로 push --all 를 사용하곤 한다.
  • git tag [TAG NAME] - 여러분의 저장소에 태그를 붙인다. 어떤 태그들이 있는지 보려면 간단히 git tag 를 입력하여 태그 목록을 볼 수 있다.
  • git branch [BRANCH NAME] - 브랜치는 태그와 비슷하다. [BRANCH NAME]을 생략하면 브랜치들의 목록을 볼 수 있고 앞에 * 이 붙은 것이 현재 사용 중인 브랜치다.
  • git checkout [BRANCH NAME] - 다른 브랜치로 이동한다.
  • gitk --ll - 이 명령은 히스토리가 그렇게 많지 않은 저장소에서만 사용하라. 이 명령어는 저장소의 모든 코맨트들과 각 브랜치/태그들을 그림으로 보여주는 도구를 실행한다. 무언가 꼬인 경우나 실수를 고치기 위해 예전으로 되돌아 가야하는 경우 매우 큰 도움이 된다.
Git 자료

케빈 서틀(Kevin Suttle)은 여기와 여기에 매우 훌륭한 Git 자료들을 모아 두었다. 아래의 목록에는 필자가 생각하기에 꼭 읽어야 할 것들을 몇 개 나열했다.마치면서…….

Git를 배우는 진입 장벽만 극복하면 Git 은 놀라운 버전 관리 도구로, 여러분에게 사용해 보길 강력하게 권한다. 여전히 Git를 배우고 있는 중이지만, 나는 사람들의 Git에 대한 질문에 답변을 -할 수 있으면- 다는 것을 즐기고 있다. 이제 나의 플래시 작업흐름에 Git를 적용한 방법에 대한 질문들에는 어느 정도 자유롭게 답변을 할 수 있다. 주저 말고 다른 사람들이 Git를 시작할 수 있도록 조언이나, 링크, 팁들을 남겨 주기 바란다.

유지보수가 어렵게 코딩하는 방법(6-완결)


이 글은 농담일 뿐이다! 혹시라도 이 글의 내택을 있는 그대로 받아들인 이가 있다면 정중히 사과한다. 캐나다 사람은 농담에 :-)를 삽입하는 것을 세련되지 못한 행동으로 받아들인다. 내가 유지보수할 수 있는 코드를 작성하는 방법에 관해 지껄일 때면 사람들은 별로 관심을 가지지 않았다. 어느 날 일을 그르치는 얼간이 같은 행동을 얘기해야 사람들이 더 반응을 보인다는 사실을 알게 됐다. 유지보수 할 수 없는 디자인 패턴을 확인하므로 더 효과적으로 악의적인 혹은 부지불식간에 일어나는 나쁜 일을 예방할 수 있다

잡다한 기법

누군가에게 프로그램을 주면 하루 만에 그를 좌절시킬 수 있다. 그러나 프로그램을 어떻게 사용하는지를 알려줌으로써 그를 평생 좌절시킬 수 있다.
- 아무개씨
재컴파일 하지 마라
가장 사악한 기법부터 살펴보자. 컴파일에 성공해서 실행파일을 만들었다면, 각 모듈에서 소스코드 몇 개를 수정하자. 그러나 이들 파일을 애써 재컴파일할 필요까진 없다. 나중에 디버깅 할 시간이 남았을 때 재컴파일 하면 된다. 운이 지지리 없는 유지보수 프로그래머가 몇 년 후에 코드를 수정하지만 프로그램이 제대로 동작할 리 없다. 아마도 그녀는 자신이 수정한 뭔가에 문제가 있다고 생각할 것이다. 이와 같은 기법으로 우리는 그녀를 몇 주 동안 바쁘게 만들 수 있다.
디버거 차단
줄을 길게 만들어서 디버거를 이용해서 한 줄씩 우리 코드를 이해하려는 사람을 좌절시킬 수 있다. 특히 브레이크 포인트를 잡기 어렵게 if와 then을 한 줄에 모두 사용하면 더욱 효과적이다. 그러면 분기문이 어느 문장을 수행하는 것인지 구별하기가 어려워진다.
S.I. vs 미국식 단위
엔지니어링 작업을 할 때 두 가지 방법으로 코드를 만들 수 있다. 하나는 모든 입력을 S.I.(미터법) 단위를 사용하고 나중에 결과를 돌려줄 때에는 사람들이 이용하는 단위로 변환할 수 있다. 다른 방법은 여러 단위를 다양하게 시스템 전체에서 혼합해 사용하는 것이다. 물론 항상 두 번째 방법을 이용하는 것이 좋다. 그게 미국식이다!
CANI
상수 그리고 절대 끝나지 않는 개선작업(Constant And Never-ending Improvement). 우리가 코드를 "개선"하면 사용자도 업그레이드해야 한다. 결국 오래된 버전을 원하는 사람은 아무도 없기 때문이다. 프로그램 자체로도 그렇게 좋아한다면, 문제를 "수정"한 버전을 내놓았을 때에는 얼마나 기뻐할지 생각해보라! 누군가가 묻지 않는 한 절대 버전 변경의 차이를 말하지 마라. 알려주지 않았으면 알아차리지도 못했을 예전 버그를 왜 알려줘야 하는가?
프로그램 정보
프로그램 정보란에는 프로그램 이름, 코더 이름, 난해한 법률용어를 포함하는 저작권 등을 포함한다. 이 화면에서 재미있는 애니메이션을 보여주는 코드를 실행하는 링크가 있다면 금상첨화다. 그러나 프로그램 정보란에 프로그램의 목적, 마이너 버전, 최신 코드 리비전 날짜, 업데이트를 얻을 수 있는 웹사이트, 저자의 이메일 주소 등은 절대 명시하지 말아야 한다. 이렇게 시간이 흐르면 많은 이들이 각자 서로 다른 버전을 사용하게 할 수 있다. 때로는 N+1 버전을 설치하지도 않고 N+2 버전을 설치하려 하는 이도 있을 것이다.
변화, 변화, 변화하라
버전마다 더 많은 변화를 줄수록 좋다. 사용자가 예전 API나 오래된 사용자 인터페이스를 사용하면서 지루해 하는 것을 원하는 사람은 아무도 없다. 그러나 사용자가 알지 못하는 변경을 하는 것도 나쁘진 않다. 결국 이 모든 변화는 사용자를 긴장시키고, 현실에 안주하지 않게 채찍질 할 것이다.
개별 파일에 C 프로토타입을 추가하라
공통 헤더를 사용하지 않고 개별 파일에 C 프로토타입을 추가하므로 파라미터 데이터 형식을 모든 파일에서 유지하게 하고 컴파일러나 링크가 형식 불일치를 검출하지 못하게 하는 일석 이조 효과를 얻을 수 있다. 이는 32비트에서 64비트 플랫폼으로 포팅할 때 특히 유용하다.
특별한 기술은 필요없다
큰 기술이 있어야 유지보수 할 수 없는 코드를 작성할 수 있는 것은 아니다. 그냥 잡히는 대로 코딩을 시작해보자. 대부분의 관리자는 우리가 만든 코드 줄 수로 생산성을 판단하는 경향이 있다. 따라서 나중에 삭제할 쓸모 없는 코드라도 일단 넣어보자.
한 개의 망치만 사용한다
자신이 잘 아는 도구를 사용해 가볍게 여행하자. 망치 하나만 있으면 모든 문제는 못에 불과하다.
표준을 무시하라
가능하면 프로젝트를 진행하는 언어와 환경에서 수 천명이 사용하는 코딩 표준을 무시해야 한다. 예를 들어 MFC 기반 응용 프로그램을 만들면서 STL 스타일의 코딩 표준을 따르겠다고 주장하자.
일반적인 True, False 규칙을 뒤집어라
일반적인 true, false에 대한 정의를 뒤집어라. 보기보다는 파급효과가 크다. 아래와 같은 정의를,
#define TRUE 0 
#define FALSE 1 
아무도 잘 찾아보지 않을 코드 깊은 곳에 숨겨야 한다. 그리고 프로그램에서는 아래와 같은 비교문을 사용할 수 있다.
if ( var == TRUE ) 
if ( var != FALSE ) 
누군가 위와 같은 중복 문제를 "수정"해서, 다음과 같이 정상적인 방법으로 사용할 가능성도 있다.
if ( var ) 
완전한 사기처럼 보일 수 있겠지만 TRUE와 FALSE가 같은 값을 갖도록 하는 기법도 있다. 1과 2 또는 -1과 0과 같이 교묘하게 변경하는 방법도 바람직하다. 자바에서도 TRUE라는 이름의 정적 상수를 정의함으로써 이 기법을 사용할 수 있다. 자바에는 true라는 내장어가 이미 있기 때문에 우리의 의도를 의심하는 프로그래머가 등장할 수 있다.
서드 파티 라이브러리
프로젝트에 막강한 서드 파티 라이브러리를 포함하고는 사용하지 않는다. 추가하고 사용하진 않았지만, 우리의 이력서 "기타 도구" 부분에 사용하지 않았던 도구 이름을 추가할 수 있다.
라이브러리를 피하라
개발 도구에 포함된 라이브러리를 모른척해야 한다. 비주얼 C++을 사용한다면 MFC나 STL의 존재를 무시하고 문자열이나 배열을 손수 작정할 수 있다. 이렇게 하면서 자신도 모르게 포인터 기술이 좋아지고 동시에 코드를 확장하려는 시도를 좌절시킬 수 있다.
빌드 순서를 만들라
빌드 순서를 정교하게 만들어서 유지보수 프로그래머가 자신이 수정한 파일을 컴파일 하지 못하게 할 수 있다. 숨겨진 SmartJ를 이용해서 make 스크립트를 무용지물로 만들자. 비슷한 방식으로 컴파일러를 클래스로 사용할 수 있다는 사실도 비밀로 간직해야 한다. 죽는 한이 있더라도 파일을 찾고, 직접 컴파일 클래스 sun.tools.javac.Main를 호출하는 간단한 자바 프로그램을 만드는 일이 얼마나 쉬운지를 절대 발설하지 말자.
Make를 이용한 장난질
여러 디렉터리에서 소스를 복사하는 배치 파일을 Make파일로 생성한 다음 어떤 규칙으로 파일을 복사하는지는 문서화하지 않는다. 이 기술을 사용하면 멋진 소스 코드 관리 시스템 없이도 코드 가지치기(branching)를 할 수 있으며 후임자가 어떤 버전의 DoUsefulWork()을 수정해야 하는지 절대 찾을 수 없게 만들 수 있다.
코딩 표준을 수집하라
정사각 박스 제안(Square Box Suggestions)과 같은 유지보수 할 수 있는 코드를 작성하는 방법에 대한 팁을 모두 모아서 대놓고 그 팁을 위반하자.
내가 아니라, IDE!
모든 코드를 makefile로 만들어라. 후임자는 헤더파일을 생성하고 응용 프로그램을 빌드하는 배치파일을 생성하는 makefile을 만들었다는 사실에 감탄할 것이다. 그리고 이를 변경했을 때 어떤 일이 일어날 것인지 알기 어렵고 최신 IDE로 프로젝트를 옮기기도 어렵게 만들 수 있다. 그리고 이미 뇌사 상태에 들어간 NMAKE 버전을 종속성 개념 없이 사용하므로 효과를 극대화 할 수 있다.
회사 코딩 표준을 무시하라
몇몇 회사에서는 프로그램에 숫자 기호 사용을 금지하는 등과 같은 강력한 정책을 적용한다. 이 경우에는 어쩔 수 없이 상수에 이름을 붙여 사용해야 한다. 물론 정책을 와해시키는 것은 간단하다. 예를 들어, 똘똘한 C++ 프로그래머는 다음과 같이 상수를 정의했다.
#define K_ONE 1 
#define K_TWO 2 
#define K_THOUSAND 999 
컴파일러 경고
컴파일러 경고를 모두 수정하지 말고 남겨두는 것이 좋다. Make 파일에 접두어 "-"를 사용하므로 컴파일 에러로 make가 실패하는걸 방지할 수 있다. 실수로 유지보수 프로그래머가 소스 코드에 에러를 저질렀더라도 make는 전체 패키지를 다시 빌드하려 할 것이다. 심지어 운이 좋으면 빌드에 성공한다! 우리 코드를 손수 컴파일 해본 프로그래머라면 컴파일에 실패할 것이고, 기존 코드나 헤더에 자신이 무엇을 잘못 추가했는지 확인하려 할 것이다. 하지만 결국 유지보수 프로그래머는 모든 버그가 원래부터 있었던 것임을 알고는 이를 찾으려 애써야 했던 즐거웠던 경험에 대해 우리에게 감사해 할 것이다. 컴파일러의 몇몇 에러 확인 진단 옵션을 사용하면 우리 프로그램이 컴파일되지 않을 수 있다. 컴파일러는 경계 값 확인 등의 기능을 수행할 수 있지만, 실제 업무에서 이 기능을 사용하는 프로그래머는 거의 없으므로 우리도 이런 기능을 사용할 이유가 없다. 이런 미묘한 버그를 찾는 기쁨과 즐거움을 컴파일러에게 빼앗긴다니 말이 되는가?
버그 수정과 업그레이드를 혼합하라
절대 "버그만 수정한" 버전을 릴리즈 하지 말아라. 버그를 수정했으면 데이터베이스 형식도 바꾸고, 복잡한 사용자 인터페이스도 변경하고, 관리자 인터페이스도 다시 만들자. 이렇게 하면 사람들은 그냥 버그에 익숙해지려 하고 결국 버그를 기능이라 부르기 시작할 것이다. 단지 이런 "기능"이 다른 방식으로 동작하길 바라는 사용자만이 새로운 버전으로 업그레이드 할 필요성을 느낄 것이다. 이런 방식으로 유지보수 작업을 줄일 수 있고, 고객으로부터 얻는 수익도 늘어난다.
제품을 릴리즈 할 때마다 파일 형식을 변경하라
미래 호환성을 원하는 고객이 많으므로 원하는 대로 해주자. 그러나 기존 버전과의 호환성은 유지하지 않는 것이 핵심이다. 그러면 민감한 버그 수정 정책(윗글 참조)과 함께 나온 새로운 버전이 나왔을 때, 고객이 한번 새로운 버전을 사용하기 시작했다면 다시 이전버전으로 돌아갈 수 없게 된다. 결국 고객은 새로운 버전이 나와도 업그레이드를 선택하지 않을 것이다. 추가 보너스 팁! 새로운 버전에서 생성한 파일을 예전 버전에서 인식조차 못하게 하는 방법은 무엇이 있을까? 이런 방법을 이용해 심지어는 같은 응용 프로그램으로 만든 파일이 아니라고 거부할 수 있다. PC 워드 프로세서에서 이러한 복잡한 동작과 관련한 예제를 제공한다.
버그를 보상하라
코드에서 버그의 근본 원인을 찾아내는 것을 두려워하지 말고 고수준 루틴에 이를 보상할 수 있는 코드를 넣자. 이는 3D 체스와 같은 지능 활동의 산물이다. 이 덕분에 이후에 작업할 유지보수 프로그래머는 문제가 데이터를 생성하는 저수준 루틴에서 발생한 것인지 아니면 값을 변경하는 고수준 루틴에서 발생한 것인지를 찾는 즐거움에 빠져 수많은 시간을 보내야 할 것이다. 이 기법은 멀티 패스 프로그램인 컴파일러에 적합하다. 첫 번째 과정에서는 문제 수정을 회피함으로써 나중 과정을 더욱 복잡하게 만들 수 있다. 운이 좋으면 컴파일러의 프론트엔드 유지보수를 담당자에게 이 부분에 대해 얘기할 필요가 없는 경우도 있다. 프론트엔드에서 데이터를 정확하게 만든 경우 백엔드가 멈추게 하면 더욱 좋다.
스핀 락(Spin Lock)을 활용하라
스핀 락을 사용하고 기본 동기화 기능을 사용하지 말아라. 반복적으로 슬립 상태에 빠지면서 전역 변수(비휘발성의)를 통해 조건을 만족하는지 확인하자. 스핀 락은 시스템 오브젝트보다 더 "일반적"이고 "유연"하며 사용하기 쉽다.
동기화 코드를 마구 뿌려대라
꼭 필요하지 않은 곳이라 하더라도 시스템 동기화 코드를 추가해보자. 필자는 코드에서 두 번째 스레드가 실행할 가능성이 전혀 없는 크리티컬 섹션을 우연히 발견했다. 기존 개발자를 한번 시험해 봤고, 그는 해당 코드가 "비난받기(critical)!" 마땅하다고 시인했다.
우아한 타락
시스템에 NT 디바이스 드라이버를 사용한다면, 응용 프로그램에서 I/O에 필요한 버퍼를 요구하고 트랜잭션이 일어나는 동안 버퍼에 락을 걸도록 요청하자. 그리고 나중에 버퍼를 언락하고 해제한다. 응용 프로그램이 버퍼에 락을 건 상태로 비정상적으로 종료하면 NT 자체의 크래쉬를 발생시킬 수 있다. 클라이언트 사이트에서는 디바이스 드라이버를 바꿀 방법이 없으므로 선택의 여지는 없다.
커스텀 스크립트 언어
우리의 클라이언트/서버 응용 프로그램에서 실행 중에 바이트로 컴파일되는 스크립팅 명령어 언어를 포함해야 한다.
컴파일러 종속 코드
컴파일러나 인터프리터 버그를 발견했으면 이 버그를 이용해 우리 코드가 제대로 동작하게 만들자. 이제 우리 프로그램을 사용하는 모든 이는 다른 컴파일러를 사용할 수 없게 된다.
실생활 예제
스승님께서 작성하신 실생활 예제를 보여주겠다. 하나의 C 함수에 그가 사용한 여러 기법을 살펴보자.
void* Realocate(void*buf, int os, int ns) 
{ 
    void*temp; 
    temp = malloc(os); 
    memcpy((void*)temp, (void*)buf, os); 
    free(buf); 
    buf = malloc(ns); 
    memset(buf, 0, ns); 
    memcpy((void*)buf, (void*)temp, ns); 
    return buf; 
} 
  • 자세히 보면 Realocate의 철자가 부정확하다. 창의적인 철자법의 힘을 얕보지 말라.
  • 아무런 이유 없이 입력 버퍼를 임시 복사본을 만든다.
  • 이유 없이 형을 변환한다. Memcpy()는 (void*)형을 매개변수로 받으므로 이미 (void*)형을 사용하더라도 무조건 형변환한다.
  • temp를 해제할 필요는 없다. 이렇게 작은 메모리 누수의 효과는 미미하기 때문에 며칠 동안 프로그램을 돌려도 끄떡없는 경우가 많다.
  • 만약을 대비해서 버퍼에서 필요한 데이터 이상을 복사하라. 유닉스에서는 코어 덤프가 발생할 것이다.
  • 위 코드에서 os는 "old size"를 ns는 "new size"를 의미하는 듯 하다.
  • 표준 라이브러리에 이미 있는 간단한 함수는 다시 만든다.
  • buf를 할당하고 0으로 memset한다. 누군가 ANSI 스펙을 변경할 가능성이 있으므로 calloc()을 사용하는 것은 위험하다(일단 어차피 buf 크기와 동일한 데이터를 복사한다는 사실은 신경쓰지 말자).
사용하지 않은 변수 에러를 고치는 방법
컴파일러에서 "사용하지 않은 지역 변수" 경고를 발생한다고 해서 그 변수를 꼭 없앨 필요는 없다. 대신, 창의적으로 고민을 좀 해보자. 나같으면…
i = i; 
중요한 것은 크기
함수가 크면 클수록 좋다는 것은 두말하면 잔소리인 진리다. 물론 jump와 GOTO도 많을수록 좋다. 이렇게 할 때 누군가 무엇을 변경하게 되면, 검증해야 할 시나리오가 정말 다양해 진다. 이제 코드 스스로가 유지보수 프로그래머에게서 자신을 보호할 수 있게 된다. 함수를 거인 왕처럼 만들 수 있다면 함수는 고질라가 되어 유지보수 프로그래머가 무슨 일인지 정신을 차리기도 전에 공격하고 무자비하게 밟아버릴 것이다.
하나의 그림은 1000개의 단어를 대신하고, 하나의 함수는 1000개의 줄을 대신한다.
모든 메소드의 바디를 가능한 한 길게 만들어라. 깊게 중첩하는 것을 잊지 말고 절대 앞으로는 1000줄 이하의 메소드나 함수를 만드는 일이 없도록 하라.
사라진 한 개의 파일
중요한 파일이 적어도 한 개 이상이 없어지게 해야 한다. 이 기법은 include에 include를 혼합하므로 효과를 극대화할 수 있다. 예를 들어, 우리 모듈에서
#include <stdcode.h>
Stdcode.h는 존재한다. 그러나 stdcode.h에서 가리키는
#include "a:\refcode.h" 
Refcode.h 파일은 어디에서도 찾을 수 없어야 한다.
여러 곳에서 작성하고 어디에서도 읽을 수 없게 하라
적어도 한 변수를 모든 곳에서 설정하도록 하고 사용하는 곳이 없게 하라. 불행히도 현대 컴파일러는 아무데서도 기록하지 않고 모든 곳에서 읽는 동작을 허용하지 않는다. 하지만 C나 C++에서는 이러한 동작을 아직 수행할 수 있다.

철학

컴파일러나 시스템 클래스를 만드는 사람이 보통 언어를 설계한다. 당연한 일이지만, 그들은 자신의 작업을 용이하게 수학 계산을 간단히 할 수 있는 방식으로 언어를 설계한다. 그러나 한 컴파일러를 구현하는 사람 뒤에는 10,000 명의 유지보수 프로그래머가 필요하다. 정작 힘들게 일하는 유지보수 프로그래머는 언어 설계 단계에서 의견을 내지 못한다. 그러나 유지보수 프로그래머가 작성한 코드 양에 비하면 컴파일러 코드는 한없이 작을 뿐이다.
이런 엘리트 주의적인 생각은 JDBC 인터페이스에서 잘 나타난다. JDBC 인터페이스는 JDBC 구현자의 삶을 쉽게 만들어 준다. 그러나 유지 보수 프로그래머에게는 악몽을 가져다 주었다. JDBC 인터페이스는 삼십년 전에 나온 포트란의 SQL 인터페이스보다 못하다.
유지보수 프로그래머는 세부사항은 감추어서 나무로 이루어진 숲을 볼 수 있게 해달라고 요청한다. 그들은 다양한 종류의 단축(shortcut) 방법을 이용해서 많은 코드를 타이핑하지 않아도 되고, 따라서 프로그램을 화면으로 확인하기 쉽게 해달라고 요청한다. 유지보수 프로그래머는 컴파일러가 요구하는 많은 하찮은 작업으로부터 해방시켜 달라고 큰소리로 불평한다.
이와 같은 노력에 부흥하는 결과로 현재 작업과 관계없는 세부 사항은 감출 수 있는 NetRexx, Bali 그리고 비주얼 편집기(예를 들어 IBM의 비주얼 에이지를 시작으로) 등이 소개됐다.

구두 제조인은 신발이 없다

자신의 원장을 워드 프로세서로 관리해 달라고 주장하는 회계사 고객이 있다고 가정하자. 아마 우리는 데이터를 구조화 한다고 그를 설득할 것이다. 그는 상호간의 필드 검사와 유효성 검사도 요구한다. 우리는 동시 업데이트를 지원하는 데이터베이스에 데이터를 저장하는 것이 유리하다고 그를 설득할 것이다.
소프트웨어 개발자 고객의 경우를 살펴보자. 그는 모든 데이터(소스 코드를) 텍스트 편집기에 보존해야 한다고 주장한다. 그는 아직 워드 프로세서의 색상, 형식 크기, 폰트 등을 사용해본 적이 없다.
소스 코드를 구조화된 데이터로 저장하면 무슨 일이 일어날까? 하나의 소스코드를 자바, NextRex, 의사결정 테이블, 플로우 차트, 루프 구조 뼈대(상세 내용 없이), 상세 내용이나 주석을 제거한 자바, 현재 관심이 있는 변수와 메소드 호출을 하이라이트한 자바 코드, 매개변수 이름과 형식에 대한 주석을 포함하는 자바 코드 등의 다양한 방식으로 볼 수 있다. 복잡한 수식 표현을 TeX나 수학자들이 하듯이 2차원으로 확인할 수 있다. 괄호를 추가하거나 뺀(자신의 우선순위 규칙 취향에 따라) 형태의 코드도 확인할 수 있다. 괄호는 다양한 크기와 색을 눈으로 구별하는데 유용하다. 선택적으로 제거하거나 적용할 수 있는 투명한 오버레이 집합을 사용해서 다른 나라에서 일하는 팀의 다른 프로그래머를 실시간으로 볼 수 있고 작업중인 코드 변경 사항도 확인할 수 있다.
색상을 이용해 미묘한 단서의 실마리로 사용할 수 있다. 예를 들어 각 패키지/클래스에 색상을 자동으로 지정해서 클래스의 메소드나 변수의 레퍼런스 백그라운드에 파스텔 그림자를 사용할 수 있다. 특정 식별자의 정의에 볼드체를 적용해서 두드러지게 할 수도 있다.
X 형식의 오브젝트를 생성하려면 어떤 메소드나 생성자를 사용해야 하는가? 오브젝트 X 형식을 파라미터로 받는 메소드는 어디 있는가? 코드에서 어떤 변수에 접근할 수 있는가?와 같은 질문을 할 수 있다. 메소드 호출이나 변수 레퍼런스를 클릭하면 관련 정의를 확인할 수 있고, 어떤 버전의 메소드가 실제 실행될 것인지 쉽게 확인할 수 있다. 지정한 메소드나 변수의 모든 레퍼런스를 확인하면서 체크 표시를 할 수도 있다. 가리키고 클릭하는 동작으로도 많은 일을 할 수 있으므로 코드를 직접 작성하는 일이 줄어든다.
위에서 살펴본 사항 중 몇 가지는 실현 불가능할 수도 있다. 어떤 것이 실생활에 꼭 필요한 것인지 알아보려면 부딪쳐 보는 수밖에 없다. 기본 도구를 얻었으면 유지보수 프로그래머의 생활을 개선할 수 있도록 수많은 아이디어를 실험해봐야 한다.
이에 대해서는 SCID 학생 프로젝트에서 더 설명하겠다.
이 기사의 초기 버전은 자바 개발자 저널(볼륨 2 문제 6)에 처음 실렸다. 1997년 11월 콜로라도 정상 회의(Colorado Summit Conference)에서도 이 주제에 대해 얘기한 적이 있다. 그 이후로 이 이야기를 발전시켜 왔다.
이 글은 농담일 뿐이다! 혹시라도 이 글의 내용을 있는 그대로 받아들인 이가 있다면 정중히 사과한다. 캐나다 사람은 농담에 :-)를 삽입하는 것을 세련되지 못한 행동으로 받아들인다. 내가 유지보수할 수 있는 코드를 작성하는 방법에 관해 지껄일 때면 사람들은 별로 관심을 가지지 않았다. 어느 날 일을 그르치는 얼간이 같은 행동을 얘기해야 사람들이 더 반응을 보인다는 사실을 알게 됐다. 유지보수 할 수 없는 디자인 패턴을 확인하므로 더 효과적으로 악의적인 혹은 부지불식간에 일어나는 나쁜 일을 예방할 수 있다.
원본 기사는 로에디 그린의 Mindproducts 사이트에서 확인 할 수 있다.