4편입니다.

아마 HDD로는 마지막편이 될꺼같습니다.

아무래도 제가 스토리지 전공이라, 이쪽은 좀 길게썼는데,

다른편들은 좀 더 짧고 간결하게 쓸 예정입니다.

읽으시는 분들 계시다면 피드백 남겨주시면 감사하겠습니다.






RAID를 구성해보자!


1편에서 HDD의 작동원리와 HDD 스펙에 나오는 숫자에 대해 알아봤고,
2편에서는 PATA / SATA 등의 커넥션 타입에 대해 알아봤습니다.
3편에서 단일 HDD의 성능과 최적화에 대해 알아봤으니, 마지막 4편에서는 RAID에 대해 알아보겠습니다.



Redundant Array of Independent Disk

RAID 혹은 레이드..

SSD가 없던 시절 HDD의 성능을 올리는 유일한 방법이었고,
그보다 중요하게는 Fault Tolerance (번역해보니 내결함성...이라고 나오네요 -_-) 를 위해 필수인 기술입니다.

하드디스크 한개에 들어있는 자료는, 그 하드가 망가지는 순간 증발해 버립니다.
백업에서 다시 불러온다고 해도, 백업 이후 지금까지 변한 데이터는 찾을 수 없고,
또 복구할때까지 그 자료를 사용하지 못한다는 점에서도 기업들에겐 뼈아팠습니다.

그래서 만들어진 기술이 RAID입니다.

RAID 기술은 0 부터 6 까지 7가지가 있습니다.
이 7가지가 또 섞여서 하이브리드 (네스티드) RAID기술이 만들어 졌고요


세부적으로 들어가기 전에,
일단 몇가지 용어를 설명하고 넘어가겠습니다.



1. 미러링 - mirroring 

미러..거울이라는 말 뜻대로, 똑같은 자료를 하나 더 만들어내는걸 말합니다.
RAID-1의 기본으로써, 디스크 두개를 이용해 같은 자료를 항상 두개 가지고 있는거죠.



2. Spanning - Concatenating 

디스크 두개를 연결하는 기술입니다.
1번 디스크가 꽉 차면 2번 디스크에 연결해서 사용합니다.



3. Spanning - Striping 

RAID를 처음 배울때는 조금 이해하기 힘든기술입니다.
아시다시피, 컴터의 모든 자료는 2진수로 저장됩니다.
11이라는 숫자를 저장하면,
1011 즉 8+0+2+1로 저장이 되는거죠. 각각 한자리를 비트(bit)라고 부릅니다. 
비트 8개가 모인 (0~255까지 표현가능한) 단위가 바이트 (byte)가 되는거고요.
한국 광랜의 예를 들자면, 100메가빗 커넥션이므로, 이론상으로 초당 12.5메가 바이트를 전송할 수 있죠 (실제론 이만큼 안나옵니다)

만약 디스크 한개가 10개의 비트를 저장할 수 있고, 1010101011101010 이라는 2진수를 저장할때,
2번 기술인 concat을 쓰면, 디스크 a에 1010101011이 저장되고, 나머지 101010이 디스크 b에 저장됩니다. 남은 용량은 디스크 b에 4비트만큼 남았겠군요.

하지만 여기서 스트라이핑을 하면, 조금 얘기가 달라집니다.

비트레벨 스트라이핑으로 예를 들어 설명하자면,
a b
1 0
1 0
1 0
1 0
1 1
1 0
1 0
1 0
이렇게 첫번째 디스크엔 11111111이 들어가고,
두번째 디스크에는 00001000이 들어갑니다.
남은 용량은 두개의 디스크 모두 2비트씩이 남습니다.

즉 한개의 비트씩 번갈아가며 두개의 디스크에 넣는거죠.

스트라이핑이 콘캣보다 좋은 이유는,
데이터를 읽거나 쓸때, 스트라이핑의 경우 항상 2개의 디스크를 사용한다는겁니다.
속도가 2배죠.

콘캣이 스트라이핑보다 좋은 점은,
없다고 봐도 무방합니다 -_-
스트라이핑이 불가능할때만 콘캣을 쓰는거죠.

꼭 콘캣이 좋은점을 찝어내자면,
1. software raid의 경우 CPU에 부하가 안걸린다.
2. 디스크를 추가로 연결할때, 리빌드를 할 필요가 없다 정도 되겠네요.
여기서 리빌드는 2개 -> 3개로 디스크 숫자를 늘릴때, 스트라이핑의 경우 저 데이터를 모두 읽어서 다시 3개의 디스크에 균등하게 배분해야 한다는 말입니다.


4. Parity
데이터를 보호하기 위해 쓰이는 기술입니다.
XOR 기법을 사용해서, (비트레벨 패리티 기준) 한개의 비트를 더 만들어냅니다.
1 xor 1 = 0
0 xor 1 = 1
1 xor 0 = 1
0 xor 0 = 0 
좀 뒤에 다시 설명하겠습니다.



자 그럼 본격적으로 RAID에 대해 알아보겠습니다.
(하드웨어)레이드 구성을 한 디스크들은, OS상에서는 한개의 디스크로 표현됩니다.



RAID0
위에 설명한 스트라이핑입니다.
2+ 개의 디스크를 연결해서 스트라이핑 합니다.
속도는 모든 RAID중에서 가장 빠릅니다.
단점은?
연결해놓은 디스크중 하나만 죽으면 나머지 디스크의 자료도 다 날라갑니다.



a1~a8까지의 블록이 있을때,
번갈아가며 양쪽 디스크에 한번씩 써주는거죠

IOPs기준 성능은 

읽기 : 디스크 한개의 성능 * RAID 0에 쓰인 디스크 숫자
쓰기 : 디스크 한개의 성능 * RAID 0에 쓰인 디스크 숫자
Fault Tolerance : 한개로도 죽으면 집단 사망.
총 용량 : 디스크 한개의 용량 * RAID0에 쓰인 디스크 숫자

RAID 1
역시 위에 설명한 미러링입니다
2개의 디스크를 연결해서, 똑같은 데이터를 양쪽 디스크에 동시에 씁니다.



읽기 성능 : 디스크 한개의 성능 * 2
쓰기 성능 : 디스크 한개와 동일함.
Fault Tolerance (기네요.. 앞으로는 FT라고 쓰겠습니다-_-) : 한개죽어도 나머지 하나가 룰루랄라 살아남습니다.
총 용량 : 디스크 한개와 동일함



RAID 2 
비트레벨 스트라이핑 + 패리티
여기서 부터 좀 복잡해집니다.
이해가 안가시는 분들은 그냥 넘어가도 무방합니다. 

레이드 그룹안의 모든 디스크의 스핀들은, 정확히 같은 속도로 돌아갑니다.
비트 단위로 스트라이핑 되며 디스크들에 써지고, 해밍코드로 패리티가 계산되어, 한개 이상의 디스크에 저장됩니다.




현재는 사장 된 기술이며,
성능/FT 둘다 패리티 디스크가 몇개냐에 따라 다릅니다.




RAID 3
RAID2와 동일하지만, 비트레벨이 아니고 바이트레벨을 사용하며, 패리티는 xor 계산입니다.
역시 대충 사장된 기술이니 넘어가겠습니다.





RAID 4
RAID3 와 동일하지만, 바이트레벨이 아니고 블록레벨을 사용하며, 패리티는 xor 계산입니다.
역시 모든 패리티는 지정된 디스크에 저장됩니다.
역시 대충 사장된 기술이니 넘어가겠습니다.





RAID 5

RAID 1/0 (곧 다시 다룹니다) 와 더불어 현재 가장 많이 쓰이는 구성입니다.
조금 길게 설명하겠습니다.
RAID 4와 동일하게, 블록레벨 스트라이핑이지만, 분산된 패리티를 씁니다.
비트레벨 (1bit), 바이트레벨 (1 byte / 8 bit)과는 달리,
사용자 지정의 블록레벨을 만듭니다. 4kbyte~128kbyte로 어떤 용도냐에 따라 크기는 다릅니다.

abcdefghi라는 데이터가 있을때 (각각의 알파벳은 한개의 블록을 나타냅니다.),
4개의 RAID 5 디스크(1,2,3,4) 에 저장을 한다면,
1 2 3 4 
a b c p1
d e p2f
g p3 h i 

이렇게 저장이 됩니다.
첫블록은 첫번째 디스크에, 두번째 블록은 두번째 디스크에, 세번째 블록은 세번째 디스크에 들어가고,
네번째 디스크는 첫 3번째 블록 abc 을 이용해 계산한 패리티가 들어갑니다.
네번째 블록은 다시 첫번째 디스크에, 다섯번째 블록은 두번째 디스크에, 여섯번째 블록은 "네번째" 디스크에 들어가고, 세번째 디스크에는 def 를 이용해 계산한 패리티가 들어가는거죠.

패리티를 분산해서 얻는 이득은, 많은 데이터가 한꺼번에 쓰여질때, 패리티 계산에 가해지는 부하를 보든 디스크에 균등하게 나눠준다는거죠.



읽기성능 : 디스크 한개의 성능 * (총디스크 갯수 - 1)  한개를 빼주는 이유는 패리티는 읽지 않고 건너뛰기 때문입니다.
쓰기성능 : 디스크 한개의 성능 * (총디스크 갯수 - 1) / 4
4로 나눠주는 이유는, 한개의 데이터를 쓸때마다 다시 패리티를 계산해서 패리티 값을 바꿔줘야 하기때문이죠. 
즉, 5개보다 적은 숫자의 디스크로 RAID5구성을 할경우, 특정상황에서는 오히려 한개보다 느립니다.
(100% random write기준이니, 실제 이런일은 거의 없다고 봐도 무방하죠)
FT: 디스크 한개까지는 죽어도 나머지 디스크들이 잘 살아서 돌아갑니다.
총 용량 : 디스크 한개의 용량 * (총 디스크 갯수 - 1)



RAID 6
5와 같습니다만, 패리티가 2개로 늘었습니다.


읽기성능 : 디스크 한개의 성능 * (총디스크 갯수 - 2)  두개를 빼주는 이유는 패리티는 읽지 않고 건너뛰기 때문입니다.
쓰기성능 : 디스크 한개의 성능 * (총디스크 갯수 - 2) / 6
6으로 나눠주는 이유는, 한개의 데이터를 쓸때마다 다시 패리티를 두번 계산해서 패리티 값을 바꿔줘야 하기때문이죠. 

FT: 디스크 두개까지는 죽어도 나머지 디스크들이 잘 살아서 돌아갑니다.
총 용량 : 디스크 한개의 용량 * (총 디스크 갯수 - 2)





Hybrid RAID (잡종-_-)

위에 쓰여진 RAID구성이 섞인 그룹입니다.
RAID 0/1 , 1/0
1/0가 0/1보다 확실히 좋지만, 대충 비슷한 구성이니 묶었습니다.
디스크를 미러링 한 후에 스트라이핑을 합니다.

즉 성능을 최대한 끌어내면서 안전성 역시 추구한 구성입니다.

읽기성능 : 디스크 한개의 성능 * 총 디스크 갯수
쓰기성능 : 디스크 한개의 성능 * 총 디스크 갯수 / 2.  2로 나눠주는 이유는. 미러링땜시 뭔가 쓸때마다 두군데에 동시에 쓰기 때문이죠.
총용량 : (디스크 한개의 용량 * 총 디스크 갯수) / 2
이게 가장 큰 문제입니다.
전체 용량의 딱 절반뿐이 사용하지 못합니다.
FT : 운이 매우매우매우매우 좋다면, 전체 디스크중 절반이 날라가도 살아있습니다.
재수 더럽게 없다면 딱 2개만 날라가도 다 날라가고요.
1/0가 0/1보다 자료 날릴 확률이 적습니다.



그 외에 RAID5/0, 5/1 등등이 있지만, 
일반유져가 쓸일 없으니 넘어갑니다.







RAID에는 Hardware Raid와 Software Raid가 있습니다.
하드웨어는 말 그대로 레이드를 구성하고 어느 블록이 어디로 갈건지 등등을 레이드 컨트롤러란 카드가 담당하고, 소프트웨어는 OS가 담당합니다.
하드웨어가 성능으로 보면 우월합니다만, 비쌉니다 -_-
괜찮은거 살려면 수십만원 우습습니다.

윈도우에서 구성가능한 소프트웨어 레이드는 다음과 같습니다
XP : RAID 0 (프로페셔널만)
7 : RAID 0(모든 버젼), RAID 1 (프로페셔널/울티메이트)

내컴터 우클릭 -> 관리 -> 디스크 관리...에서 다이나믹 디스크를 만들어주면 됩니다.







일단 여기까지가 HDD글 전부입니다.

더 깊게 설명하자면 한도 끝도 없지만,

이정도면 HDD가 무엇인지, RAID가 무엇인지는 대충 다 설명했다고 보입니다.


읽으신 분들 어땠는지 피드백 남겨주시면 감사하겠고요,

혹시 더 깊게 아시고 싶으신 분들은 댓글이나 쪽지 주시면 좀 깊게 더 써보겠습니다.

다음글에선 CPU를 다뤄보겠습니다.



Posted by 뉴로
,
저는 프로그래머는 아니라서 100% 이해가 되지는 않지만 그래도 웃기네요.. ㅎㅎㅎㅎ


1 딱 떨어지는 숫자는 2진수입니다. 
2 한 손으로 31까지 셀 수 있음 
3 만능이 아님 
4 컴퓨터를 잘 하는게 아님 
5 프로그래머라고 Office 시리즈에 정통한 것이 아님 
6 아, 그 작업은 사무쪽 누님이 잘하실 겁니다. 
7 가나 입력으로 변환한 다음에는 반드시 로마자 입력으로 돌려놓을 것 
8 프로그램의 쓰레기 수집은 잘 하지만 자기 방의 쓰레기 수집은 잘 못함 
9 멀티스레드 처리 작성은 할 수 있지만 멀티스레드 처리는 못함 
10 Amazon 에서 사는 건 기술서이므로, 딱히 포장물 내용을 확인할 필요는 없음 

11 쌓아놓은 책은 스택이므로 순번을 바꾸지 말것 
12 오라일리 책은 「같은 책」이 아님 
13 표지에 동물만 그려져 있는 책만 꽂혀있어도 그건 동물도감이 아님 
14 프로그래밍을 안하는 날도 있음 
15 프로그래밍 언어나 에디터에 대한 집착이 사라진다면 깨달음을 얻었거나 완전연소했거나 둘 중 하나 
16 언어로 바람피우는 것과 인생의 바람피우기는 다른 것 
17 「자식을 죽인다」는 말에 놀라지 말 것 
18 일 관계로 전화를 할 때, 자식이 죽지 않으면 부모를 죽여버리라는 대화를 들어도 놀라지 말것 
19 라이브러리라는 것은 도서관을 말하는 게 아님 
20 「사이드 이펙트(부작용)」는 부정적인 의미로 사용하는 것이 아님 

21 특히 「다이아몬드 상속」은 유산상속같은 이야기를 하는 것이 아님 
22 괜히 보석 이름 같은 것을 중얼거려도 보석에 대해 잘 아는 것이 아님 
23 루비와 펄 중에 뭐가 좋아? 라고 물어보면, 싱긋 웃으면서 펄이라고 대답할 것 
24 「조금만 더하면」「거의 끝났어」라는 말이 나오기 시작하면 당분간 끝나지 않을 것이라고 생각할 것 
25 갑자기 혼잣말을 하기 시작해도 정신이 이상해진 것이 아님 
26 PC 를 보고 있는 남편에게 말을 걸어도 되는 타이밍인지 아닌지 외견으로 판단하는 것은 포기하는 것이 좋음 
27 23-24시 정도가 가장 활발함 
28 HP 는 항상 0에 수렴함 
29 회사와 집의 구별이 그다지 없고, PC 앞에 있는가 없는가의 구별 밖에 없음 
30 스스로가 정보수집과 오락의 경계선을 이해하지 못함 

31 몬스터헌터는 업무 
32 애니메이션 보는 것은 업무 
33 일을 하는 것처럼 보이지만 실은 인터넷을 하는 것 뿐임 
34 주말에도 스터디에 간다고 하는 것은 공부를 열심히 한다는 증거, 가사가 싫어서 그러는 게 아님 
35 한밤에 긴급전화가 왔다면, 다음날부터의 예정은 캔슬이라고 생각합시다 
36 밤중에 갑자기 사라져도 그냥 장애 대응하러 간 것임 
37 오전중에 돌아오는 일이 많아져도 바람피우는 것이 아닌지 의심하지 말것 
38 주말에만 사복으로 「출근」했다고 바람피우는 것이라고 의심하지 말 것 
39 결혼식장에서 신랑이 사라져도 당황하지 말것. 고객이 호출한 것 뿐임 
40 정시퇴근은 도시전설 

41 「귀가한다」「귀가할 수 있다」라는 말은 별 도움이 안됨 
42 10일 정도 돌아오지 않아도 당황하지 말 것 
43 감금같은 걸 당해도 빚이 있어서 그러거나 한 게 아님 
44 가끔씩 일찍 돌아와도 잘렸을 걱정은 하지 말 것 
45 여름 휴가 언제야? 라고 묻지 말 것 
46 Twitter 의 post 빈도 감소나 내용에서 상대가 얼마나 바쁜지 추측해서 위로할 것 
47 화재나 행진같은 것에 트라우마를 갖고 있을 것 
48 남편 급여의 직능급과 기본급과 잔업수당의 비율 
49 노동기준법 
50 OA 기기라고 적힌 우편물은 절대로 OA 기기가 아님 

51 PC 나 휴대폰, iphone 에 패스워드 락이 걸려있는 것은 보안대책을 위해서. 바람을 핀다거나 야한 것을 숨기고 있는게 아니랍니다( ^ω^) 
52 컴퓨터는 이미 집에 있잖아, 라고 하지 마시길. 당신이 갖고 있는 구두나 가방과 같은 것입니다.
53 한밤중에 컴퓨터로 동영상을 보면서 싱글거리고 있다면, 그것은 분명 Apple 의 신제품 발표이므로 신용카드를 몰수하는 것이 좋음 
54 스티브 잡스의 프리젠테이션이 있는 다음날 아침에 갑자기 개최되는 가족회의에서 제출하는 안건에 대하여 「다른 집은 다른 집이고 우리 집은 우리 집이야!」라고 기각할 것 
55 뭐가 뭔지 알수 없는 T 셔츠를 남편이 계속 가져와도 적당히 버리거나 하지 말 것 
56 컴퓨터 책상에 놓여있는 피겨나 프라모델은 버리지 말 것 
57 그것은 잡동사니도 부서진 물건도 아님 
58 키넥트를 사려고 하는 것은 유저 인터페이스 연구 때문에 
59 러브 플러스를 하는 것은 유저 인터페이스 연구 때문에 
60 사용자 경험(UX)인지 뭔지 하는 주제에 CUI 를 좋아함 

61 LCD 가 달려있는 작고 비슷하게 생긴 기계를 잔뜩 갖고 있어도 전부 다른 물건이며 각자 의미가 있습니다 
62 동작검증을 하기 위해서는 신제품이 필요하며, 그것은 Amazon 에서 배달됨 
63 옥션 사용방법을 숙지하고, 남편이 사온 장난감을 팔아치워 용돈으로 씁시다 
64 생일 선물은 원하는 물건을 미리 말해두지 않으면 신제품 디지털 가전(Gadjet)을 받게 됨 
65 깜짝 선물을 준비하고 싶다면 남편의 Amazon 위시 리스트를 조사함 
66 iPhone 앱, Android 앱, Web 사이트를 만들었다는 이야기를 들으면 뭐가 뭔지 몰라도 상냥하게 대답해줄 것 
67 쓸데없이 하이텐션으로 의미를 알 수 없는 소리를 지껄일 때에는 단순히 흥미 깊은 기술이 나와서 텐션이 높아진 것 뿐이므로, "잘 모르겠지만, 대단하다는 건 알겠다"라고 대답해주세요 
68 갑자기 이상한 어휘가 늘었다면 니코니코 동화같은 데애서 유행하고 있는 것이라고 추측하시길
69 남편의 HN 과 본명을 이어보려고 해서는 안됨 
70 남편의 블로그의 과거로그를 음독해서는 안됨 

71 남편의 HN 으로 검색해서 흑역사를 알아서는 안됨 
72 「우리 마누라가…」라고 했을 때, 그것은 프로그래머 사이에서 통용되는 전문용어입니다. 당신을 말하는 것이 아닙니다 
73 오타쿠라고 하면 필요 이상으로 싫어하지만, 긱(Geek)이라고 말하면 기뻐합니다 
74 침울해하고 있을 때는 「컴퓨터를 조작해서 ○○할 때 마우스를 쓰지 않고 키보드만으로 하려면 어떻게 해야해?」라고 물으면 기뻐하면서 가르쳐 줄 것입니다 
75 「시뮬레이션」이라고 말하면 혼나므로 주의할 것 
76 이상, 이하, 미만, 보다 위, 보다 아래를 대충 섞어쓰면 기분이 나빠짐 
77 프로그래머는 「절대로」「뭔가 이상해졌어」「아무것도 안했어」같은 말에 과잉으로 반응합니다. 홧병, 쇼크사, 자살의 위험성이 있으므로 이런 말을 사용할 때에는 세심한 주의가 필요합니다 
78 부부싸움할 때 최대의 무기는 화이트 보드 
79 어쩌다 아내의 방식에 불만을 표시하면 「그건 사양(仕?)이예요」라고 대답함 
80 남편이 이건 사양이라고 말하면 그 사양은 변경되었습니다 라고 대답할 것 

81 싸워서 꼭지가 돌아버렸을 때에는, 네트워크 회선을 끊어버리는 것이 가장 손쉽고 효과적으로 분노를 표현하는 방법입니다. 
82 가능하면 아내와의 대화를 자동화시키고 싶어 함 
83 아내에게는 사양 변경이 붙는 법 
84 홈 서버를 가리키면서 쓰지도 않는데 왜 항상 전원이 켜져 있는 거야 라고 묻지 말 것 
85 연락수단은 전화<<<<<(넘을 수 없는 벽)<<<<메일<<<<<<86 Google Calender 에서 상대의 스터디 스케쥴을 파악할 것 
87 집안 예정은 남편이 지정한 그룹웨어로 공유할 것. 구두(口頭)로의 통지만으로는 위험 
88 남편이 해야할 것은 데스마치(죽음의 행진)이 아닌 여유가 있을 때 기억시켜두지 않으면 답이 없음 
89 가정 내의 중요한 스케쥴을 끼워넣고 싶을 때에는 마감 근처의 주말은 피합시다. 어차피 집에 못 돌아옵니다 
90 남편이 전문분야인 화제에는 신중하게 접근할 것 

91 친구 관계의 잡담을 할 때에는 상관관계도를 그려주면 이해가 빨라집니다 
92 단순히 이야기를 들어주기 바랄 때에서는 그렇게 명시할 것 
93 동의해주기 바랄 때에 분석되어 정론을 들어도 화내지 마시기 바랍니다 
94 요건은 항목별로 적어서 전하지 않으면 프로그래머 스스로가 버그를 냄 
95 밤생활이 불만이면 Redbull 을 내밀어봄 
96 정기적으로 자식들에게 이게 아빠야 하면서 사진을 보여주세요 
97 남편이 「프로그래머의 아내가 알아야 할 97가지」같은 걸 트윗해도 신경쓰지 말 것 
98 읽어보라고 한 97가지의 절반 이상이 뭔 소리인지 몰라도 어쩔 수 없음 
99 이러니저러니 해도 아내를 사랑함. 하지만「쪽팔려서 말 못해」라고 생각해서 말로 표현하지 않을뿐.

Posted by 뉴로
,
웹 검색과 제 경험을 약간 추가하여 작성했습니다.
 
Java 입문
 
   
Head First Java - 뇌 회로를 자극하는 자바 학습법, 개정판
버트 베이츠, 케이시 시에라 (지은이), 서환수 (옮긴이)
한빛미디어 (2005), ISBN(13): 9788979143713
 
 
Thinking in JAVA - 개정4판
Bruce Eckel (지은이), 심재철, 최정국 (옮긴이)
사이텍미디어(희중당) (2007), ISBN(13) : 9788955508468
 
 
Java 중급
Effective Java Programming Language Guide - 자바 유창하게 말하기
조슈아 블로치 (지은이), 이해일 (옮긴이)
대웅미디어 (2003), ISBN(13) : 9788990109149
 
 
 
디자인 패턴
GoF의 디자인 패턴 (개정판 / 양장)
원제: Design Patterns : Elements of Reusable Object-Oriented Software
에릭 감마,리처드 헬름,랄프 존슨,존 블라시디스 공저
피어슨에듀케이션코리아 (2007), ISBN(13) : 9788945072146
 
 
참고링크:
http://wiki.bawi.org/index.php/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%B1%85%EC%B6%94%EC%B2%9C
Posted by 뉴로
,

사용자 스토리

web 2009. 12. 31. 20:55
사용자 스토리: 고객 중심의 요구사항 기법
 
사용자 스토리 II - XP 를 XP 답게 만드는 것
http://xguru.net/blog/356.html
 
프로젝트 관리, 어떻게 시작할까요?
Posted by 뉴로
,
리눅스에 대해 기본적으로 알아야 할 내용.
 
연재순서
1회.
개발자를 위한 리눅스 설치와 기본 명령어
2회. 고급 리눅스 명령어와 중요 시스템 관리
3회. 개발자를 위한 vim 편집기 사용법
4회. 오픈소스 프로젝트의 필수 개발툴 활용 <끝>
Posted by 뉴로
,

[펌] [UML] UseCase Diagram

web 2009. 12. 31. 20:53
UML(3) -유스케이스(Usecase) 다이어그램


UML(3) -유스케이스(Usecase) 다이어그램
심원도
E-mail:wideeye@www.plasticsoftware.com
플라스틱 소프트웨어
Homepage:www.plasticsoftware.com

지난 회에서 우리는 UML의 전체 구성에 대하여 알아보았다. 전체적인 구성을 보았으니 앞으로 각 다이어그램을 하나씩 보도록 하자.  이번 회에는 유스케이스 다이어그램에 관하여 알아보도록 하겠다.  많은 다이어그램 중에 왜 유스케이스 다이어그램을 가장 먼저 설명을 하는가에 대한 의문이 일것이다.  물론 필자의 마음일 수도 있지만 이 보다도 더 명확한 이유가 존재한다.  독자 여러분이 어떠한 방법론을 배우고 있다 하더라도 프로젝트를 수행함에 있어서 가장 먼저 수행되는 일이 동일할 것이다. 그것은 프로젝트가 무엇인지에 대한 기술이다. 프로젝트가 무엇인지 모르고 어떻게 프로젝트를 수행하겠는가?  이렇게 프로젝트가 무엇인지에 대해서 알아보는 것이 요구분석(Requirement Analysis)이다.  글의 흐름으로 보아 유스케이스 다이어그램이 요구분석을 위한 다이어그램이라는 것을 유추할 수 있을 것이다.  결국 유스케이스 다이어그램은 프로젝트 수행시 가장 먼저 나오는 다이어그램이고 다른 다이어그램의 배경이 되는 중요한 다이어그램이다.  이제부터 유스케이스 다이어그램을 자세히 알아보도록 하겠다.
 
1. 표기(Notation)과 의미(Semantics)
(1) 유스케이스(Usecase)
그림 1. 유스케이스

유스케이스의 표기는 그림 1에서와 같이 타원으로 표시하고 이름을 속에 명시하게된다.
(2) 유스케이스의 의미.
유스케이스는 말 그대로 쓰임새를 나타낸다. 다시 말해 한 프로젝트의 결과물이 작동하여 사용되는 쓰임새를 분류하여 나타내는 것이다. 예를 들어 우리가 늘 상주하는 집을 들면 집이 사용되어지는 예를 들 수가 있다. 집은 식사를 위한 장소를 사용되어질 수 있고 아니면 휴식을 위한 장소 아니면 수면을 취하기 위한 장소.. 등등 여러가지 용도의 사용 예를 들 수 있다. 결국 이러한 여러 사용 예들이 집의 구조를 결정하는 사항이 될 것이다.
(3) 액터(Actor)

그림 2 - 액터

그림 3 - 스테레오 타입이 액터인 클래스
액터의 경우 그림 2에서 보는 바와 같이 스틱맨으로 표시하고 그 하단에 액터의 이름을 명시한다.  또한 그림 3와 같이 스테레오타입(Stereotype)을  'Actor' 로 가지는 클래스로 표기하기도 한다.
(4) 액터의 의미
액터는 구축해야할 시스템과 상호 교류하는 어떠한 사람이나 어떤 것이 될 수 있다. 예를 들어 입출금할 수 있는 ATM기계를 보면 입출금을 하는 행위자인 손님의 경우 하나의 액터가 될 수 있다. 그리고 ATM기계가 입출금의 처리를 위해 연결하는 은행의 주 전산망 또한 하나의 액터가 될 수 있다. 이렇듯이 구축하고자 하는 시스템의 쓰임새와 교류하는 외부적인 것들의 추상적인 역할을 액터라고 한다.
 
2. 액터들간의 관계(Relationship)
(1) 일반화(Generalization) 관계의 표기

그림 4 -액터와 액터 사이의 일반화 관계 
(2) 일반화 관계의 의미
일반화 관계는 객체지향의 상속의 의미와 유사하다. 일반화된 액터의 모든 특성을 특수한 액터가 모두 가지게 된다. 그림 4에서와 같이 고객 액터의 모든 특성을 상업고객이 모두 포함하게 된다.
 
3. 액터와 유스케이스, 유스케이스와 유스케이스 사이의 관계
유스케이스와 유스케이스사이의 관계를 말하기에 앞서 알아두어야 할 사항이 있다. 현재 UML의 표준화된 버전은1.1 이다. 하지만 현시점에도 계속 버전업을 위한 수정이 가해지고 있다. 결과적으로 현재 1.3 RTF라는 표준화되지 않은 버전 또한 나와 있다.  유스케이스와 유스케이스와의 관계에서 1.1버전과 1.3버전의 차이점이 존재함을 유념하기 바란다.  필자는 표준인 1.1 을 대상으로 설명을 하도록 하겠다.
(1) 통신(Communicates) 관계

그림 5 - 통신(Association) 관계 
(2) 통신 관계의 의미
통신관계의 의미는 이러한 관계로 묶인 두 개체가 상호 작용을 한다는 의미이다.  그림 5에서와 같이 현금자동출납기계의 시스템에서 그 사용자와 사용자확인의 유스케이스는 상호작용을 하게 된다. 이를 관계로 표시한 것이 통신 관계이다. 참고로 UML1.3 RTF의 경우 통신관계는 연관(Association) 관계로 대체되어 사용되게 된다.
(3) 확장(Extends) 관계

그림 6 - 확장(Extends) 관계
(4) 확장 관계의 의미
확장(Extends)관계는 유스케이스가 어떤한 조건이 만족할 경우 확장할 수 있는 확장시점(Extention Point)를 가지고 그 때 연관된 유스케이스를 포함하는 관계이다 예를 들면 그림 6에서와 같이 추가 요구시라는 확장시점에서 카탈로그요구의 유스케이스가 주문접수의 유스케이스에 포함되게 된다.
(5) 사용(Uses) 관계

그림 7 - 사용(Uses) 관계
(6) 사용 관계의 의미
사용관계는 특정한 유스케이스가 다른 유스케이스를 포함하고 있는 경우를 나타낸다. 그림 7에서는 고객확인의 유스케이스가 주문접수의 유스케이스와 주문조사의 유스케이스를 모두 포함하게 되는 경우이다. UML 1.3 RTF에서는 Uses의 관계가 include의 관계로 이름이 바뀌어서 사용되게 된다.
(7) 일반화(Generalization) 관계 

그림 8 - 일반화(Generalization) 관계
(8) 일반화 관계의 의미
일반화 관계는 액터 사이의 일반화 관계와 동일하게 객체지향의 상속의 개념과 유사하다. 
 
4. 액터와 유스케이스의 추출법.
실제로 시스템을 구축하기 위해 유스케이스 다이어그램을 그릴 때 액터와 유스케이스를 만들기가 막막할 것이다. 물론 정확한 액터와 유스케이스를 추출하기 위해서는 여러 번의 반복이 필요하지만 처음으로 추출할려는 사람은 다음과 같은 대충의 지표 등을 통해 추출해보는 것도 좋다.
(1) 액터의 추출법
  1. 시스템의 주기능을 사용하는 사람은 누구인가.
  2. 누가 시스템으로부터 업무 지원을 받는가?
  3. 누가 시스템을 운영, 유지 보수하는가?
  4. 시스템과 정보를 교환하는 외부 시스템은 무엇인가?
  5. 시스템이 내어놓은 결과물에 누가 관심을 가지는가?
(2) 유스케이스 추출법
  1. Actor가 요구하는 시스템의 주요 기능은 무엇인가?
  2. Actor가 시스템의 어떤 정보를 수정, 조회, 삭제, 저장하느가?
  3. 시스템이 Actor에게 주는 어떠한 Event가 있는가?,  Actor가 시스템에는 어떠한 Event가 있는가?
  4. 시스템의 입력과 출력으로 무엇이 필요한가? 그리고 입력과 출력이 어디에서 오고 어디에로 가는가?
  5. 시스템의 구현에서 가장 문제가 되는 점은 무엇인가?
 
5. 시나리오
유스케이스 다이어그램을 그리면서 빠뜨려서는 안될 내용이 시나리오이다. 유스케이스 다이어그램을 완성하였다면 유스케이스 다이어그램의 명세가 필요하게 된다. 즉 유스케이스 다이어그램이 무엇을 해야하고 어떻게 해야하는가에 같은 부연 설명이 필요한 것이다. 유스케이스는 순서에 의해 배열이 가능하고 이러한 순서를 일반적인 자연어 문장으로 표현하되 외부인이 보아도 알기쉬운 정도로 쉽게 기술하여야 한다.
마무리?
유스케이스 다이어그램은 다른 다이어그램을 그리기 위한 바탕이 되는 다이어그램이다. 즉 유스케이스 다이어그램이 잘못 되었다면 결과물은 잘못된 것일 수밖에 없다. 유스케이스 다이어그래이 잘 되었다면 이후 그려나갈 다른 다이어그램이 원래의 목적에 맞게 그릴 수 있는지 비교할 수 있는 좋은 바탕이 될 수 있다.
참고로 유스케이스 다이어그램을 잘 그리기 위해 다음의 단계로 넘어가는 것을 주저하지 말기 바란다. 프로젝트를 잘 수행하기 위해서는 여러 번의 반복적 개발을 통해 오류의 수정 과정이 필요하고 이에 유스케이스 다이어그램을 수정하는 일도 포함된다. 즉 어느 정도 유스케이스 다이어그램이 완성되면 다음의 다이어그램을 진행하길 바란다.

이 글에 삽입된 다이어그램은 “Plastic Software”의 UML 모델링 툴인 “PLASTIC 2.0”을 이용하여 그렸다.

Posted by 뉴로
,

ORA-04031 오라클 에러

web 2009. 12. 28. 00:02
EXP-00056: ORACLE error 4031 encountered
ORA-04031: unable to allocate 1016 bytes of shared memory ("shared pool","...==XDB","qmxlu subheap","qmemNextBuf:alloc")
EXP-00056: ORACLE error 4031 encountered
ORA-04031: unable to allocate 1016 bytes of shared memory ("shared pool","...==XDB","qmxlu subheap","qmemNextBuf:alloc")
EXP-00000: Export terminated unsuccessfully
 
RA-4031의 솔루션은 그 원인에 따라 다양한 방법이 있습니다.
먼저 ORA-4031가 발생하는 원인은, SHARED_POOL을 관리하는 과정에, 많은 조각화(Fragment)가 발생하고 Free Memory가 아주 적은 상태에서, 커다란 SQL(PL/SQL)이 Memory로 Load 될 때 공간이 부족해서 발생할 수 있습니다.
 
이 ora-4031 Error가 발생하게 되면, Shared pool의 관리가 원활히 되지 않아, 이후에 수행되는 모든 SQL이 error가 발생합니다. 그러므로 이는 반드시 예방되어야 합니다.
 
 이러한 Memory관리상의 문제를 해결하기 위해 조치 할 수 있는 것은 아래의 것들이 있습니다.
 
1.      v$sql 내의 Literal SQL이 많은지 확인한다.
많은 경우 Literal SQL을 사용하는 SQL을    찾아서 공유 할수 있도록 Bind Variable을 사용토록 하면 됩니다.
 
   => Literal SQL을 찾는 방법.
 
select substr(sql_text, 1, 40) "SQL",
       count(*) cnt,
       sum(executions) "TotExecs",
       sum(sharable_mem) mem,
       min(first_load_time) start_time,
       max(first_load_time) end_time,
       max(hash_value) hash       
from v$sqlarea
where executions < 5    --> 수행 횟수가 5번 이하인 것.
group by substr(sql_text, 1, 40)
having count(*) > 30    --> 비슷한 문장이 30개 이상.
order by 2 desc;
 
 
2. v$sql 내의 sharable Memory가 큰것들을 확인 한다.
   1M byte이상의 SQL이 있다면 확인 후 SQL의 복잡도를 줄인다(recursive call을 많이 한다든지..). 대부분의 경우 크기가 큰 것들은 일반 SQL이 아니라 PL/SQL이므로 이러한 것들은 Memory에서 내려오지 않도록 Pin을 시키는 방법도 있습니다. (그렇다고 memory에서 완전히 안내려 오는 것은 아닙니다.)
 
   => PL/SQL을 Memory에 Pin시키는 방법.
   execute dbms_shared_pool.keep('SCOTT.HELLO_WORLD');
  
3. SHARED_POOL_SIZE와 SHARED_POOL_RESERVED_SIZE의 크기를 늘린다.
   항상 Shared pool의 Free가 여유가 있도록 shared_pool_size를 크기를 좀 늘리시고
   특히 Shared_pool_reserved_size의 크기를 100M정도 되도록 지정하세요. 경험적으로 shared_pool_reserved_size가 100M정도 지정하면 ora-4031가 많이 발생하지는 않더군요.
 
   Free공간 확인 .
 
   SELECT free_space, avg_free_size, used_space, avg_used_size, request_failures, last_failure_size
   FROM    v$shared_pool_reserved;
 
4. 이것이 진짜 마약처럼 잘 듯는 방법인데, 9i부터는 Shared_pool의 관리를 좀더 효율적으로 하고 System의    CPU를 효과적으로 사용하기 위해 하나의 heap memory를 사용하던 것을 subheap으로 나누어 관리를 하고 있지요. 이렇게 sub-heap으로 나누어 관리하다 보니 작은 공간이 sub heap에 동시에 있더라도 이를 잘 활용하지 못해서 발생하는 경우가 있습니다. 이러한 이유로 ORA-4031 Error의 원인이 되는 경우가 종종 있습니다.
   현재 시스템이 Multi CPU인 경우에는 아마도 1보다 큰 값으로 되어 있을 겁니다.
 
   그래서 아래의 Query로 조회해 본 후 그 값이 1보다 큰 값이라면 init.ora에서
   _kghdsidx_count=1로 지정한 후 restart해서 사용해 보세요. 어지간해서 ORA-4031가발생 하지 않을 겁니다.
 
            select x.ksppinm, y.ksppstvl
             from x$ksppi x , x$ksppcv y
             where x.indx = y.indx
             and x.ksppinm like '_kghdsidx_count%' escape ''
             order by x.ksppinm;
            
출처: http://database.sarang.net/?inc=read&aid=22794&criteria=oracle&subcrit=&id=&limit=20&keyword=ORA-04031&page=1
참고: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1513005503967
 
===================================================================
 
우선 현재 값을 알고 싶다면 sysdba 로 접속해서 다음과 같이 봅니다.
SQL> show parameter shared_pool_size;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_size                     big integer 64M
 
이것을 다시 100M 로 설정하려면 initSID.ora 파일을 열어서 다음과 같이 추가합니다.
java_pool_size 와 large_pool_size 는 추가하지 않아도 좋습니다. 추가할 경우는 자신의 시스템에 알맞는 값을 넣어주세요.
 
###########################################
# 풀
###########################################
java_pool_size=33554432
large_pool_size=1048576
shared_pool_size=104857600
 
추가한 뒤에는 오라클 재시작. 재시작 방법은 sysdba 로 접속해서
$ sqlplus / as sysdba
SQL> shutdown immediate    <=== 오라클 정지
SQL> startup mount              <=== 오라클 시작
   

Posted by 뉴로
,

XML 강좌, JSTL 강좌

web 2009. 12. 28. 00:01
XML 강좌:
 
 
wiki.javajigi.net 에는 이외에도 자바, 프레임워크, 이클립스, 루비(Ruby) 등 좋은 정보가 많이 있는듯하니 방문해보시기 바랍니다.
 
 
 
JSTL 강좌:
 
커스텀 태그로 JSP 페이지 제어하기: http://www.ibm.com/developerworks/kr/library/j-taglib/
 
자카르타 프로젝트 사이트: http://jakarta.apache-korea.org/taglibs/index.html
 
 

Posted by 뉴로
,
자바(Java) 웹 개발자가 되고 싶은 분들을 위한 안내.
 
처음 공부할 때 무엇부터 해야 좋을지 또는 어느 정도 공부는 했는데 앞으로 어떤 것을 더 해야 할 지 고민하는 분들을 위한 글입니다.
 
너무나도 당연하기 때문에 이 분이 쓰신 글에는 빠져있지만 웹을 하려면 HTML + CSS + 자바스크립트 (+ XML 까지) 는 기본이겠죠. 그 후에 PHP, JSP, ASP 중 하나를 선택해서 웹 프로그래밍을 시작하는게 대부분의 경우일텐데, 이제는 선택의 여지가 거의 없이 JSP 라고 봅니다.
 
PHP 의 경우 처음 배우기는 JSP 보다 더 쉽다고 생각하지만 배운 이후 활용도가 JSP 에 비해 떨어집니다. 우리나라에서 대부분의 대형 프로젝트들이 모두 JSP 계열로 진행되는 것으로 알고 있습니다. 특히, 관공서 관련 프로젝트는 100% 이고요. 요즘 (괜찮은) 자바 프로그래머가 일 할 자리는 아직까지는 꽤 있습니다. 돈을 많이 번다는 얘기는 아니고 그냥 노가다(?) 수준의 일자리는 3년 이상 경력자에게는 넘친다는거죠. 네이버, 다음 같은 곳은 가려는 사람은 많고 자리는 한정되어 있으니 당연히 잘 하는 사람이 가게 되어 있습니다. 개발자는 실력만 있으면 학벌은 필요없죠. 물론 승진해서 큰 회사의 높은 자리까지 가려면 학벌도 중요합니다만...
 
덧붙여 http://code.google.com/doctype/ 이런 것도 있었군요.
 
원글 출처는 http://kwon37xi.egloos.com/3666564 입니다. 아래는 퍼온 내용입니다.
 
 
================================================================================
 
OKJSP에 자주 가서 요즘 자바 개발자들이 어떻게 살아가나를 보는 편인데, 아주 많이 반복적으로 올라오는 질문이 "대체 뭘 공부해야 하나요? 프레임워크는 Spring을 해야 할까요? iBATIS를 해야 할까요?" 하는 식의 질문들이다(이 질문은 사실 말이 안된다. 왜 그런지 읽다보면 나온다).

Java는 웹 관련 프레임워크들이 너무 다양하고, Ruby나 Python 같은 경우에는 RubyOnRailsDjanog 처럼 하나의 프레임워크 안에 기능별 프레임워크들도 모두 다 All in one 형태로 들어 있어서 혼란을 주지 않는 반면, Java는 각 영역별로 프레임워크가 모두 다르고, 또한 각 영역별로 존재하는 프레임워크들의 종류도 많아서 초보 개발자들에게 극심한 혼란을 주고 있다.

그래서 나름대로 Java Web 개발자들을 위한 학습 로드맵을 정리해 보았다.

1. Java 그 자체
많은 웹 개발자들이 마치 JSP 코드를 짤 줄 알면 그걸로 Java 웹 개발을 할 줄아는 것이라 생각하고 Java 그 자체를 소홀히 하는 것을 본다.
말도 안되는 소리이다. Java를 모르고서 Java 웹 개발을 제대로 한다는 것은 어불 성설이다. Java 그 자체를 먼저 공부하라.

특히 Java 5 문법을 숙지하길 권한다. 이제 우리나라도 점차 Java 5가 대세가 되어 가고 있다. 대부분의 프레임워크들과 WAS(JSP와 서블릿을 구동하는 서버)도 모두 Java 5를 기준으로 바뀌었으며, JVM 자체도 버전이 높을 수록 성능이 더 좋다.

2. JSP와 Servlet 그리고 Model 1
모델 1은, JSP 하나에 DB에 접속해서 쿼리를 날리는 등의 모든 업무적인 기능(Business Logic)을 넣고, 그 아래에 HTML 코드를 박아 넣는 식으로 개발하는 것을 의미한다.
아직도 많은 개발자들이 여기에 길들여져 있는데, 일단 JSP 자체에 대한 기본기를 익힌 뒤로는 재빨리 버려야 할 습관이다.

그리고 많은 개발자들이 Servlet을 무시하고 JSP만 하는 것을 보곤 하는데, Servlet에 대한 학습이 제대로 이뤄지지 않으면 더 나은 웹 개발이 곤란하다. Servlet에 대한 기초 개념을 확실히 잡길 권한다.

3. Model 2 - 프레임워크의 등장
JSP로 열심히 개발을 하다보니 프로젝트 규모도 커지기 시작하고, JSP 파일 크기도 수천줄에 달하는등 엄청나게 커진다.
그런데 이 JSP에다 두서없이 모든 기능을 다 때려 넣다보니 JSP마다 똑같은 기능들이 Copy&Paste로 들어가고, JSP 안에 들어 있는 Java 코드들에서 에러가 발생하면 찾아내서 디버깅 하는 일이 지옥같이 느껴지기 시작한다.

여기서 Model 2가 구원자로 등장한다.

Model 2는 말만 멋드러졌지 실제로는 간단한 개념이다.

JSP에서 수행하던 DB 쿼리 등의 작업을 Servlet에게 넘겨주고 JSP에서는 오로지 화면 출력만 담당하는 것이다.

Servlet에서 DB 쿼리등 화면 출력과는 상관없는 비지니스 로직을 일단 먼저 모두 수행하고, 그 결과를 request.setAttribute("key",결과객체);로 담은 다음 JSP 페이지로 포워딩(forward)을 하면 JSP에서는 request.getAttribute("key")로 그 객체를 받아서 화면에 뿌려주기만 한다.
이런 업무 수행단/화면 출력단의 철저한 역할 분리가 Model 2이다.

여기서 이러한 각 역할을 "MVC - Model View Controller" 라고 한다. 그래서 Model 2는 MVC와 동일한 의미로 사용하기 도 한다. MVC의 의미는 공부하면서 찾아보라.

이게 뭐가 좋냐고? 개발 기간이 좀 길어지고 프로젝트 규모가 쬐끔 커지고, 기존 프로젝트를 유지보수를 해보면 얼마나 좋은지 몸소 뼈져리게 느끼게 된다.

Model 2의 기능을 정형화해서 쉽게 구현하게 해주는 것이 MVC Framework들의 역할이다.
가장 유명한 Model 2 웹 프레임워크들은 다음과 같은 것들이 있다.

* 스트럿츠 1 - Struts 1
* 스트럿츠 2 - Struts 2
* 스프링 MVC - Spring MVC
* 기타 덜 유명한 Wicket, Stripes, JSF, Tapestry 등.

Struts 1은 MVC의 효시라고 할 수 있다. 우리에게 MVC라는 축복을 주기는하였으나, 나온지 오래된 만큼 낡은 개념들이 많이 녹아있고 쓸데 없이 복잡하고 배우기도 어려운 편이다.

오히려 Struts 2와 Spring MVC가 더 배우기 쉬울 것이며, 개발도 더 쉽다. 현재 추세는 Struts 2와 Spring MVC이다. 대형 포탈이나 SI 업체들도 Spring/Struts 2를 주로 채택하는 추세로 가고 있는 것으로 알고 있다.

둘 중 하나의 개념만 확실히 이해해도 다른 것을 배우는데 어려움이 별로 없으므로 그냥 둘중에 골라서 배우길 권한다. 나는 Spring을 선호한다.

그리고 MVC 프레임워크를 사용하기 시작하면서 View를 만드는 JSP에 대해서도 재조명이 시작된다. 기존에 Java 코드를 JSP에 직접 넣던 관행을 버리고 JSTL과 태그 라이브러리를 사용하거나 아예 JSP를 버리고 다른 템플릿 엔진으로 만들기도 한다. 이에 관해서는 맨 마지막에.

4. 퍼시스턴스 프레임워크 : JDBC 반복 작업에 짜증이 나기 시작하다.
현대 웹 개발에서 가장 큰 역할을 차지하는 것은 뭐니뭐니해도 단연 Database 작업이다.
지금까지는 아마도 JDBC에서 DB 커넥션을 맺고, 쿼리를 날리고 그 결과 ResultSet을 JSP로 넘겨주어서 출력하는 식으로 했을 것이다.
이미 다들 알고 있겠지만 JDBC를 사용하면 똑같은 코드가 굉장히 많이 반복해서 나온다. 한마디로 "삽질"의 전형이 JDBC 작업이다.
이것을 깨달은 많은 개발자들이 조금 어정짱하게 반복작업을 해결해주는 Util 클래스들을 프로젝트별로 만들어서 사용하곤 한다.
하지만, 물론 이에 대해 정형화하고 깔끔하고 훨씬 더 사용하기 쉬게 만들려는 노력이 이미 수년에 걸쳐 이루어졌다.

이렇게 DB관련된 작업을 정형화한 것들을 Persistence Framework 라고 한다.

* 아이바티스 - iBATIS : SQL Mapper - JDBC보다 더 쉽게 배우고, 더 편하게 사용한다.
* 하이버네이트 - Hibernate : 객체지향을 객체지향답게, 개발 기간을 엄청나게 단축시켜주다.

퍼시스턴스 프레임워크의 양대 산맥은 iBATIS와 Hibernate이다. 이 둘 모두 우리나라에 책이 나와 있다.
iBATIS는 SQL Mapper의 한 종류이고, Hibernate는 ORM의 한 종류이다.

이 둘의 차이는 iBATIS는 개발자가 SQL 쿼리를 직접 작성한 것을 객체에 매핑시켜주는 것이고, ORM은 DB 스키마와 객체간의 관계를 설정파일로 만들면 자동으로 쿼리를 만들어주는 것이다.

자, 이 둘을 보면 미국에서는 Hibernate가 인기가 좋고, 우리나라에서는 iBATIS가 사실상 SI 업계를 평정했다.
그러니까, 일단은 우리나라에서는 iBATIS를 공부하면 된다고 보면 된다.

이렇게 말하니까 마치 이 둘이 경쟁자 같은데, 사실 이 둘은 경쟁 상대라기 보다는 보완해주는 역할을 한다. SI에서 처럼 DB 테이블이 정규화 되어 있지 않은 경우에는 Hibernate같은 ORM을 사용하면 프로젝트를 말아먹을 수 있다.

iBATIS는 테이블 정규화에 무관하게, 개발자가 작성한 SQL을 객체로 매핑하기 때문에 DB 스키마가 마구 꼬여 있는 상황에서도 유연하게 작동하고, 개발자가 직접 SQL 튜닝을 할 수 있다는 장점이다.

그리고 Hibernate는 배우기가 굉장히 어려운 프레임워크이고 튜닝이 매우 어렵다. Hibernate책을 보면 캐싱을 통해 성능을 향상시키라고 하지만 캐싱은 iBATIS도 못지않게 잘 지원한다. 하지만 일단 배우면, 그로인한 코딩 생산성이 iBATIS가 감히 넘볼 수 없을 정도록 급격히 향상된다.

Hibernate는 DB 정규화가 잘되어 있는 웹 포탈 업체나 패키지 소프트웨어 제작시에 강력히 권장할만 하다.

5. IoC와 DI - 객체의 생성주기와 의존성을 관리하고 싶어지다
사실 내가 경험한 SI를 보면 4단계 까지만 가도 막장은 아닌 프로젝트라고 본다. 아직도 신규 프로젝트를 하면서도 Model 1에 JDBC로 코딩하는 것을 많이 보았기 때문이다.

앞서, MVC라는 형태로 웹 애플리케이션의 역할을 철저하게 분할해서 처리하라고 했었다.

이제 여기서 좀 더 역할을 분할하기 시작한다.

Database를 관장하는 코드(DAO)와 Database 처리 결과를 가지고 그외 비지니스 로직을 추가로 수행하는 코드(Service), 그리고 웹으로 들어온 요청을 받아서 비지니스 로직을 호출하고, 그 결과를 다시 웹(HTML 등)으로 내보내는 코드(Controller)로 분할을 하면 유지보수가 더 쉽고, DB가 Oracle에서 DB2 로 변경되는 식의 중대 변화가 있을 때도 DAO만 바꾸면 되는 식으로 변화에 대한 대처가 유연해 진다는 것을 깨닫기 시작한다.

이제는 각 역할별로 클래스를 분할하고 컨트롤러 객체는 서비스 객체에 서비스 객체는 DAO 객체에 의존해서 작동하도록 코드를 바꾸기 시작한다. 그리고 객체의 생성과 파괴 주기도 관리해야만 하게 된다. 객체를 하나만 생성하면 되는데 불필요하게 매번 new를 할 필요는 없으니까.

이렇게 객체의 생성/파괴 주기를 관리하고 객체간의 의존성을 관리해주는 프레임워크를 IoC 컨테이너라고 부른다.

1. Spring Framework
2. EJB 3.0

사실상 대세는 Spring Framework로 굳어졌다. EJB 3.0은 내가 안써봐서 뭐라 말은 못하겠다.

Spring MVC는 이 Spring Framework의 일부분이다.

Spring은 또한 AOP도 지원한다.

AOP 의 개념이 상당히 어려운 편이라서 개념 자체를 확실히 한마디로는 표현하지 못하겠다. 어쨌든 개발자들에게 가장 쉽게 다가오는 표현으로 하자면, AOP는 동일한 패턴으로 반복적으로 해야하는 일을 설정을 통해 자동으로 해주는 것이다.
이에 관한 가장 보편적인 예가 바로 트랜잭션이다.
지금까지는 아마도 비지니스 로직이 시작될 때 트랜잭션이 시작되고, 비지니스 로직이 끝날 때 트랜잭션을 종료하는 코드를 매번 작성해서 넣었을 것이다.
AOP를 사용하면, 비지니스 로직의 역할을 하는 메소드가 무엇인지 설정파일에 넣어주기만 하면 자동으로 메소드가 시작될 때 트랜잭션을 시작시키고, 메소드가 끝날 때 트랜잭션을 종료시켜준다. 물론 예외가 발생하면 트랜잭션을 rollback도 해준다. 따라서 Spring을 사용한 프로젝트에서는 트랜잭션 관련 코드를 볼 수 없을 것이다.

Spring 프레임워크는 기본적으로 IoC 컨테이너 역할을 하는 것이 핵심이다. 따라서 Spring을 사용한다고 해서 꼭 Spring MVC를 사용할 필요는 없다. Struts 2 + Spring + iBATIS 나 SpringMVC + Spring + Hibernate 등... 어떠한 조합이라도 가능하다.

6. 그 외
◈ Template Engine : JSP 보다 더 간결하면서 강력한게 필요해!
   * JSP + JSTL : Sun이 지정한 산업표준이다. JSTL은 당연히 쓰고 있으리라 믿는다.
   * Freemarker : 가장 권장할 만하다.
   * Velocity : 굉장히 배우기 쉽다. JSTL보다 더 빨리 배워서 쓸 수 있다. 가독성도 좋다. 그러나 Freemarker 만큼 편하고 강력하지는 못하다.
많은 사람들이 Java 웹 개발을 그냥 "JSP 개발"이라고도 부르는데, MVC가 도입되고, Freemarker 같은 다른 템플릿 엔진을 사용하게 되면 더이상 JSP는 코빼기도 안보이게 된다. 그러므로.. JSP 개발이라는 말은 쓰지 않았으면 좋겠다.

◈ Layout Engine
   * Sitemesh : 헤더 푸터 처럼 동일 패턴이 반복되는 레이아웃을 관리해준다.

◈ XML 도우미 : W3C DOM은 너무 어렵고 난잡하다. 좀 더 편한 XML관련 개발을 원한다면..
   * JDOM : Java 표준으로 지정됐다고 한다.
   * DOM4J
둘 다 비슷하게 편한거 같다. 예전엔 JDOM을 썼었는데, 나 같은 경우 현재 프로젝트에서는 DOM4J를 사용한다. Hibernate가 DOM4J를 사용하기 때문에, 별도의 라이브러리 더 넣는게 귀찮아서.

◈ 단위 테스트
   * jUnit : 코드를 철저하게 테스트하자.

◈ 소스코드 버전관리
   * CVS
   * Subversion : 현재 대세는 Subversion
내가 최고 막장으로 꼽는 프로젝트는 아직도 FTP로 소스 관리하는 프로젝트이다. 이런 프로젝트에는 절대로 참여하지 않을 것이라고 굳게 맹세하고 또 맹세했다. --;
소스 코드 버전관리는 여러 개발자들이 동시에 개발할 때 소스코드를 저장하고 충돌을 관리해주며, 소스 변경 내역을 계속해서 추적해서 과거 소스로 언제든지 돌아갈 수 있도록 도와준다.
현재 대세는 Subversion이지만 CVS로도 버전관리의 이점을 충분히 만끽할 수 있다. 그리고.. 사실 CVS가 사용법을 익히기는 더 쉽다.

◈ 자동 빌드
   *
Ant : Ant 면 만사 Ok!
   *
Maven
아직도 javac 로 컴파일하고 있고, FTP로 파일 올려서 복사하고 있다면.. 이 모든일을 자동으로 명령 한방에 처리하도록 해야 실수도 적고, 퇴근도 일찍한다.
Ant로 빌드와 배포를 자동화 하자.

결론

내가 권하는 조합은
* SI 업체에서 일하는 경우 : Struts 2 혹은 SpringMVC + iBATIS + JSP/JSTL + 가능하다면 Spring Framework
* 웹 포털등과 같은 업계, 패키지 소프트웨어 제작 업체 : Struts 2 혹은 Spring MVC + Hibernate + Spring Framework + Freemarker + Sitemesh
 

'web' 카테고리의 다른 글

사용자 스토리  (0) 2009.12.31
처음부터 다시 배우는 리눅스  (0) 2009.12.31
[펌] [UML] UseCase Diagram  (0) 2009.12.31
ORA-04031 오라클 에러  (0) 2009.12.28
XML 강좌, JSTL 강좌  (0) 2009.12.28
스트럿츠2 실행시 Error filterStart  (0) 2009.12.27
[펌] yum 사용법  (0) 2009.12.27
svn (서브버전, Subversion) 사용 글 모음  (0) 2009.12.27
네이버 광고 차단하기 080602  (0) 2009.12.27
ASF MP3 변환 및 자르기 080223  (0) 2009.12.27
Posted by 뉴로
,
스트럿츠2 (Struts2) 를 테스트하고 있었는데 계속 다음과 같은 에러가 나오고 실행이 안되는겁니다.
톰켓을 실행할 때 표시되는 내용:
 
org.apache.catalina.core.StandardContext start
심각: Error filterStart
org.apache.catalina.core.StandardContext start
심각: Context [/strutsTest] startup failed due to previous errors
 
localhost.log 파일에는 이런 식으로 표시되죠.
org.apache.catalina.core.StandardContext filterStart
심각: Exception starting filter struts2
Unable to load configuration. - bean - jar:file: .../WEB-INF/lib/struts2-core-2.1.2.jar!/struts-default.xml:46:178
 
톰켓 버전에 따라서 XML validation disabled 라는 메시지도 표시되는 경우가 있는 것 같습니다.
 
web.xml 에서 필터 부분을 해석해주지 못하니까 에러를 발생시키고 스트럿츠2 실행을 못하는 현상입니다. 구글에서 이렇게 저렇게 찾아봤는데 처음에는 xml 파일을 UTF-8 로 인코딩 선언했는데 파일을 UTF 로 저장할 때 BOM 이 생겼기 때문이라는 글을 봤습니다. web.xml 과 struts.xml 파일을 검사해봤는데 이상 없었습니다.
 
엄청나게 헤맨 끝에 결국 답을 찾았습니다. 스트럿츠2 실행을 위해서 필요한 최소한의 라이브러리가 잘못되어 있었던겁니다. 제가 본 책이나 웹 사이트에는,
 
commons-logging-1.0.4.jar
freemarker-2.3.12.jar
ognl-2.6.11.jar
struts2-core-2.1.2.jar
xwork-2.1.1.jar
 
이 정도만 있으면 스트럿츠2 처음 공부할 때 나오는 HelloWorld 나 튜토리얼 실행 가능하다고 써있지만 이것만으로는 위의 경우같은 에러가 생깁니다. 이를 해결하려면
 
commons-fileupload-1.2.1.jar
 
를 추가해주어야 합니다. 결국 알고보면 별 것 아니었는데 이것때문에 많은 시간을 소비했네요.
jar 파일들의 버전은 사용하는 톰켓과 스트럿츠2 버전에 따라서 달라지겠죠. 제가 마지막 테스트에 사용한 버전은,
 
tomcat-6.0.18
jdk 1.6.0_06
struts-2.1.2 (beta)
 
 
 덧붙여서, 스트럿츠2 테스트 할 때 struts-2.x.x-all.zip 을 받았을 경우 그 안에 들어있는 lib 폴더의 모든 파일들을 라이브러리로 사용해도 문제가 생깁니다. 플러그인 관련 라이브러리들 때문에 생기는 문제니까 자신이 사용하는 목적에 맞는 라이브러리만 선택해서 사용하세요. 테스트라면 위에 나온 정도로 충분합니다.
 
===============================================================================
Error filterStart 가 발생하는 또 다른 경우:
잘 돌아가던 프로그램이 자바와 톰캣의 버전을 변경하면서 안되는 경우가 있습니다.
그런데, 에러메시지는 Error filterStart 외에 별다른 사항이 없어서 사람을 혼란스럽게 만드는 경우도 생깁니다.
 
JDK 1.5 와 Tomcat 5.5 를 쓰는 경우
javax.xml.transform.TransformerFactoryConfigurationError: Provider org.apache.xalan.processor.TransformerFactoryImpl not found
라는 에러가 발생할 수 있습니다.
 
톰캣설치폴더/common/endorsed 안에
 
xercesImpl.jar
xml-apis.jar
 
두 개의 파일이 같이 있는 경우 생기는 에러이며 해결책은 xml-apis.jar 를 지우면 됩니다.
 
struts2 필터 설정의 문제가 아니니 스트럿츠를 탓하지 맙시다...
 

Posted by 뉴로
,

[펌] yum 사용법

web 2009. 12. 27. 23:57
1. 업데이트할 목록을 보려면?

# yum list updates

2. 업데이트 목록을 다운로드하고, 업데이트를 설치하려면?

# yum update -y

3. 설치된 rpm 패키지 목록을 보려면?

# rpm -qa
# yum list installed

4. gcc 패키지가 설치되어 있는지 확인 하려면?

# rpm -qa | grep gcc
# yum list installed gcc

5. gcc 패키지를 설치하려면?

# yum install gcc gcc-c++

6. gcc 패키지를 업데이트 하려면?

# yum update gcc gcc-c++

7. 패키지 이름으로 검색하려면?

# yum list 패키지명
# yum list 정규식
# yum list gcc
# yum list gcc*

8. 여러개의 패키지를 설치하려면?

# yum install gcc gcc-c++

9. 패키지를 삭제하려면?

# yum remove gcc gcc-c++

10. 설치가 가능한 모든 패키지를 보려면?

# yum list all

11. 패키지 그룹을 보려면?

# yum grouplist

12. 그룹 패키지를 모두 설치하려면?

# yum groupinstall "Development Tools"

13. 그룹 패키지를 업데이트 하려면?

# yum groupupdate "Development Tools"

14. 그룹 패키지를 삭제하려면?

# yum groupremove "Development Tools"

15. 아키텍처를 지정하여 설치하려면?

# yum install mysql.i386

16. 파일을 가지고 있는 패키지명을 알려면?

# rpm -qf /etc/passwd
# yum whatprovides /etc/passwd

17. 맨페이지를 보려면?

# man yum


Posted by 뉴로
,
Posted by 뉴로
,
네이버 사이트 이용할 때 광고가 너무 많아서 귀찮게 느껴지는 분들은 다음과 같은 방법으로 네이버 광고를 차단할 수 있습니다.
 
인터넷 창 위쪽의 메뉴 중 [도구] 클릭 -> [인터넷 옵션] -> [보안] 으로 들어갑니다.
 
 
제한된 사이트를 누르면 아래와 같은 화면이 표시됩니다.


 
 
"영역에 웹 사이트 추가" 아래 입력란에 아래 주소를 하나씩 복사해서 넣고 추가를 눌러줍니다.
 
ad.naver.com
ad.news.naver.com
adc.naver.com
adcr.naver.com
adcreative.naver.com
ia.www.naver.com
nv.ad.naver.com
nv1.ad.naver.com
nv2.ad.naver.com
nv3.ad.naver.com
nv4.ad.naver.com
wrd.naver.com

이렇게 하면 대부분의 네이버 광고가 차단되서 보기 싫은 광고를 안 볼 수 있습니다.
 

Posted by 뉴로
,
asf 파일을 mp3 로 변환해야 할 일이 생겨서 검색을 해봤는데
검색결과가 썩 만족스럽지가 않아서 약간의 시행착오를 겪었습니다.
 
제가 원했던건
 
1) asf 파일을 자른다.
2) 잘라낸 asf 파일을 mp3 로 변환한다.
 
였는데 1) 의 과정에서 나온 결과물이 제대로 되지가 않아서 2) 의 과정에 문제가 있었습니다.
 
우선 asf 파일에서 원하는 부분만 잘라내기 위해 먼저 썼던 프로그램은 asftools v3.1 이었는데
이 프로그램은 사용하기 간편하고 좋은 프로그램이지만 잘라내는 과정에서 원본의 코덱이 아닌
다른 코덱으로 바꿔버리더군요. 그래서 mp3 변환 프로그램이 이 바뀐 코덱을 받아들이지 않아서
변환을 할 수 없었습니다.
 
그래서 asftools 를 포기하고 Steeper v1.1 을 사용해서 asf 파일을 잘라냈습니다.
 
이제 잘라낸 asf 파일을 mp3 로 변환해야 했는데 처음에는 asftools 를 썼기 때문에
이 프로그램이 지원하는 ASF -> WAV 변환 기능을 이용해서 일단 wav 파일로 만든 뒤
이걸 다시 CDex v1.70 Beta2 를 이용해서 WAV -> MP3 변환을 해야겠다고 생각했습니다.
 
그런데, asftools 의 코덱을 바꿔버리는 문제때문에 wav 도 역시 변환에 문제가 있었습니다.
결국 asftools 를 포기하고 찾은 프로그램이 골드웨이브(GoldWave v5.23) 입니다.
 
골드웨이브는 asf 파일을 바로 mp3 로 변환 가능합니다. asf 파일을 읽어들인 뒤 Save As 로
저장하면서 원하는 비트레이트 등의 옵션을 지정해주면 바로 mp3 로 저장됩니다.
 
결론:
 
1) asf 파일은 Steeper v1.1 을 이용해서 잘라낸다.
2) 잘라낸 asf 파일을 GoldWave v5.23 로 mp3 로 변환
 
골드웨이브에서 mp3 변환할 때 MP3 Encoder 를 설치하라고 안내문이 뜨는데
안내문 링크를 클릭해서 encoder 를 받고, 받은 압축파일을 풀어서 그 중
lame_enc.dll 파일을 골드웨이브 설치 폴더(설치시 변경안했다면 기본적으로
C:\Program Files\GoldWave 에 설치됩니다.)에 복사해주면 됩니다.
 
두 프로그램은 모두 엠파스 자료실에서 다운로드 가능합니다.


<2012.01.30 추가사항>
엠파스가 없어져서 위 링크가 동작을 안하네요. 새로 링크 걸어 드립니다. Steeper 는 1.2 버전으로 올라갔네요. 골드웨이브도 작성일 현재 5.66 까지 나와있고요. 아래 링크 말고 네이버 등에서 검색하면 포탈자료실에서도 찾을 수 있습니다. 버전 달라도 괜찮아요.

Steeper V1.2
 http://proletsoft.freeservers.com/mmb/steeper.html   에 가서 아래쪽에 보면 Download Steeper v1.2 라는 링크가 있으니 클릭하세요.
 
GoldWave V5.66   http://www.goldwave.com/release.php

 
Posted by 뉴로
,
출처: http://blog.naver.com/kickthebaby/20007714481
 
아래 표는 윈도우에서 주로 사용하는 시스템 프로세스(process)에 대한 정의입니다. 한글로 옮기려다 그리 어렵지 않은 단어들의 구성이라 그냥 테이블을 옮깁니다. 이 테이블에 포함된 프로세스는 윈도우가 정상적으로 동작하거나 기본적인 기능을 하기 위해 필수적인 것들입니다. 윈도XP 이상 버전에서 Ctrl+Alt+Del 키를 동시에 누르면 나타나는 "작업 관리자"의 프로세스 창에서 현재 실행 중인 프로세스를 볼 수 있습니다.
 
아래 표를 참조하시면 백그라운드에 떠 있는 프로세스 가운데 필요없는 프로세스를 강제로 없앨 수 있습니다. 혹은 자신도 모르게 설치된 스파이웨어나 불필요한 프로그램을 발견할 수도 있습니다. 이 표는 http://www.liutilities.com/ 에서 제공하는 System Processes Listed in the WinTasks Process Library를 옮겨 온 것입니다.
 
 
System Processes    
 [system process]  actmovie.exe  agentsvr.exe
 alg.exe  ASPNET_WP.exe  btwdins.exe
 ccmexec.exe  cidaemon.exe  cisvc.exe
 clisvcl.exe  cmd.exe  Control.exe
 crss.exe  csrss.exe  ctfmon.exe
 ddhelp.exe  dfssvc.exe  dllhost.exe
 dos4gw.exe  dumprep.exe  explorer.exe
 fast.exe  grpconv.exe  hidserv.exe
 iexplore.exe  imapi.exe  inetinfo.exe
 internat.exe  kernel32.dll  launch32.exe
 loadwc.exe  locator.exe  logonui.exe
 lsass.exe  mad.exe  mapisp32.exe
 mdm.exe  mmc.exe  mmtask.tsk
 mprexe.exe  msconfig.exe  msdtc.exe
 msgsrv32.exe  msiexec.exe  msoobe.exe
 mstask.exe  mstinit.exe  ndisuio.sys
 netdde.exe  ntoskrnl.exe  ntvdm.exe
 pstores.exe  rasautou.exe  rdpclip.exe
 regsvc.exe  regsvr32.exe  rnaapp.exe
 rpcss.exe  rsvp.exe  rundll32.exe
 runonce.exe  sapisvr.exe  scanregw.exe
 scardsvr.exe  services.exe  smss.exe
 snmp.exe  spool32.exe  spoolss.exe
 spoolsv.exe  srvany.exe  svchost.exe
 system  System Idle Process  systray.exe
 tapisrv.exe  taskmgr.exe  taskmon.exe
 tcpsvcs.exe  userinit.exe  winlogon.exe
 winmgmt.exe  winoa386.mod  WMIADAP.EXE
 wmiexe.exe  wmiprvse.exe  wowexec.exe
 wpabaln.exe  wscntfy.exe  wuaclt.exe
 wuauboot.exe  wuauclt.exe  wuaudt.exe
 wucrtupd.exe

Posted by 뉴로
,
엄청난 고전 자료. 이제는 의미 없는...
이제는 프레임워크를 다들 쓰니까 이런 날코딩은 없겠지요?
=======================================

======================================================
Making efficient use of Oracle8i thru Apache and PHP 4
======================================================

    (c) Thies C. Arntzen <thies@thieso.net> 2001


introduction
============

this paper will give you an overview of the points covered in my "Making
efficient use of Oracle" session. it will cover:

- connecting
- transactions
- error-handling
- binding & defining
- autoincrement
- efficient "select for update" using ROWID
- large objects
- nested tables
- stored procedures
- refcursors
- collections


connecting
==========

when you connect to an oracle-instance thru PHP you get back a db-handle:

$db = OCILogon("scott","tiger");

this db-handle consists of a few individual oracle structures. the
important ones are the server-handle which holds the connection to the
oracle-server second we need the session-handle which carries the
authenticated user/password and the third one is our so called
service-context.

during the login the most expensive operation is setting up the
server-handle as this actually creates the oracle shadow process on the
server side. starting a session over this already established link is
still somehow expensive but relatively cheap compared to the former. last
but not least creating the service-context is a no-brainer as the creation
of the service-context does not even need a sever-round-trip (= the client
lib needs to talk to the server)

therefore PHP tries it's best to avoid the creation of unneeded
server-handles and session-handles. all of this complexity is hidden
inside the three available log-on functions within PHP:


OCILogon($username,$password[, $tnsname ]);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gets you a standard, non-persistent connection that will be closed
automatically by PHP on script-end. PHP will reuse existing
server-handles and session-handles.

OCIPLogon($username,$password[, $tnsname ]);

will do the same as OCILogon() but mark the sever and session handle
as persistent, which means that PHP won't close them on script-end. if
your script does a OCILogon("s","t") and later a OCIPLogon("s","t")
_no_ new server or session handle will be created but instead the
existing ones will be marked persistent.

OCINLogon($username,$password[, $tnsname ]);

will reuse server-handles but always create a new session handle. this
is because oracle has tied the transaction context to the
session-handle. so if you need to isolate transactions on one page you
would use OCILogon() or OCIPLogon() for the "main" connection and
create an additional connection using OCINLogon(). the OCINLogon()
connection would be handled thru the same server-handle as the other
connection but would have it's own session-handle. side-note: the
session-handle created by OCINLogon() will always be freed at the end
of the script.


if we have a page like this:

<?php

  $scottDB = OCILogon("scott","tiger","TC");

  // will create a server-handle and connect to to database "TC"

  $sysDB = OCILogon("sys","manager","TC");

  // will reuse the "TC" server-handle from our 1st OCILogon() call but
  // create a new session-handle

  $paulDB = OCIPLogon("paul","lion","TC");

  // will reuse the "TC" server-handle from our 1st OCILogon() _and_ mark
  // it persistent. as a new session-handle is created for "paul"

  $scott2DB = OCIPLogon("scott","tiger","TC");

  // will reuse "TC" (which is already marked as persistent) and reuse
  // the "scott" session-handle and mark that as persistent as well

  $scott3DB = OCINLogon("scott","tiger","TC");


  // will reuse "TC" (which is already marked as persistent) and create a
  // new session-handle as we used OCINLogon()

  ....
?>

is this page (which doesn't make any sense in it's current form) gets
loaded the picture changes:

<?php

  $scottDB = OCILogon("scott","tiger","TC");

  // "TC" from cache, "scott" from cache

  $sysDB = OCILogon("sys","manager","TC");

  // "TC" from cache, create session-handle fro "sys"

  $paulDB = OCIPLogon("paul","lion","TC");

  // "TC" from cache, create session-handle fro "paul"

  $scott2DB = OCIPLogon("scott","tiger","TC");

  // "TC" from cache, "scott" from cache

  $scott3DB = OCINLogon("scott","tiger","TC");

  // "TC" from cache, new "scott" session as we want to isolate
  // transactions.

  ....
?>

the important thing is that we only need one server-connection per
database-server that we connect and that we can run as many session thru
this one channel as we like and that PHP does the thinking for us!


transactions
============

by default PHP works in the COMMIT_ON_SUCCESS mode (auto-commit-mode).

names.sql
create table names (id number, name varchar2(32));

<?php
$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"insert into names values (1,'thies')");
OCIExecute($stmt);

// PHP does _all_ cleanups for us!
?>

if we want to do the commit ourself:

<?php
$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"insert into names values (1,'thies')");
OCIExecute($stmt,OCI_DEFAULT);

OCICommit($db); // or OCIRollback($db);

// PHP does _all_ cleanups for us!
?>

note: see the OCI_DEFAULT parameter in the OCIExecute() call!

as said before oracle ties the transaction-context to the session-handle
which means that if we only use OCILogon() (and not OCINLogon()) we won't
get any transaction-isolation.

if we need to have a second isolated transaction-context in our sample we
would have to write:

<?php
$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"insert into names values (1,'thies')");
OCIExecute($stmt,OCI_DEFAULT);

$idb = OCINLogon("scott","tiger");
$istmt = OCIParse($idb,"select name from names where id = 1");
OCIExecute($istmt);
while (OCIFetch($istmt))
echo OCIResult($istmt,"NAME")."\n"; // will not show the just inserted
// row as we live i a different
// transaction context and the
// insert is not committed yet!

OCICommit($db);
echo "\n";

OCIExecute($istmt); // reexecute the "select" statement
while (OCIFetch($istmt))
echo OCIResult($istmt,"NAME")."\n"; // will now show the just inserted
// row!

// PHP does _all_ cleanups for us!
?>

BTW: on script end all uncommitted transactions will get rolled-back!

error-handling
==============

PHP stores oracle-errors in the context they happened. you have to call
OCIError() to retrieve the error-code and error-message from oracle. the
function OCIError() returns FALSE if no error has occurred in the selected
context or an associative array containing the "code" and "message" of the
error. this little example illustrates how:

<?php

$db = OCILogon("scott","tiger");
if (! $db) { // connection failed
// as we don't have a connection yet the error is stored in the
// module global error-handle
$err = OCIError();

if ($err[ "code" ] == "12545") {
echo "target host or object does not exist\n";
}
die();
}

$stmt = OCIParse($db,"select sysdate from dual");
if (! $stmt) {
// when OCIParse() reports an error (usually a parse-error) the
// error is stored in the connection-handle that was used for
// parsing.

$err = OCIError($db);
echo $err[ "code" ]." ".$err[ "message" ]."\n";
die();
}

if (! OCIExecute($stmt)) {
// when OCIExecute() fails the error is stored in the supplied
// statement-handle

$err = OCIError($stmt);
echo $err[ "code" ]." ".$err[ "message" ]."\n";
die();
}
?>

all errors that are reported by oracle are also sent to the standard PHP
error-handler with E_WARNING priority. so if you want to handle all oracle
related errors yourself it's maybe a good idea to prefix all OCI*() calls
with an '@'.

binding & defining
==================

one of the more advanced features of oracle and the PHP interface is that
it allows user defined bind- and define-variables. binding is the
technique that allows to have placeholder in your sql-statement and
oracle will take the value of the bound-variable directly from
script-space. this has two major advantages: you don't have to escape
quotes in you field-values as would have to do if you were in-lining the
values in your sql-statement. example: you want to insert O'Hare into your
oracle DB so you have to say "insert into names values ('O''Hare')".
even though PHP can easily escape the apostrophe it's still an extra step.

the bigger advantage is that oracle is very smart about reusing already
parsed statements. parsing statements is considered an expensive operation
on oracle. user-rights, field-name etc are checked against the db during
statement parsing. therefore oracle caches the parsed representation of
your sql in the so called SGA (Server Global-Area). if you issue the
_exact_ same sql again, oracle would find the already parsed statement and
reexecuted that. so instead of saying:

<?php

$data = array("2" => "larry","3" => "bill", "4" => "steve");

$db = OCILogon("scott","tiger");
while (list($id,$name) = each($data)) {
$id = strtr($id,array("'","''"));
$name = strtr($name,array("'","''"));

$stmt = OCIParse($db,"insert into names values ('$id','$name')");
OCIExecute($stmt);
}
?>

you would say:

<?php

$data = array("2" => "larry","3" => "bill", "4" => "steve");

$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"insert into names values (:id,:name)");
OCIBindByName($stmt,":ID",$id,32);
OCIBindByName($stmt,":NAME",$name,32);

while (list($id,$name) = each($data))
OCIExecute($stmt);
?>

voila! we'll see more about binds later!


defining on the other hand allows us to receive rows from oracle into
predefined PHP-variables.

instead of saying:

<?php

$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"select * from names");
OCIExecute($stmt);

while (OCIFetch($stmt)) {
echo "id:".OCIResult($stmt,"ID")."\n";
echo "name:".OCIResult($stmt,"NAME")."\n";
}
?>

we can say:

<?php

$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"select * from names");

// note that oracle converts all colum-names to UPPERCASE
OCIDefineByName($stmt,"ID",$id);
OCIDefineByName($stmt,"NAME",$name);

OCIExecute($stmt);

while (OCIFetch($stmt)) {
echo "id:$id\n";
echo "name:$name\n";
}
?>

this combined with OCIBindByName() would allow us to copy one table to
another without any script-level assignments:

names2.sql
create table names2 (id number, name varchar2(32));

<?php

$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"select * from names");
$insert = OCIParse($db,"insert into names2 values (:ID,:NAME)");

// note that oracle converts all column-names to UPPERCASE
OCIDefineByName($stmt,"ID",$id);
OCIDefineByName($stmt,"NAME",$name);

OCIBindByName($insert,"ID",$id,32);
OCIBindByName($insert,"NAME",$name,32);

OCIExecute($stmt);

while (OCIFetch($stmt)) {
OCIExecute($insert);
}
?>

note: the PHP oracle interface fully supports the SQL NULL-value when
using bind & define!

autoincrement
=============

so called sequencers are very useful for generating the unique-id (primary
key) that every GoodTable(tm) should have. oracle allows you to have triggers
auto-fill the next value of a sequencer into your primary-key field but
when you insert a record into your table they won't tell the actual
sequencer-value used (see mysql_insert_id()). to get the oci_insert_id()
_without_ an extra server-round-trip you can use the oracle "RETURNING"
clause together with a bound-variable:

seq.sql
create sequence myid;

<?php

$data = array("larry","bill","steve");

$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"insert into names values (myid.nextval,:name) returning id into :id");
OCIBindByName($stmt,":ID",$id,32);
OCIBindByName($stmt,":NAME",$name,32);

while (list(,$name) = each($data)) {
OCIExecute($stmt);
echo "$name got id:$id\n";
}
?>

efficient "select for update" using ROWID
=========================================

if you need to update your chicken table you usually do a select
to get the old row values from your database, then you do some
calculations based on the just read values and then you update that very record
in the database with the updated values. as said before having a unique
field as the primary-key in every table is a SmartThing(tm) to do but to
do the most efficient update you don't need that when you use oracle.
in oracle every row has an "address" inside the database which is called
the ROWID. this ROWID is unique over all tables in the database and filled
in automatically by oracle. so why not use this as the primary key?
simple answer, the ROWID changes when you export and re-import the table.
but for a simple update the ROWID is still the most efficient way of
addressing the record to be updated!

chicken.sql
create table chicken (id number, chickens_sold number);
insert into chicken values (1,100);

    <?php

        $db = OCILogon("scott","tiger");

        $stmt = OCIParse($db,"select rowid,chickens_sold from chicken for update");
        OCIDefineByName($stmt,"CHICKENS_SOLD",$chickens_sold);
        OCIDefineByName($stmt,"ROWID",$rid);
        OCIExecute($stmt,OCI_DEFAULT);
        OCIFetch($stmt);

echo "chicken sold so far: $chickens_sold\n";

$update = OCIParse($db,"update chicken set chickens_sold=:chickens_sold where rowid = :rid");
OCIBindByName($update,"CHICKENS_SOLD",$chickens_sold,32);
OCIBindByName($update,"RID",$rid,-1,OCI_B_ROWID);

$chickens_sold += 100;

OCIExecute($update);
OCICommit($db);
    ?>

note: ROWID is handled as an opaque data-type within PHP (you cannot print
it as a string). if you need the ROWID as a string do
"select ROWIDTOCHAR(rowid) from chicken"

large objects
=============

PHP has full support for using internal and external LOBs in oracle. LOBs
are different from "normal" data-types as they require extra programming on
the script side. when you need to store large amount of data in one field
LOBs are the ideal choice. you could also store bigger fields (up to 2GB)
in a "LONG" or "LONG RAW" field (which is as good supported be PHP) but
oracle plans to drop support for those types in future releases. "LONG"
and "LONG RAW" fields can not be replicated across servers and they will
always get loaded into memory when the row containing the "LONG" or "LONG
RAW" is touched. LOBs don't have this limitation but cause a tiny bit more
headache when used. oracle has CLOBs (character-LOB) BLOBs (binary-LOB)
and BFILEs (external files - only path to file is stored in database).

before you can use a LOB oracle needs to create it - lets illustrate:

blobdemo.sql
create table blobdemo (id number, lob blob);

<?php

$data = array("/lib/libc-2.2.2.so","/lib/libncurses.so.5.2");

$db = OCILogon("scott","tiger");
$stmt = OCIParse($db,"insert into blobdemo values
(myid.nextval,EMPTY_BLOB()) returning id,lob into :id,:lob");
$lob = OCINewDescriptor($db);
OCIBindByName($stmt,":ID",$id,32);
OCIBindByName($stmt,":LOB",$lob,-1,SQLT_BLOB);

while (list(,$file) = each($data)) {
OCIExecute($stmt,OCI_DEFAULT); // we cannot use autocommitt here
$lob->save(`cat $file`);
echo "$file id:$id\n";
OCICommit($db);
}
?>

now we have loaded our libc and ncurses into oracle - makes sense;-)

getting them back is more trivial:

    <?php

        $db = OCILogon("scott","tiger");
        $stmt = OCIParse($db,"select * from blobdemo");
        OCIExecute($stmt);

        while (OCIFetchInto($stmt,$arr,OCI_ASSOC)) {
echo "id: ".$arr[ "ID" ]."\n";
echo "size: ".strlen($arr[ "LOB" ]->load())."\n";
}
    ?>

to update a lob you have to load the LOB-descriptor first:

    <?php

        $db = OCILogon("scott","tiger");
        $stmt = OCIParse($db,"select blob from blobdemo for update");
        OCIExecute($stmt,OCI_DEFAULT);

        while (OCIFetchInto($stmt,$arr,OCI_ASSOC)) {
$content = $arr[ "LOB" ]->load();

echo "id: ".$arr[ "ID" ]."\n";
echo "size: ".strlen($content)."\n";

$lob->save(strrev($content));
}
OCICommit($db);
    ?>

there are functions to just replace a part of a LOB, you can spool a LOB
to the browser or a file _without_ buffering it a PHP-variable. the
OCIFetchInto function also allows you to inline the LOB values into your
result-set, this saves you the call to ->load() but LOB-data which is
returned instead of the locator can not be modified like shown above.


the oracle-BFILE type can be read like a normal LOB/CLOB but can't be
written to. basically you can store the path to a file on the
oracle-server in a table-field and the LOB functions allow you to read this
file thru the oracle server-connection. this can be extremely helpful if
your web-server is in front of a firewall and you only want to allow
oracle-traffic thru this firewall (no NFS-traffic). the BFILE allows you
to keep your images in the file-system so they don't clutter your
table-space but you can still access them as if they were a part of your
database!

nested tables
=============

lets say we have a user and a duty table:

create table family (id number, name varchar2(32));
create table duties (id number, user_id number, duty varchar2(32));

and we preload some data:

insert into family values (1, 'thies');
insert into duties values (1, 1, 'cook');
insert into duties values (1, 1, 'make tea');
insert into duties values (1, 1, 'fix the code');

insert into family values (2, 'antje');
insert into duties values (1, 2, 'change dipers');
insert into duties values (1, 2, 'bring kid to school');

we can now say (in sqlplus):

select id,name,CURSOR(select duty from duties where duties.user_id = family.id) as duties
from family;

in PHP we would have to say:

<?
        $db = OCILogon("scott","tiger");
        $stmt = OCIParse($db,"
                select name,CURSOR(select duty from duties where duties.user_id = family.id) as duties
                from family");

        OCIExecute($stmt);

        while (OCIFetchinto($stmt,$arr,OCI_ASSOC)) {
            echo $arr[ "NAME" ]."\n";
            echo "-----\n";

            // Now execute the sub-query
            OCIExecute($arr[ "DUTIES" ]);
            while (OCIFetchinto($arr[ "DUTIES" ],$duties,OCI_ASSOC)) {
                echo $duties[ "DUTY" ]."\n";
            }
echo "\n";
        }
    ?>

gets us:

thies
-----
make tea
fix the code
cook

antje
-----
change dipers
bring kid to school




stored procedures
=================

calling stored-procedures from PHP is trivial once you understood the
binding of variables:

inoutdemo.sql
CREATE OR REPLACE PROCEDURE inoutdemo (
par_in IN VARCHAR2,
      par_in_out IN OUT VARCHAR2,
      par_out OUT VARCHAR2)
IS
BEGIN
      par_out := par_in;
    par_in_out := par_in || ' ' || par_in_out;
END;

<?
        $db = OCILogon("scott","tiger");
        $stmt = OCIParse($db,"BEGIN inoutdemo(:in,:inout,:out); END;");
        OCIBindByName($stmt,":in",$in,32);
        OCIBindByName($stmt,":inout",$inout,32);
        OCIBindByName($stmt,":out",$out,32);

        $in = "Hello ";
        $inout = "World!";

        OCIExecute($stmt);

        echo $in."\n";
        echo $inout."\n";
        echo $out."\n";
    ?>


refcursors
==========

very similar to the nested-tables are refcursors which can be passed out of
stored-procedures:

CREATE OR REPLACE PACKAGE info AS
TYPE the_data IS REF CURSOR RETURN all_users%ROWTYPE;
PROCEDURE output(return_data IN OUT the_data);
END info;
/
CREATE OR REPLACE PACKAGE BODY info AS
PROCEDURE output(return_data IN OUT the_data) IS
  BEGIN
OPEN return_data FOR SELECT * FROM all_users;
END output;
END info;
/


to call this procedure from PHP we would have to say:


<?php
        $db = OCILogon("scott","tiger");

$curs = OCINewCursor($db);

        $stmt = OCIParse($db,"begin info.output(:data); end;");
        OCIBindByName($stmt,":data",$curs,-1,OCI_B_CURSOR);
        OCIExecute($stmt);
        OCIExecute($curs);

while (OCIFetchinto($curs,$duties,OCI_ASSOC)) {
var_dump($duties);
}
    ?>


collections
===========

collections are a way to pass a variable number of items to a stored
procedure. they are very helpful to reduce to number of roundtrips to the
database when inserting more than one record at a time. if we have a table
with user-responsibilities like this:

CREATE TABLE user_responsibilities(
user_id VARCHAR2(100),
   responsibility VARCHAR2(100)
   );

we might want to update the responsibilities of one user with a new set -
in PHP wo would do:

<?php
$duties = array("clean","cook","buy-food");
$user = "andy";

        $db = OCILogon("scott","tiger");
        $stmt = OCIParse($db,"DELETE FROM user_responsibilities WHERE user_id = '$user'");
        OCIExecute($stmt);

while (list(,$v) = each($duties)) {
$stmt = OCIParse($db,"INSERT INTO user_responsibilities
  (user_id,responsibility)
  values('$user','$v')");
OCIExecute($stmt);
   }
?>


we would end up doing a lot of database-roundtrips doing it this way! if we
use the collection feature of oracle we could save most of the roundtrips
and let oracle do all the work for us:


CREATE OR REPLACE TYPE str_vec AS VARRAY(100) OF VARCHAR2(100);

CREATE OR REPLACE PROCEDURE update_responsiblities(
i_user_id IN VARCHAR2,
i_responsibilities IN str_vec)
IS
BEGIN
   DELETE FROM user_responsibilities WHERE user_id = i_user_id;
   FOR i IN 1 .. i_responsibilities.count LOOP
  INSERT INTO user_responsibilities(user_id,responsibility) values
(i_user_id,i_responsibilities(i));
   END LOOP;
END;

<?php
$duties = array("clean","cook","buy-food");
$user = "andy";

        $db = OCILogon("scott","tiger");

   $arr = OCINewCollection($db,'STR_VEC');
   $stmt = OCIParse($db,"begin update_responsiblities(:user,:duties); end;");

while (list(,$v) = each($duties)) {
   $arr->append($v);
}

    OCIBindByName($stmt,':user',$user);
   OCIBindByName($stmt,':duties',$arr,32,OCI_B_SQLT_NTY);

   OCIExecute($stmt);
?>


outlook into the future
=======================

- connection pooling
- failover

Posted by 뉴로
,
무려 2004년 3월달의 이야기입니다.
그 당시에는 저랬군 하고 넘어가시면 되겠습니다.
==============================================


엠파스 블로그(http://blog.empas.com
 HTML에디터 편집창의 툴바(Tool Bar)의 모습

 
 다른건 크게 다른것이 없으나 박스를 유심히 보면 네이버에 없는 기능이다. 흔히 워드프로세서에나 있는 번호매기기나 내어쓰기, 들여쓰기 기능이 있다. 본인처럼 공백문자로 정열을 하는 노가다 꾼에겐 정말 필요한 기능이다. 그리고 그 뒤로 보이는 선긋기나 HTML 코딩편집도 정말 유용한 기능이 아닐 수 없다.
 
 지금까지의 설명을 듣자면 분명 네이버보다 좋아 보일 수도 있다. 하지만 이 포스트를 작성하면서 비교도 많이 해 보았다. 감성블로그를 지향하는 네이버의 입장에선 하루 아침에 모든 기능을 지원할 수 는 없겠지만, 적어도 엠파스의 블로그를 벤치마킹해서 도입할 것은 과감히 도입해야 한다.
 
 이런 저런 기능들을 종합하고 비교해보면 그래도 네이버가 다소 우위에 있다고 느낀다. 기능을 떠나 인터페이스(사용환경)에 있어서는 네이버가 좀더 친근하고 세련된 느낌을 지울 수 없다. 세부적인 디자인에 대한 선택권까지 사용자에게 주어진 네이버와 제한된 스킨으로 디자인을 해야 할 엠파스와 무엇이 더 낫겠는가?
 
 비록 중요하고 필요한 기능이 빠졌다 할지라도 앞으로 추가될 기능과 서버의 안정을 기대하며 네이버에 끊임없는 관심과 향상을 바란다. 네이버 커뮤니티개발팀! 좀 더 분발해 주세요!
 
- Rhodanthe
 

http://blog.naver.com/nass.do?Redirect=Dlog&Qs=/nass/20001145727
에서 가져왔습니다~




출처: http://ilmano.egloos.com/704491
Posted by 뉴로
,
2004년 3월에 작성했던 글입니다. 그 시절을 상상하며 읽읍시다.
==============================

누구나 다 아는 얘기 같지만 그래도 다시 한 번 짚고 넘어간다는 의미에서 적어봅니다.

1) 네비게이션 편의를 위한 현재 위치 확인기능 제공

2) 네비게이션 편의를 위한 사이트맵 제공

    ○ 가급적이면 텍스트로 구성하며 전체 웹 사이트의 구조를 쉽게 파악할 수 있도록 하고, 원하는 곳으로의 이동을 쉽게 할 수 있도록 해야 합니다.

3) 회원 가입 양식에서의 사용성 

    ○ 사용자가 입력 할 때 TAB 키를 이용하여 순차적으로 쉽게 이동할 수 있도록 하고 필요한 경우는 자동으로 입력 칸이 이동되도록 합니다. 은행, 카드 사이트들이 이런 부분들을 잘 처리하고 있죠.

    ○ 가급적 사용자 정보는 꼭 필요한 것만 물어봅시다. 개인사이트 들에서 쓸데없이 주민등록번호를 입력하게 할 필요는 없습니다. 암호화 되어 관리자는 볼 수 없고 중복 가입을 방지한다는 의미에서 그렇게 한다지만 굳이 그렇게 할 필요가 있나요?

4) 초보자를 위한 가이드 제공

    ○ 가이드 없이도 쉽게 쓸 수 있도록 만드는 것이 가장 좋은 방법이겠습니다만.

    ○ HELP DESK 와 FAQ 의 활용

5) 정보이용 내역의 제공

    ○ 유료컨텐츠 제공 사이트라면 반드시 필요합니다.

6) 검색 서비스에서의 사용성
   
    ○ 검색은 결과가 제대로 나오지 못한다면 차라리 없는 것이 낫습니다.

7) 주요 메뉴에 대한 바로가기 기능 제공

8) 팝업(새창 띄우기) 창에서의 사용성

9) 표준화된 메뉴 이름 사용

     ○ 쉬운 것 같으면서도 좀 까다로운 부분이라고 생각됩니다. 이걸 누르면 뭐가 되고 어디로 가는지 사용자가 고민하지 않도록 해야합니다.

10) 기타

      쓸데없는 플래시는 쓰지 말아야 합니다. 사이트는 가급적 가볍게 만들어야 한다고 생각합니다. 뽀대내려고 플래시로 도배한 사이트는 개인적으로 짜증이 나서 다시 가기 싫더군요.


Posted by 뉴로
,

프로그래밍 추천 도서

web 2009. 9. 26. 09:04
잘 정리 되어있어서 퍼왔습니다.
출처가 엠파스 블로그이고 그 글도 이글루스에서 가져온 것으로 되어있는데 이글루스 링크는 연결이 되지 않습니다. 엠파스 블로그도 현재는 문을 닫아서 올해가 지나면 모든 글이 삭제되는 것으로 알고 있어요.

출처: http://blog.empas.com/newcan77/21737719



#. C 
(참고루 어려운 언어입니다. 
혹, 책을 보시다가 자신의 머리를 탓하거나 지금의 길이 내길이 아니라 느끼실 경우가 있는데 너무 상심마시길
언어가 어려워서 그런겁니다. ^^)

1. The C Programming Language : ANSI C Version (2nd Edition)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=199608030003
(C언어의 창시자 Brian W. Kernighan, Dennis M. Ritchie의 저서 입니다. 
모든 언어는 그 언어제작자가 쓴 책을 가장 먼저보는게 좋습니다.)

2. The Practice of Programming
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200001240005
(C언어의 창시자중 한명인 Brian W. Kernighan의 저서 입니다.)

3. Programming Pearls, 2nd Edition
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200301140012
(김창준씨가 눈물을 흘리며 보아야 한다고 언급한 책 ㅠㅠ)

4. 유닉스 ? 리눅스 프로그래밍 필수 유틸리티 : vi, make, gcc, gdb, cvs, rpm
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200411040005
(제 개인적인 생각이지만, C언어의 좀더 깊은 면을 알고싶으면 
UNIX계열의 OS를 다루어 보아야 한다고 생각합니다. 당연히 Linux도 포함됩니다.)

5. Art of UNIX Programming
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200408050002

6. Advanced Programming in the UNIX Environment
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=199407270054
(몇해 전 작고하신 STEVENS 할아버지의 명저입니다. ㅠㅠ)

#. C++
(C 보다 훨씬 더 어렵습니다. 제가 본 언어중에 젤 어렵습니다. ㅡㅡ.)

1-1. The C++ Programming Language Special Edition
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200505090002
(언어 제작자인 Bjarne Stroustrup의 저서 이지만 그 양이 넘 방대하여 
처음 보시려구 하면 곰이 마늘과 쑥을 먹을 정도의 굉장한 인내력이 필요하므로 다음의 책도 가능합니다.)

1-2. 초보자를 위한 C++ 21일완성 (최신개정4판)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200301270002
(제가 처음으로 본 프로그래밍 책입이다. ^^; 21일완성 시리즈는 악서로 유명합니다.
하지만 그중에서 그나마 칭찬이 나오는 책입니다.)

2. Accelerated C++ : 예제로 배우는 진짜배기 C++ 프로그래밍
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200303030001
(Bjarne Stroustrup이 왜 이제서야 이런책이 나왔는지 한탄하며 극찬한 책입니다.)

3. 에센셜 C++(Essential C++)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200306200002

4. EFFECTIVE C++ 2편
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=199803010003
(존경하는 C++의 대가 Scott Meyers를 세상에 알려준 명저입니다. 하지만 번역이 어려운 책을 더욱 어렵게 합니다.
현재 원서는 3판이 나왔으며 그것을 곽용재가 씨가 번역중인걸로 알고 있습니다.
참고루 이 책은 스터디 하기에 좋은 책입니다.)

5. More Effective C++
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200301290001
(전작이 너무 좋아서 하나 더 쓴 겁니다. ^^; 
서문에서 자신은 Template를 잘 몰라 이것에 대해 언급하지 않았다는 Meyers의 말에 경의를 표합니다. ㅠㅠ)

6. Effective STL : C++ 표준 템플릿 라이브러리(STL)를 효과적으로 활용하는 50가지의 명쾌한 테크닉 모음
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200201120001
(역시 Meyers의 Effective Serise 눈물을 줄줄 흘리며 보아야 합니다. ㅠㅠ)

7. Design Patterns Explained: A New Perspective on Object-Oriented Design
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200305270002
(일명 DPE로 알려진 명저입니다. 김창준씨가 Design Pattern입문서로 극추한 책입니다.)

8. GoF의 디자인 패턴 : Design Patterns
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200209240010
(OOP의 4명의 깽, JOHN VLISSIDES, Erich Gamma, Ralph Johnson, Richard Helm들이 모여 세상에서 가장 어려운
책중에 하나를 만들어보자며 만든 책인거 같습니다. ㅠㅠ)

9. 제네릭 프로그래밍과 디자인 패턴을 적용한 Modern C++ Design
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200303030004
(C++를 OOP Paradigm이 아닌 Generic Paradigm으로 보자는 내용이 주를 이룹니다.
Meyers가 Template의 대가라 지목한 Andrei Alexandrescu의 저서입니다.


#. Java
(위의 두 언어들 보단 쉽습니다. 하지만 역시 OOP Paradigm의 기반지식이 필요하단 조건이 있죠)

1. The Java Programming Language (3rd Edition)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200105070004
(역시 언어제작자(?) James Gosling의 저서입니다.)

1-1. Java 세상을 덮친 Eclipse[이클립스] : 개정판 ver 3.1
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200508310017
(Java Programming을 하면서 Eclipse를 사용하지 않는다면 Java를 하지 마라는 저의 말이 있습니다. ^^;)

2. Thinking in Java (3rd Edition)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200307110003
(Thinking in Series로 유명한 Bruce Eckel의 명저입니다.)

3. Java 언어로 배우는 디자인 패턴 입문
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200203130012
(일본 사람이 쓴 책인데, Design Pattern을 비교적 쉽게 잘 설명했습니다.)

4. Test Driven Development : By Example
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200412020003
(Eclipse와 XP 방법론의 아버지라 불리는 Kent Beck의 명저입니다. 번역 또한 김창준씨의 감동의 번역으로 극추 ^^;)

5. UML for Java Programmers
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200312170001
(존경하는 Robert C. Martin의 명서입니다. 
Java는 OOP Paradigm의 탄탄한 기초지식이 없으면 조금도 안다고 말할 수 없다. 역시 나의 말 ^^V
DPE와 함께 OOP의 탄탄한 기초를 아주 쉽게 설명하였습니다.)

6. Practical Java
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200207080010#1
(문득 생각나 추가한 책이다. 나에게 디자인패턴에 대한 초석을 깔아주었던 승권선배의 번역서이다. 절판되었단다 ㅡㅡ.)

7. Bitter Java
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200203270007
(쓰디슨 자바로 알려진 유명한 책이죠, 자바로 이렇게 하면 안된다는것을 보여주는 책이죠 ^^;)

8. JAVA NETWORK PROGRAMMING (2ND EDITION)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200005060004
(꽤 좋은 책들을 많이 출판했던 Manning Publications의 책입니다. 지금은 문을 닫았죠 ㅠㅠ
번역은 그리 추천하지 않습니다.)

9. Head First Ejb: Passing the Sun Certified Business Component Developer Exam
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200501100008
(자바의 궁극은 Enterprise Programming이죠 ^^;)

10. Concurrent Programming in Java: Design Principles and Pattern (2nd Edition)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200302170006
(Progamming에서 가장 어려운 이슈중의 하나인 Concurrent Programming을 심도있게 다룬 책입니다.)


#. 언어를 떠나 내공을 위한...
(여기는 이 글에서 언급한 책들과 중복될 수 있음)

1. The Practice of Programming
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200001240005
(C언어의 창시자중 한명인 Brian W. Kernighan의 저서 입니다.)

2. Programming Pearls, 2nd Edition
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200301140012
(김창준씨가 눈물을 흘리며 보아야 한다고 언급한 책 ㅠㅠ)

2-1. 소프트웨어 장인정신
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200212120001
(심심할 때 한번씩 읽어줄 책입니다.)

3. Design Patterns Explained: A New Perspective on Object-Oriented Design
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200305270002
(일명 DPE로 알려진 명저입니다. 김창준씨가 Design Pattern입문서로 극추한 책입니다.)

4. Test Driven Development : By Example
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200412020003
(Eclipse와 XP 방법론의 아버지라 불리는 Kent Beck의 명저입니다. 번역 또한 김창준씨의 감동의 번역으로 극추 ^^;)

5. UML for Java Programmers
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200312170001
(존경하는 Robert C. Martin의 명서입니다. 
Java는 OOP Paradigm의 탄탄한 기초지식이 없으면 조금도 안다고 말할 수 없다. 역시 나의 말 ^^V
DPE와 함께 OOP의 탄탄한 기초를 아주 쉽게 설명하였습니다.)

6. The Pragmatic Programmer: From Journeyman to Master
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200505180011
(존경하는 지인께서 말씀하시길 프로그래머의 동의보감이라할 수 있는 책이라 하였습니다.
역시, 김창준씨의 주옥같은 번역 ㅠㅠ)

7. Refactoring : Improving the Design of Existing Code
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200204020003
(깔끔한 코드를 꿈꾸나요? UML Distilled의 저자인 Martin Fowler의 명저입니다.)

8. Agile Software Development, Principles, Patterns, and Practices
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200402020001
(Robert C. Martin의 명저입니다.)

9. Code Complete (2/E)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200504110013
(정말 유명한 Code Complete의 개정판 이군요)


#. Microsoft Programming
(혹시나, 윈도우 프로그래밍을 하고 싶으신 분들도 있을꺼 같아 몇권 끼워넣습니다. 
C++를 조금보신 후 보시는게 좋을 듯)

1. Windows API 정복
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200104240006
(Windows Programming의 기본서)

2. Programming Windows 5/E
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200411190011
(Charles Petzold의 명저입니다.)

3. Visual C++ 6 완벽가이드 2/E
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200401310006
(일명, 눈까리 책으로 알려진 명저(?)입니다. MFC는 이 한권만 보셔도 충분하실듯)

4. Essential COM
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=199803200007
(Window Programming의 중수로 가기 위해 꼭 넘어야할 산 COM, COM의 창시자 DON BOX의 책입니다.
한때, 번역서가 나온적이 있습니다. 잘 찾아보시길... 참고루 전 소장하고 있습니다. ^^;)


#. 제가 추천하고 싶은 언어와 관련한 책들
(이 책들은 선수가 없습니다. 참고하시길...)

1. Structure and Interpretation of Computer Programs
http://mitpress.mit.edu/sicp/
(MIP에서 만든 Programming Course입니다. 위의 URL에서 전문을 보실 수 있습니다.)

1-1. How to Design Programs
http://www.htdp.org/
(위 책이 너무 어렵다 하여 쉬운버젼으로 나온 책입니다.)

2. THE HASKELL SCHOOL OF EXPRESSION
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200101200004
(Pure Functional Language인 Haskell에 대한 입문서로 유명한 책입니다. Haskell의 대가 Paul Hudak의 저서입니다.)

2-1. Haskell: The Craft of Functional Programming (2/E)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200602010017
(위 책의 대안으로 추천할 수 있는 책입니다.)

3. Programming Ruby: The Pragmatic Programmers' Guide (2/E)
http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200501030004
(일본에서 만든 언어인 Ruby에 대한 책입니다.)

4. YAML
http://www.yaml.org/
(언어라기 보단 훌륭하고 잘 정의된 TEXT의 한 예이다.)
 
 

Posted by 뉴로
,