2016.02.17 13:15

소프트웨어 역사의 주요 인물


소프트웨어 발전에 기여하신 분들을 출생 연도 순으로 정리했습니다. 기술 혁신, 알고리즘 개발 등 학문 및 공학 발전에 이바지 한 분들로 한정한 것입니다.

 

한글 이름 영문 이름 출생 연도
찰스 베비지 Charles Babbage 1791

에이다 러브레이스

Augusta Ada King 1815
조지 George Boole 1815
폰 노이만 John von Neumann 1903
알론조 처치 Alonzo Church 1903

그레이스 호퍼

Grace Murray Hopper 1906
모클리 John William Mauchly 1907
엘런 튜링 Alan Mathison Turing 1912
J 에커트 J Presper Echert 1919
에드가 코드 Edgar Frank "Ted" Codd 1923
더글러스 엥겔바트 Douglas C. Engelbart 1925
메카시 John McCarthy 1927
마빈 민스키 Marvin Minsky 1927
에츠허르 데이크스트라 Edsger Wybe Dijkstra 1930
찰스 앤터니 리처드 호어 Sir Charles Antony Richard Hoare 1934
니클라우스 비르트 Niklaus Wirth 1934
도널드 커누스 Donald Ervin Knuth 1938
엘런 케이 Alan Curtis Kay 1940
데니스 리치 Dennis MacAlistair Ritchie 1941
브라이언 커니핸 Brian Wilson Kernighan 1942
게리 킬달 Gary Arlen Kildall 1942
톰프슨 Kenneth Lane Thompson 1943
찰스 시모니 Charles Simonyi 1948
비야네_스트롭스트룹 Bjarne Stroustrup 1950
리처드 스톨먼 Richard Matthew Stallman 1953
조이 William Nelson Joy 1954
팀 버너스 리 Sir Timothy John "Tim" Berners-Lee 1955
제임스 고슬링 James Arthur Gosling 1955
조슈아 블로흐 Joshua Bloch 1961
마틴 파울러 Martin Fowler 1963
리누스 토르발스 Linus Benedict Torvalds 1969
로버트 마틴 Robert Cecil Martin



[인물 소개 및 업적]


찰스 베비지


영국의 수학자이자 철학자, 발명가, 기계공학자로서 "프로그램이 가능한 컴퓨터" 개념을 창안했다. 배비지는 기계식 컴퓨터를 최초로 개발한 인물로 평가 받고 있으며, 그의 연구 이후 더욱 복잡한 형태의 컴퓨터들이 등장하게 된다. 배비지는 인간의 수작업에 이한 계산으로 인해 자주 오차가 발생하는 것을 확인하고, 이를 개선하기 위해 기계를 이용한 계산 방법을 고안하려 애썼다. 그의 기계적 컴퓨터는 데이터와 메모리를 분리하고, 명령을 입력할 수 있으며, 입/출력 장치를 분리하는 등 현대적 컴퓨터에 사용되는 기법을 포함하고 있었다.


이다 러브레이스


영국 시인 조지 고든 바이런의 유일한 법적 친자이며, 세계 최초의 프로그래머로 알려져 있다. 에이다는 찰스 배비지의 연구에 대한 좋은 이해자이자 협력자였고, 배비지가 고안한 해석기관을 위한 공동작업을 수행한 것으로 널리 알려져 있다. 배비지의 해석기관에서 처리될 목적으로 작성된 알고리즘이 최초의 컴퓨터 프로그램으로 인정되고 있으며, 해석기관을 단순한 계산기 정도로 생각했던 당대의 과학자들과 달리 훨씬 다양한 목적으로 활용될 가능성에 주목해 현대 컴퓨터의 출현을 예측했다. 프로그래밍 언어에 사용되는 중요한 개념인 루프, GOTO 문, IF 문과 같은 제어문의 개념을 소개했다. 또한 서브루린(subroutine)에 대한 개념을 고안하였다.


조지 불


영국의 수학자, 논리학자이다. 논리 대수인 불 대수(Boolean Algebra)를 창안해, 기호논리학 분야에 큰 업적을 남겼다. 부울 대수는 현대 컴퓨터의 논리 연산 기능의 기본 원리이다.


폰 노이만


현대적 컴퓨터의 구조를 설계한 사람이다. 지금까지 거의 모든 컴퓨터는 폰 노이만이 정립한 아키텍쳐를 따르고 있기 때문에 "폰 노이만 머신"이라고도 부른다. 프로그램 내장 방식, 이진법을 컴퓨터에 도입했으며, 순서도와 서브루티, 몬테카를로법을 최초로 사용했다. 1945년 병합 정렬(merge sort)를 만들었고, 간단한 원칙만으로 스스로 진화하는 복잡한 프로그램을 구상했고 이를 오토마톤이라고 명명했다. 유명한 일화는 제자들이 어셈블리어를 만들 당시에 노발대발 했다는데, 그 이유가 '완벽한 신의 언어가 있는데, 그걸 놔두고 저런 조잡한걸 만들려고 하느냐?'였다.


알론조 처치


알론조 처치는 미국의 수학자이자, 논리학자이다. 전산학의 이론적인 기초를 세운 사람 중의 한 명이다. 1936년 람다 대수에 대한 논문을 썼고, 람다 셈법에 대한 처치의 연구는 리스프(LISP) 계열의 프로그래밍 언어 뿐만 아니라, 일반적인 함수형 언어 전반에 큰 영향을 끼쳤다.


그레이스 호퍼


미국의 프로그래머, 수학 교수이자 해군 제독으로 제대한 여성 군인.1906년 뉴욕에서 태어나 후일 바서대학에서 부교수로 수학을 강의했다. 2차대전 발발 직후, 1943년 미 해군에 입대했고 수학적 재능을 이용해 탄도를 계산하는 일과 최초의 컴퓨터 중 하나인 마크Ⅰ의 프로그램을 개발하는 일을 수행하며, 전쟁 이후에는 최초의 상업용 컴퓨터인 유니박(UNIVAC) 개발팀과 함께 프로그램을 개발하고 최초의 컴파일러를 개발하는데 참여했다. 그 후 해군에 복귀해 코볼(COBOL) 언어와 컴파일러 개발에 참여했고 후일 해군 제독으로 전역했다. 또한, 그는 컴퓨터에서 버그라는 단어를 최초로 사용한 것으로 유명하다. 1946년 하버드대학의 컴퓨터 마크Ⅱ를 사용하던 중 컴퓨터에 고장이 발생했는데 컴퓨터에 나방이 붙어 장애를 일으킨 것을 확인하고, 일지에 고장을 일으킨 벌레를 테이프로 붙인 후, 컴퓨터 버그란 이름을 붙였다


존 모클리


J 프레스퍼 에커트와 함께 최초의 전자 컴퓨터인 애니악을 만든 미국의 물리학자이다. 1943년 미국 전쟁성(지금의 국방부)은 펜실베니아 대학교의 공학 교수였던 모클리를 ENIAC 개발을 위한 프로젝트 총괄 책임자로 임명했다. J. 프레스퍼 에커트와 함께 ENIAC을 제작하였으며 이후 EDVAC, UNIAC 등의 컴퓨터를 설계했다.


엘런 튜링


영국의 수학자, 암호학자, 논리학자이자 컴퓨터 과학의 선구적 인물이다. 이론 컴퓨터 과학과 인공지능 분야에 지대한 공헌을 했기 때문에 "컴퓨터 과학의 아버지"라고 불린다. 튜링 기계는 튜링이 알고리즘을 설명하기 위해 도입한 가상의 기계이다. 이 기계는 한정된 종류의 기호 중 하나를 기록할 수 있는 칸들이 무한히 이어진 띠와 각 칸의 정보를 읽고 수정하는 기계로 이루어져 있다. 그리고 튜링 머신의 상태와 칸에 기록된 기호에 따라 지정된 절차를 수행한다. 튜링 머신이 수행하는 절차는 1. 현재 기계가 위치하는 칸의 기호를 수정 2. 띠의 위치 이동 3. 튜링 머신의 상태 변경 이 있다. 현대적 소프트웨어는 그 기본 원리가 튜링 머신에 기초한다.


J 에커트


존 모클리의 제자로서 ENIAC을 설계 및 개발하는 프로젝트에서 수석 엔지니어로 참여했다.


에드가 코드


관계형 데이터 베이스 이론의 창안자. 미국 미시간대학교에서 컴퓨터과학 박사 학위를 받은 후, IBM 에서 근무하다 "A Relational Model of Data for Large Shared Data Banks"라는 논문을 썼다. 코드의 관계형 모멜에 대한 논문에 크게 감명 받은 래리 앨리슨(Larry Ellison)은 지금의 오라클(ORACLE)로 이름을 바꾼 회사를 설립했다.


더글러스 엥겔바트


더글러스 엥겔바트(Douglas C. Engelbart, 1925년 1월 30일 ~ 2013년 7월 2일, 오리건 주 출생)는 노르웨이/스웨덴계 미국인 발명가이다. 그는 특히 컴퓨터 마우스의 발명자로 유명하다. 또한 그래픽 사용자 인터페이스, 하이퍼텍스트, 네트워크 컴퓨터 등 인간과 컴퓨터 상호 작용 분야의 선구자이다.


존 메카시


존 매카시(John McCarthy, 1927년 9월 4일 - 2011년 10월 24일)는 미국의 전산학자이자 인지과학자이다. 인공지능에 대한 연구 업적을 인정받아 1971년 튜링상을 수상했다. 리스프 프로그래밍 언어를 발명했으며, 1956년에 다트머스 학회에서 처음으로 '인공지능'(Artificial Intelligence)이라는 용어를 창안했다.


마빈 민스키


마빈 리 민스키(Marvin Lee Minsky, 1927년 8월 9일 ~ 2016년 1월 24일)은 인공지능(AI) 분야를 개척한 미국인 과학자이다. MIT의 인공지능 연구소의 공동 설립자이며, AI와 관련된 몇 개의 책의 저자이기도 하다.


에츠허르 데이크스트라


데이크스트라는 전산학이 아직 학문으로 완전하게 정립되지 않았던 시절에 전산학의 여러 분야에 걸쳐 많은 공헌을 했다. 그의 다방면에 걸친 업적은 다음과 같다. 데이크스트라 알고리즘을 개발하여 최단경로 알고리즘에 대한 학문적 연구를 시작했다. GOTO문을 사용하지 말 것을 주장했으며, 그의 주장은 1968년에 그의 논문 "GOTO문의 해로움"(Go To Statement Considered Harmful)에 정리되었다. 세마포어에 대한 연구를 처음으로 시작하였다.


찰스 앤터니 리처드 호어


찰스 앤터니 리처드 호어 경, Kt (Sir Charles Antony Richard Hoare, 1934년 1월 11일 ~ )은 영국의 컴퓨터 과학자이다. 애칭 토니 호어(Tony Hoare)로도 불린다. 가장 널리 쓰이는 정렬 알고리즘의 하나인 퀵 정렬을 고안해낸 것으로 유명하다. 그는 호어 이론, 형식 언어의 한 종류로 병행 프로세스간 통신을 기술하는데 이용되는 커뮤니케이팅 시퀀셜 프로세스(CSP)의 개발, 프로그래밍 언어인 Occam에도 영향을 끼친 것으로 알려져 있다.


니클라우스 비르트


스위스의 컴퓨터 과학자이며, 파스칼을 포함한 다양한 프로그래밍 언어를 설계한 것으로 가장 유명하다. 


도널드 커누스


커누스는 컴퓨터 과학 분야에서 가장 권위있는 책인 《The Art of Computer Programming》의 저자로 가장 널리 알려져 있다. 알고리즘 분석 분야를 실질적으로 창조했으며, 이론 컴퓨터 과학의 여러 분야에서 기초적인 중요한 공헌을 했다. TEX 조판 시스템과 메타폰트 폰트 디자인 시스템을 만들었으며 문학적 프로그래밍 (literate programming)의 개념을 처음으로 주장했다.


엘런 케이


앨런 커티스 케이는 미국의 전산학자이다. 객체 지향 프로그래밍과 사용자 인터페이스 디자인 분야의 선구자로 잘 알려져 있다. 


데니스 리치


켄 톰슨(Ken Thompson) 등과 함께 최초의 유닉스(Unix) 시스템을 개발했고, 1971년 최초의 〈Unix Programmer's Manual〉을 썼다. 또한 C 언어를 개발한 후 브라이언 커니핸과 함께 〈C 프로그래밍 언어〉(The C Programming Language)를 기술했다. 커니핸과 〈C 프로그래밍 언어〉책을 썼기에 커니핸이 C 언어 개발에 참여한 것으로 종종 오해받으나 커니핸의 말에 따르면 자신은 C언어 개발에 참여하지 않았다고 한다. 그는 ALTRAN, B언어, BCPL, Multics 등의 개발에도 영향을 끼친 것으로도 알려져 있다.


브라이언 커니핸


C를 만든 데니스 리치와 함께 최초의 C언어 해설서인 〈C 언어 프로그래밍〉를 써서 널리 알려져 있다. 커니핸은 자신은 C 언어의 탄생에 전혀 기여하지 않았다고 밝혔다. 그는 dirtroff를 비롯한 수많은 유닉스 프로그램을 작성했다. 선 린과 함께 그래프 분할과 외판원 문제를 푸는 유명한 휴리스틱을 개발하였다. 전자는 커니핸-린 알고리즘 (줄여서 KL), 후자는 린-커니핸 알고리즘 (줄여서 LK)이라고 부른다.


게리 킬달


게리 알렌 킬달은 운영 체제 CP/M과 GEM의 개발자이며, 디지털 리서치(Digital Research)의 설립자이다. 윈도와 메뉴로 동작하는 사용자 인터페이스를 갖춘 선점형 멀티태스킹 운영 체제를 도입했다. 최초의 디스크 트랙 버퍼링 체계, 미리 읽기 알고리즘, 파일 디렉터리 캐시와 램 디스크 에뮬레이터의 창조, 1980년대에 바이너리 재컴파일러의 도입, 최초로 마이크로프로세서에 특화된 프로그래밍 언어와 컴파일러 제작 등의 업적을 이루었다.


켄 톰프슨


케니스 레인 톰프슨은 미국의 컴퓨터 프로그래머로, AT&T 벨 연구소에서 유닉스와 플랜 9 운영 체제의 개발을 주도했다. C언어의 모체가 된 B언어를 개발하기도 했다. 2006년부터 구글에서 근무하면서 고 언어의 개발에 참여했다. 그밖에 정규표현식, QED 편집기, UTF-8 인코딩 등의 개발에도 기여했고, 체스 기계 벨의 개발에도 동참했다. 1983년에 유닉스 개발과 관련된 공로로 데니스 리치와 함께 튜링상을 수상했다.


찰스 시모니


헝가리 태생의 미국 소프트웨어 개발자, MS에서 근무하면서 MS Word 와 Excel을 개발했다. "헝가리안 명명법"이라 불리는 코딩 스타일을 창안했다.


비야네_스트롭스트룹


리처드 스톨먼


빌 조이


팀 버너스 리


제임스 고슬링


조슈아 블로흐


마틴 파울러


리누스 토르발스


로버트 마틴



켄트 벡,  조엘 스폴스키, 제프 맷우드, 앤디 루빈, 롭 파이크, 마츠모토 유키히로, 귀도 반 로섬, Robert Donner, Curt Johnson (mine sweeper), Robert sedgewick, GoF, three amigos, 허먼 훌러리스, 레이 오지, 와츠 험프리, 마크 안드레센, 마가렛 해밀턴, 앤더스 해즐스버그, John Vincent Atanasoff, 제프리 리처

Posted by 善 곽중선
2016.01.27 19:56

[문제 제시]

"임의의 문장을 입력 받아 해당 문장에서 한글 단어만 추출하려면 어떻게 해야 할까요?

문장 부호, 공백 문자, 특수 문자 등 한글 이외의 문자를 모두 제외해야 합니다. 

이러한 프로그램을 가장 효율적(빠르거나, 메모리를 적게 쓰거나)으로 동작하게 하려면, 무엇을 고려해야 할까요?"


[프로그램 개발 절차]

위와 같은 문제를 아래의 4단계에 걸쳐 개발하려고 합니다.


분석 > 설계 > 개발 > 성능/기능 테스트


[소프트웨어 개발에서 분석이란? 그리고 어떻게?]

소프트웨어 개발에서 '분석'은 '무엇(what)'을 만들 것인지를 정의(파악)하는 단계입니다. 머리가 좋거나, 지식을 많이 쌓은 사람만이 할 수 있는 것은 아닙니다. 분석이라는 단어부터 어렵게 느껴질 수 있는데, 영어 단어인 analysis의 어원을 살펴봅시다.


analysis는 'ana(up to)'와 'lysis(untie)'가 결합하여 얽히고 뭉쳐 보이지 않던 것을 물러지게(lys) 하면 그 속에 무엇이 있는지'를 알게 됩니다.

출처 - lose 에 대하여


분석 (分析) : 한자로는 '나눌 分', '쪼갤 析' 영어의 어원과 크게 다르지 않습니다. 분석이란, 주어진 과제(혹은 문제)를 좀 더 잘게 쪼개서 문제를 명확히 이해하는 과정입니다. 잘게 쪼개다 보면 미쳐 생각하지 못했던 부분들이 드러나기도 합니다. 그리고 분석 과정에서 새로운 의문점이 드러나기도 합니다. 분석 과정은 문제를 쪼개보고, 의문점이 발생하면 이해를 위해 문제를 다시 검토하거나, 심하면 문제를 재정의합니다. 


개발이나 설계를 하기 전에 분석하는 이유는 "구현"할 수 있는 문제인지를 파악하고, 처음 문제에서 미쳐 드러나지 않은 숨은 위험요소를 찾아내며 구현할 수 없다면 문제를 재정의하거나, 주어진 자원(시간, 비용)으로 풀 수 없다면 전체 계획을 수정하기 위한 작업입니다. 또한, 분석 결과는 설계와 구현하는데 필요한 사양(specification)으로 활용됩니다.


["한글 단어 추출" 문제 분석]

먼저, 주어진 문제를 한 문장씩 나누어 봅니다.


1. 임의의 문장을 입력 받아 해당 문장에서 한글 단어만 추출한다.

2. 문장 부호, 공백 문자, 특수 문자와 한글 이외의 문자를 모두 제외해야 한다.

3. 가장 효율적(빠르거나, 메모리를 적게 쓰거나)으로 동작해야 한다.


다시 쪼갤 수 있다면 쪼개 봅니다. 모호한 것들을 제거해 나갑니다. 새로운 의문점이 드러날 수도 있습니다.


1. 임의의 문장을 입력 받아 해당 문장에서 한글 단어만 추출한다.


: 임의의 문장을 어떻게 입력 받을 것인가? 사람이 직접 입력하는지, 웹 사이트의 주소를 입력 받는지, 아니면 파일을 선택하는지?

: 한글 단어는 정확히 명사를 추출한다는 것인지? 아니면, 문장성분(예를 들어 주어+조사)을 의미하는 것인지?


2. 문장 부호, 공백 문자, 특수 문자 등 한글 이외의 문자를 모두 제외해야 한다.


: 영어, 숫자 문자도 제외하는가?


3. 가장 효율적(빠르거나, 메모리를 적게 쓰거나)으로 동작해야 한다.


: 빠른데 메모리를 많이 쓰거나, 느린데 메모리를 적게 쓴다면 둘 중 어느 쪽이 나은 결과인가?


문제에서 제기되지 않았지만, 다른 의문도 발생할 수 있습니다.


- 입력 텍스트의 다양한 텍스트 인코딩(UTF-8, EUC-KR)을 지원해야 하는가?

- 형태소 분석기를 적용해야 하는가?

- 어떤 언어를 개발해야 하는가?

- 어떤 플랫폼 (웹, PC 어플리케이션, 모바일)에서 동작해야 하는가?

- 처리 결과는 데이터베이스에 저장해야 하는가?


위와 같은 의문점에 대한 답을 구한 후에, 요구사항(세부 문제 항목)을 나열하면 간단한 '요건 분석'을 마쳤다고 할 수 있습니다.


Posted by 善 곽중선
2015.12.29 15:20

객체 지향 기법에 대한, 그럴 것이라고 알려진 혹은 지레짐작하는 오해들

 

  • 그 자체로 좋은 성능을 내는 소프트웨어를 만들 수 있는 기술이 아니다.
    좋은 성능을 내는 소프트웨어 만들고자 하면, 알고리즘과 자료구조 이론을 공부하라.

  • 더 나은 알고리즘(적은 메모리와 CPU 사용)을 위한 기초도 아니다.
    좋은 알고리즘을 작성하는 능력은 논리적 사고와 수학적 문제해결 능력에서 비롯된다.

  • 좀 더 짧은 코드를 작성할 수 있는 기술 조차 아니다.
    더 짧은 코드를 작성하는 것은 남들이 작성한 좋은 코드를 많이 읽어 보고,다양한 유형의 코드를 직접 작성하며 수련해야 한다.

  • 버그를 줄여주는 혹은 버그 발생 확률을 줄여지는 않는가?
    인간은 완벽하지 않다. 다만, 신중한 태도와 지루한 반복 테스트 혹은 다양한 테스트 케이스 작성을 미루지 않는 정신 지구력을 통해 버그를 줄일 수 있다.

  • 복잡한 문제를 쉽게 풀 수 있는 마법은 더욱 더 아니다.
    복잡한 문제를 코드로 잘 풀어내는 능력은 천재적인 능력에서 비롯되는 것보다 많은 코드를 읽어 보고, 다양한 문제를 더 많이 풀어보고, 새로운 해법을 끊임없이 고민하는 노력을 통해 얻어진다.

  • 더 깊은 수준의 지식을 자랑할 수 있는 난이도 높은 기술도 아니다.
    객체지향 기술은 더 이상 소수의 전문가가 숨기고 있는 보물이나, 감추어진 비밀이 아니다. 누구나 인터넷과 서적을 통해 익힐 수 있다. 수많은 가이드와 예제가 나와 있다.

  • 머리가 좋아지는 사고력 훈련 코드 혹은 두뇌 비타민?
    말도 안된다.
    객체지향을 사용하지 않는 프로그램과 더 복잡한 프로그램도 많고, 어떤 객체지향 전문가도 객체지향이 최상의 프로그래밍 기법이라고 말하지 않는다.


객체 지향의 진실


  • 객체지향은 코드를 보다, 단순하고, 이해하기 쉽고, 추가/변경/조합하기 쉽도록 만들기 위한 것이다.
    (그런데, 정작 객체지향을 배운 사람이 더 복잡하게 설계하는 일도 많다. 그래서 오해가 늘었다.)

  • 높은 성능(CPU와 메모리를 적게 사용하는 것)의 소프트웨어는 객체지향 설계의 관심사가 아니다.
    성능이 무엇보다 중요하다면, 비객체지향 언어를 배우거나 찾아보라.

  • 객체지향은 가장 거대한 형태의 소프트웨어를 가장 단순한 코드들의 집합으로 구현하며,각각의 코드 블록(클래스 혹은 인터페이스 그리고 메소드 등)의 형태는 가장 단순한 형태로 유지하려는 노력이다. 
    이를 통해, 복잡함이 통제할 수 없는 수준으로 증가하는 것을 방지하고, 문제가 발생하더라고 원인을 알기 쉬우며, 많은 사람들이 협력하는 프로젝트 내에서 조차 다수가 상호협력하면서 또한 독립적인 개발이 가능하게 만든다는 얼핏 이율배반적인 목표를 이추구하는 것이다.

  • 객체지향의 목표는 기계지향(기계에 친숙한) 코드가 아니라, 인간 지향(사람의 사고 흐름에 가까운)의 코드를 작성하는 것이다.
    그런데, 여기서 함정은 객체지향이 서양 철학과 언어 체계에 근접해 있다는 것이다.
     그러니, 조금 버겁더라도 가급적 코드(혹은 주석)를 영어 문장으로 읽어보는 시도를 해 볼 필요가 있다.

  • 객체지향은 절차 지향의 함정에서 벗어나기 위한 노력이다. 절차 지향으로 코드(혹은 논리)의 흐름을 이해하고, 작성하는 습관은 자연스러울 수 있다. (flow-chart 는 절차지향의 설명하는 가장 직관적인 사례다.)
    절차지향의 문제를 깨닫지 못하는 한, 당신은 제대로 객체지향을 받아들이기 어려울 것이다.

  • 객체지향은 수많은 사례에서 연구, 발견 그리고 제안된 우수한 소프트웨어 설계 기법들을 설계자 뿐만 아니라 코드를 만들어 내는 개발자들이 직접 타이핑하는 순간에 쓸 수 있게끔 하려는 노력이다. 따라서, 객체지향 언어 문법과 코드와 패턴은 성능과는 아무런 상관이 없는 관용어(idiom)로 가득차 있다.


Posted by 善 곽중선
2015.12.28 23:54

※ NoSQL 이란? - 'No! SQL' 이 아니라, 【Not Only SQL】의 약어이다.


  1. 관계형 데이터베이스의 장점과 단점

    * 장점
        - 데이터의 일관성을 보장한다. (transaction, atomicity)
        - 정규화를 전제로 하고 있기 때문에 데이터의 중복 가능성이 상대적으로 적다.
        - SQL 언어를 이용하고, JOIN, LIKE 등 다양한 검색 조건을 이용해 원하는 데이터를 손쉽게 찾을 수 있다.
        - 축적된 경험과 수십년간 검증된 솔루션(제품, out of box)들이 있다.
        - 상대적으로 설치,사용 및 관리가 용이하다.

    * 단점
        - 단시간에 대량의 데이터 입력(수십 GB byte 이상)이 발생할 경우, 느리다. (상대적으로 그렇다)
        - 데이터 구조 혹은 스키마(schema)이 일정(혹은 정적)하고, 변동이 많을 경우, 유지관리가 어렵다.
        - 누적된 데이터 크기가 커질수록 수행 성능이 급격히 낮아진다.
        - 분산, 대용량 시스템을 구축하기 불가능한 것은 아니나, 상대적으로 어렵다.

    1. NoSQL과 RDBMS의 관계

      - NoSQL은 관계형 데이터베이스(RDBMS)를 대체하기 위한 것이 아니다.
        (관계형 데이터베이스가 엄격/정밀하다면, NoSQL은 유연하지만 데이터 구조가 정교하지 않다.)
      - 관계형 데이터베이스는 데이터의 일관성 및 신뢰성이 매우 중요한 비즈니스(금융, 전자상거래 등)에서는 필수적이나,
        대량의 데이터를 고속으로 처리하거나, 비정형 데이터를 처리하는데 적합하지 않다.
      - NoSQL은 대규모/분산 환경에 보다 적합한 형태로 설계되어 있다.
      - 신뢰성을 (약간이나마) 희생할 수 있다면, NoSQL은 보다 적은 하드웨어 비용으로 고성능/고가용성을 달성할 수 있다.
      - RDBMS는 SQL, 정규화 등 표준화된 언어와 기술 표준이 있으나, NoSQL은 제품(오픈 소스 등) 종류가 다양하고,
        각각의 기능/성능/특징이 매우 다양하기 때문에 용도에 맞는 솔루션을 선택하기가 까다롭다.
      - NoSQL은 발전(버전 업) 속도가 빠른 반면, 시장을 주도하는 솔루션 사업자가 명확하지 않다. (Do/Try It Yourself!)

      ▶ NoSQL과 RDBMS는 경쟁 관계가 아니라, 고유의 적합/적용 가능한 데이터/처리 영역이 있다. (일부 겹치는 부분도 있음) ◀

    2. NoSQL을 고려해야 하는 상황

      - 대량의 데이터를 수집/처리해야 할 경우
      - 데이터 구조 혹은 스키마가 일정하지 않을 것이라고 예상되는 경우
      - 보다 적은 비용으로 대용량 / 분산 처리를 하고 싶은 경우
      - 빠른 데이터 접근 속도를 보장 받고 싶은 경우.
      - 데이터의 무결성, 일관성을 최우선 조건으로 고려하지 않아도 되는 상황
      - 그리고, 가장 중요한 것은 직접 설치 및 검증을 수행할 수 있고 다양한 문제에 부딧치는 상황에 외부의 도움(기술지원 등) 없이 스스로 해결할 수 있는 역량과 의지를 가진 경우.

    3. NoSQL 분류[각주:1]

    휘발성 key-value
    스토어

    영속성 key-value 
    스토어

    문서형 데이터

    컬럼형 데이터

     memcached

    Flare 

    MongoDB

    Casandra 

     (Redis)

    (Redis) 

    CouchDB 

    HBase 

     

     

     

    HyperTable



    1. 빅데이터 시대를 위한 NoSQL 핵심 가이드 (로드북 출판사, Tatsuya Sasaki 저, 송은영 편역) 참조 [본문으로]
    Posted by 善 곽중선
    2015.05.11 01:43

    "AlgoSpot DRAWRECT 문제 풀이"에 대한 마지막 코드 예제 입니다. 이번에는 절차지향 방식의 코드를 개선해 XOR 비트 연산자의 원리를 이용해 if 제어문 조차 사용하지 않는 short code를 소개하고자 합니다. XOR 비트 연산자 사용에 대한 아이디어는 이은택님이 제안해 주셨고, 이은택님의 샘플 코드 또한 참고해 보시면 좋겠습니다. XOR 연산자를 활용한 기법을 소개하는 이유는 컴퓨터 하부 구조의 동작 방식 (2진수 기반의 컴퓨터 원리 등)과 수학적 논리(혹은 공식)를 잘 이해할 경우, 더 할 나위 없는 성능을 발휘하는 가장 짧은 코드를 작성할 수 있다는 것을 보여 드리기 위함입니다.


    ▶ 배타적 논리합


    배타적 논리합 (exclusive or)은 수리 논리학에서 주어진 2개의 명제 가운데 1개만 참일 경우를 판단하는 논리 연산입니다. 약칭으로 XOR, EOR, EXOR라고도 씁니다. 연산자는 ⊻ (유니코드: U+22BB)입니다. 혼돈이 되지 않을 경우, XOR, xor ⊕ (유니코드: U+2295), +、≠ 라고도 씁니다. (위키백과 배타적 논리합 참조)


    배타적 논리합의 "진리표"는 아래와 같습니다.


     명제 P

    명제 Q

     P  Q

     참

     참

     거짓 

     참

     거짓 

     참 

     거짓

     참 

     참 

     거짓

     거짓

     거짓


    ▶ XOR (Exclusive OR) 비트 연산


    XOR 연산은 두 값의 각 자릿 수를 비교해, 값이 같으면 0, 다르면 1을 계산하는 연산입니다. XOR 연산은 비트 단위로 이루어집니다.


    0101

    XOR    0011

    -----------

           = 0110

     

    C or C++ 언어에서 XOR 비트 연산자는 ^ (caret) 문자를 사용합니다.


       x = y ^ z;


    ▶ XOR 비트 연산을 이용한 동일 값 제거


    XOR 비트 연산자를 활용하면, 여러 개의 값 중에서 동일한 값들을 제거할 수 있습니다. 예를 들어, 3개의 값이 존재하고 그 중에서 2개의 값이 동일하고 나머지 하나의 값이 다른 경우, XOR 비트 연산 2번을 통해 나머지 하나의 다른 값을 추출할 수 있습니다. 예를 들어, 십진수 12, 7, 7 등 3개의 값을 2번에 걸쳐 XOR 연산을 수행하는 과정과 그 결과는 다음과 같습니다. 연산 순서에 상관없이 하나의 다른 값이 얻게 되는 것을 확인할 수 있습니다.


    ▶ XOR 비트 연산을 short code 예시

    #include <stdio.h>
    #include <stdlib.h>
    
    /* x,y 좌표를 표현하는 점(point) 구조체를 정의한다. */ 
    typedef struct {
       int x;
       int y;
    } point;
     
    
    int main(int argc, char *argv[]) {
    	
    	// 테스트 케이스 반복 횟수 및 좌표 변수 생성 및 초기화 
    	int cnt = 0;
    	point p1 = {0, 0};
    	point p2 = {0, 0};
    	point p3 = {0, 0};
    	point p4 = {0, 0};
    	
    	// 테스트 케이스 반복 횟수 입력. 
    	int testCaseCount;
    	printf("Input test case number : ");
    	scanf("%d", &testCaseCount); 
    	
    	// 입력 받은 테스트 케이스 수만큼 반복 처리... 
    	for(cnt=0; cnt<testCaseCount; cnt++) {
    		
    		// ----- pt, p3, p3 등 3개의 좌표 값 입력 -----
    		printf("Input p1 (x, y) : ");
    		scanf("%d %d", &p1.x, &p1.y);
    		printf("p1.x = %d, p1.y = %d\n", p1.x, p1.y);
    		
    		printf("Input p2 (x, y) : ");
    		scanf("%d %d", &p2.x, &p2.y);
    		printf("p2.x = %d, p2.y = %d\n", p2.x, p2.y);
    		
    		printf("Input p3 (x, y) : ");
    		scanf("%d %d", &p3.x, &p3.y);
    		printf("p3.x = %d, p3.y = %d\n", p3.x, p3.y);
    		
    		// ----- 4번째 좌표 계산 및 출력 ----- 
    
    		// p4.x 좌표 계산 
    		p4.x = p1.x ^ p2.x ^ p3.x;
    		// p4.y 좌표 계산 
    		p4.y = p1.y ^ p2.y ^ p3.y;
    
    		// p4 좌표 출력 
    		printf("\nResult p4.x = %d, p4.y = %d", p4.x, p4.y );
    	}
    	
    	return 0;
    }


    Posted by 善 곽중선
    2015.05.10 03:39

    "AlgoSpot DRAWRECT 문제 풀이"에 대한 2가지 코드를 준비해 봤습니다. 그중에서 두번째로 객체지향적으로 문제를 풀어보는 코드입니다. 객체지향 프로그래밍의 목표는 컴퓨터가 최대한 효율적으로 문제를 해결할 수 있도록 코드를 작성하는 것이 아니라, 인간이 세상을 바라보는 시각에 근접하게끔 코드를 작성하는 것입니다. 따라서, 절차지향적 코드에 비해 코드의 분량이 좀 더 길어지거나, 상대적으로 비효율적으로 느껴질 수 있습니다. 그러나, 하드웨어의 성능 발전, 컴파일러 기술의 향상 등으로 인해 조금 더 길어진 코딩이라고 할지라도 전체적인 성능 상의 차이는 두드러지게 나타나지는 않는 편입니다. (참고 : 절차지향 코드 버전)


    더불어, 객체지향 기법을 적용하는 분야(혹은 도메인)에서는 기계 보다는 인간의 관점을 중시하는 경향이 있습니다. 객체지향 혹은 절차지향 중 어느 한 쪽이 우월한가를 따지는 것은 별 의미가 없습니다. 객체지향과 절차지향은 각각의 장점과 단점을 가지고 있고, 해결해야할 문제가 일상생활(실세계)의 문제에 가까울수록 객체지향 기법으로 설계하고 코딩했을 때 얻을 수 있는 이득이 많습니다. 이점을 염두에 두시고, 이어지는 설명과 구현 절차를 읽으셔야 합니다.  


    ▶ 객체지향 철학 그리고 5대 개념


    문제 풀이에 앞서 객체지향 철학 및 5대 개념을 먼저 읽어보시는 것을 권합니다.



    ▶ UML(Unified Model Language)


    객체지향으로 설계 및 구현할 때는 플로우 챠트가 아니라, 가급적 UML(Unified Modeling Language)을 이용해 설계합니다. (플로우 차트를 절대 사용하지 말아야 한다는 것은 아닙니다. 객체지향 코드 내에서도 논리적인 흐름이 발견되고 논리적인 흐름을 표현하는데는 플로우 차트가 유용합니다.) UML 에서는 다양한 다이어그램을 이용해 소프트웨어의 모델을 설계하는데, 그중에서 유스 케이스(Use Case), 클래스 다이어그램(Class Diagram) 그리고, 시퀀스 다이어그램(Sequence Diagram)을 가장 많이 사용하게 됩니다. "UML: 클래스 다이어그램과 소스코드 매핑" 문서를 읽어보시면 도움이 될 듯 합니다.


    UML 중에서 유스 케이스(Use Case)는 가장 직관적이면서 이해하기 쉽고, 가장 먼저 작성하게 됩니다. 사용자(actor)가 컴퓨터(소프트웨어 혹은 하드웨어)를 이용해 어떤 작업들을 수행하는가? 소프트웨어가 어떤 기능을 제공하는가? 라는 질문에 대해 가장 포괄적이고, 직관적으로 보여주는 다이어그램입니다. 아래 그림을 보시면, 논리적인 흐름이나 기술적인 정보는 아무것도 표현하지 않습니다. 객체지향 설계의 접근 방식의 모토(motto)는 바로 인간의 시선에서부터 시작하자는 것입니다.


    유스 케이스 다이어그램의 목적은 시스템 혹은 소프트웨어에 대한 요약(brief), 개요(outline or overview)를 제공하는 것입니다. 소프트웨어를 구현함에 있어서 가장 핵심적인 기능은 무엇인가? 좀 더 세세한 설계를 진행하기에 앞서 시스템을 최대한 간략히 묘사함으로써 개발자/기획자/설계자 등 프로젝트에 참여하는 모든 사람들이 공통의 목표를 명확히 공유할 수 있도록 하는 것이 목표입니다.


    DRAWRECT를 정의하는 유스 케이스는 매우 단순합니다. 3개의 좌표를 제시하고, 사각형의 4번째 좌표를 계산하는 것입니다. 유스 케이스 다이어그램으로 표현하면 아래와 같습니다.




    ▶ 객체 후보 정하기 


    절차지향 프로그램은 고유한 기능을 수행하는 함수(혹은 서브루틴)들을 프로그래머가 지정한 절차에 따라 연속적으로 실행시켜 결과를 얻는 방식입니다. 공장의 컨베이너 벨트처럼 잘 짜여진 흐름에 따라, 연쇄적으로 하나씩 작업들이 이어가는 것이죠. 따라서, 소프트웨어 개발자 혹은 설계자는 각각의 작업을 마친 후에 다음 작업이 무엇이 실행되어야 하고, 각 단계에서 가공된 데이터를 다음 단계의 함수로 어떻게 전달할 것인가? 동적인 흐름을 하나씩 따져가며 문제를 풀어야 합니다.


    반면에 객체지향 프로그래밍은 객체라는 형태의 부품들을 먼저 정의 혹은 추출합니다. 이것은 사람이 현실 세계를 이해하는 방식에서 비롯된 것입니다. 우리는 움직이는 자동차를 바라볼 때 자동차의 가속, 감속, 회전 등의 동작(behavior)과 자동차 자체의 형태, 무게, 차종 등의 상태 정보(status)를 구분해서 인식하지 않습니다. 그냥 자동차 자체는 동작과 상태를 함께 지니고 있다고 받아들입니다. 이러한 인간의 사고 방식을 따르는 객체지향 프로그램에서 객체라는 요소는 행위(behavior)와 상태(status)를 함께 가지고 있는 소프트웨어 부품(parts, component)입니다. 객체지향 설계에서는 문제를 푸는 절차에 앞서, 해결하고자 하는 문제 자체에 포함된 다양한 객체를 먼저 식별(identify or extract)하고, 각 객체들이 서로 어떻게 연결되고, 함께 상호 작용하는지를 파악합니다.


    DRAWRECT 문제에서 객체(혹은 클래스)로 구분지을 수 있는 후보군은 다음과 같습니다. 후보군이라고 말하는 것은 설계하는 사람의 관점에 따라 객체 혹은 클래스가 아니라고 볼 수도 있다는 말입니다. 정확히 어떤 방식으로 설계해야 하고 어떤 클래스들을 정의해야 한다는 엄격한 기준은 없습니다.


     객체(클래스) 후보

     행위 (behavior)

    상태(status) 

     뷰포인트

     입력 좌표 값의 정상 유무 검증

     최소, 최대 좌표 허용 범위 

     좌표

     X축, Y축 값 저장 및 조회

     X축 및 Y축 좌표 값

     사각형

     p1, p2, p3 등 3개의 좌표 저장

     p4 좌표 계산

     p1, p2, p3 등의 좌표 정보


     

    ▶ 객체 간의 정적 관계 설계 (클래스 다이어그램)


    객체 간의 정적인 관계는 클래스 다이어그램을 이용해 정의합니다. 관계(relation)를 통해 객체 혹은 클래스들이 서로 간에 어떤 의미(역할)을 가지는지를 나타내게 됩니다. 자동차의 부품들이 서로 아무런 상관없이 존재하거나, 독립적으로 동작하는 것이 거의 없는 것처럼 객체지향 프로그램에서도 프로그램의 부품에 해당하는 객체들에 각각의 역할과 의미가 부여되어야 합니다. 클래스 다이어그램을 통해서 각 클래스 간의 상속, 합성, 연관 등의 정적인 관계를 파악합니다. 이러한 관계 부여는 실제 코딩으로 이어지기 때문에 의미 없는 문서화 작업으로 치부해서는 안됩니다.


    - 사각형(Rectangle)은 좌표(Point)를 포함합니다. 이를 소유 관계(has-a relation)라고 합니다.

    - 뷰포인트(Viewpoint)는 좌표(Point)를 검증합니다. 이를 연관(association)이라 합니다.




    ▶ 객체 간의 상호 동작 설계 (시퀀스 다이어그램)


    객체 혹은 클래스들이 함께 동작하는 과정에서 어떤 기능을 호출하는지와 어떤 정보를 주고 받는지를 표현하는 것이 시퀀스 다이어그램입니다. 시퀀스 다이어그램은 기능의 흐름을 표현한다는 점에서 플로우 차트와 유사하나, 논리적인 판단(if 조건 등)을 기술하지 않는다는 점은 플로우 차트와 다릅니다. 앞서 말한 것처럼 객체지향 설계에서는 세밀한 논리적 흐름보다는 큰 얼개(구조)를 표현하는데 집중합니다.




    ▶ 객체지향 코드 작성


    위와 같은 설계를 바탕으로 구현된 코드는 아래와 같습니다.


    [Point.java]
    package algospot.exam.drawrect;
    
    /**
     * 점(point) 클래스.
     * 
     */
    public class Point {
    	// X 축 좌표.
    	private int xCoord;
    	// Y 축 좌표.
    	private int yCoord;
    	
    	/**
    	 * 생성자와 getter 메소드만을 제공하는 이유는 최초 값 설정 후에 잘못 변경되는 것을 막기 위함이다.
    	 * 
    	 * @param xCoord X 좌표
    	 * @param yCoord Y 좌표
    	 */
    	public Point(int xCoord, int yCoord) {
    		this.xCoord = xCoord;
    		this.yCoord = yCoord;
    	}
    	
    	public int getXCoord() {
    		return xCoord;
    	}
    	
    	public int getYCoord() {
    		return yCoord;
    	}
    	
    	public String toString() {
    		return String.format("(x = %d, y = %d)", xCoord, yCoord);
    	}
    }
    
    [Viewport.java]
    package algospot.exam.drawrect;
    
    public class Viewport {
    	private static final int MIN_COORDINATE = 1;
    	private static final int MAX_COORDINATE = 1000;
    
    	public static boolean validatePoint(Point point) {
    		return point.getXCoord() >= MIN_COORDINATE && point.getXCoord() <= MAX_COORDINATE &&
    				point.getYCoord() >= MIN_COORDINATE && point.getYCoord() <= MAX_COORDINATE;
    	}
    }
    
    [Rectangle.java]
    package algospot.exam.drawrect;
    
    /**
     * 직사각형 클래스
     * @author "Sunny Kwak"
     *
     */
    public class Rectangle {
    	private Point p1;
    	private Point p2;
    	private Point p3;
    	
    	public Rectangle(Point p1, Point p2, Point p3) {
    		this.p1 = p1;
    		this.p2 = p2;
    		this.p3 = p3;
    	}
    	
    	/**
    	 * 3개의 사각형 좌표 값을 이용해 마지막 좌표를 계산한다.
    	 * @return
    	 */
    	public Point calculateP4() {
    		int x = 0, y = 0;
    		
    		if(p1.getXCoord() == p2.getXCoord()) {
    			x = p3.getXCoord();
    		} else if(p1.getXCoord() == p3.getXCoord()) {
    			x = p2.getXCoord();
    		} else if(p2.getXCoord() == p3.getXCoord()) {
    			x = p1.getXCoord();
    		}
    		
    		if(p1.getYCoord() == p2.getYCoord()) {
    			y = p3.getYCoord();
    		} else if(p1.getYCoord() == p3.getYCoord()) {
    			y = p2.getYCoord();
    		} else if(p2.getYCoord() == p3.getYCoord()) {
    			y = p1.getYCoord();
    		}
    		
    		return new Point(x, y);
    	}
    }
    
    [AlgoSpotDrawRect.java]
    package algospot.exam.drawrect;
    
    import java.util.Scanner;
    
    /**
     * 직사각형의 3개 좌표를 입력 받아 4번째 좌표를 계산하는 프로그램.
     *  
     * @author "Sunny Kwak"
     */
    public class AlgoSpotDrawRect {
    
    	public static void main(String[] args) {
    
    		Scanner scanner = new Scanner(System.in);
    		
    		// 테스트 케이스 반복 횟수 입력.
    		System.out.print("Input test case number : ");
    		int loopCnt = scanner.nextInt();
    		
    		// 입력 받은 테스트 케이스 수만큼 반복 처리... 
    		for (int cnt = 0; cnt < loopCnt; cnt++) {
    
    			// pt, p3, p3 등 3개의 좌표 값 입력 
    			Point p1 = readPoint(scanner);
    			Point p2 = readPoint(scanner);
    			Point p3 = readPoint(scanner);
    
    			// 직사각형 객체 생성 및 4번째 좌표 계산 
    			Rectangle rectangle = new Rectangle(p1, p2, p3);
    			Point p4 = rectangle.calculateP4();
    			
    			// 정상적으로 계산된 경우, 4번째 좌표 출력 
    			System.out.printf("%d %d\n", p4.getXCoord(), p4.getYCoord());
    		}
    
    		scanner.close();
    	}
    
    	/*
    	 * x, y 좌표 입력 및 정상 좌표 유무 검사.
    	 * 정상 좌표인 경우, Point 객체를 생성한 후 반환.
    	 */
    	private static Point readPoint(Scanner scanner) {
    		System.out.print("Input p1 (x, y) : ");
    		int xCoord = scanner.nextInt();
    		int yCoord = scanner.nextInt();
    		Point point = new Point(xCoord, yCoord);
    
    		if (Viewport.validatePoint(point)) {
    			return point;
    		} else {
    			throw new IllegalArgumentException("Invalide coordinate : " + point);
    		}
    	}
    
    }
    
    


    Posted by 善 곽중선
    2015.05.09 19:29

    "AlgoSpot DRAWRECT 문제 풀이"에 대한 2가지 코드를 준비해 봤습니다. 그중에서 첫번째로 절차지향적으로 문제를 풀어보는 코드입니다. 알고리즘 자체를 코드로 변환하는 방법에 대해서 익숙하지 않거나, 사람이 인식할 수 있는 코드를 작성하는 방법을 잘 모르시는 분들을 위해 준비한 것입니다.


    컴퓨터가 이해하는 코드는 어느 바보나 다 짤 수 있다. 훌륭한 프로그래머는 사람이 이해할 수 있는 코드를 짠다.

    - 마틴 파울러 : Martin Fowler (리팩토링 저자).


    ▶ 주 플로우 챠트 작성 (Draw main flow chart)


    앞서 알고리즘 문제 풀이에서 기술한 흐름을 순서도(flow chart)로 작성해 봅니다. 논리 전개에 익숙하지 않은 분들은 가급적 바로 코딩에 뛰어들지 마시고, 귀찮더라고 문제를 풀 때마다 플로우 차트를 그리는 연습을 해야 합니다. 그리고 가급적이면, 파워포인트 혹은 플로우 챠트 그리는 도구를 사용하지 말고, 직접 종이에 그려 보는 것을 권장합니다. 그래야 좀 더 논리적인 전개에 집중할 수 있습니다. 플로우 차트를 도구 없이도 머리 속에서 그릴 수 있게 되면, 그 다음에는 종이나 파워포인트 없이 바로 코딩을 시작해도 됩니다.




    ▶ 서브루틴 플로우 챠트 작성 (Draw subroutine flow chart)


    주된 흐름을 플로우 차트로 작성한 후에는 서브루틴(subroutine)에 대한 플로우 차트를 작성합니다. 플로우 차트 하나에 모든 논리(logic0을 담을 수 없습니다. 달리 말해서, 하나의 플로우 차트에 단계가 10~20개 정도가 좋은 것이고 그 보다 많은 단계를 하나의 플로우 차트에 그려 넣는다는 것은 플로우 차트를 쪼갤 필요가 있다는 얘기가 됩니다. 문제를 한 눈에 알아보고, 전체 흐름을 파악할 수 있을 정도가 되어야 버그(bug)를 최대한 방지할 수 있습니다. 또한 플로우 차트를 쪼개는 과정에서 부수적으로 서브루틴(subroutine) 혹은 함수(function)를 도출해낼 수 있다는 점도 플로우 차트를 권장하는 이유입니다.




    ▶ 절차적 코드 작성


    절차적 프로그래밍 패러다임을 적용하기 위해 C 언어로 작성하였습니다. 아래 코드를 보시면, 여러 개의 좌표를 저장하기 위해 구조체(struct)를 사용하신 것을 확인할 수 있습니다. 논리(logic)도 중요하지만, 프로그래밍 언어들에서 제공하는 구조체 등을 활용하면 보다 사람이 이해하기 좋은 코드 (직관적이고, 가독성 높은)를 작성하실 수 있습니다.


    #include <stdio.h>
    #include <stdlib.h>
    
    /* x,y 좌표를 표현하는 점(point) 구조체를 정의한다. */ 
    typedef struct {
       int x;
       int y;
    } point;
    
    int main(int argc, char *argv[]) {
    	
    	// 테스트 케이스 반복 횟수 및 좌표 변수 생성 및 초기화 
    	int cnt = 0;
    	point p1 = {0, 0};
    	point p2 = {0, 0};
    	point p3 = {0, 0};
    	point p4 = {0, 0};
    	
    	// 테스트 케이스 반복 횟수 입력. 
    	int testCaseCount;
    	printf("Input test case number : ");
    	scanf("%d", &testCaseCount); 
    	
    	// 입력 받은 테스트 케이스 수만큼 반복 처리... 
    	for(cnt=0; cnt<testCaseCount; cnt++) {
    		
    		// pt, p3, p3 등 3개의 좌표 값 입력 
    		printf("Input p1 (x, y) : ");
    		scanf("%d %d", &p1.x, &p1.y);
    		printf("p1.x = %d, p1.y = %d\n", p1.x, p1.y);
    		
    		printf("Input p2 (x, y) : ");
    		scanf("%d %d", &p2.x, &p2.y);
    		printf("p2.x = %d, p2.y = %d\n", p2.x, p2.y);
    		
    		printf("Input p3 (x, y) : ");
    		scanf("%d %d", &p3.x, &p3.y);
    		printf("p3.x = %d, p3.y = %d\n", p3.x, p3.y);
    		
    		// 4번째 좌표 계산  (p1 ~ p3는 입력, p4 는 출력 용도의 인자[argument]) 
    		int returnCode = calculateP4(&p1, &p2, &p3, &p4);
    		
    		// 정상적으로 계산된 경우, 네번째 좌표 출력 
    		if(returnCode == 0) {
    			printf("Result p4.x = %d, p4.y = %d", p4.x, p4.y );
    		} 
    		// 잘못된 입력 좌표가 존재할 경우, 에러 메시지 출력 및 프로그램 종료. 
    		else {
    			printf("Error : Invalid coordinate");
    			return 1;
    		}
    		
    	}
    
    	return 0;
    }
    
    /*
     * p1, p2, p3 등 3개의 좌표 값을 입력받아, p4 좌표 계산.
     *
     * 만일, 잘못된 자표가 입력된 경우 -1 반환, 정상적으로 좌표를 계산한 경우 0 반환. 
     */
    int calculateP4(point *p1, point *p2, point *p3, point *p4) {
    
    	// p4.x 좌표 계산 
    	if(p1->x == p2->x) {
    		p4->x = p3->x;
    	} else if(p1->x == p3->x) {
    		p4->x = p2->x;
    	} else if(p2->x == p3->x) {
    		p4->x = p1->x;
    	} else {
    		return -1;
    	}
    	
    	// p4.y 좌표 계산 
    	if(p1->y == p2->y) {
    		p4->y = p3->y;
    	} else if(p1->y == p3->y) {
    		p4->y = p2->y;
    	} else if(p2->y == p3->y) {
    		p4->y = p1->y;
    	} else {
    		return -1;
    	}
    	
    	return 0;
    }
    


    ▶ 실행 결과


    위와 같은 코드의 실행 결과(예시)는 아래와 같습니다.


    Input test case number : 1

    Input p1 (x, y) : 10 30

    p1.x = 10, p1.y = 30

    Input p2 (x, y) : 45 30

    p2.x = 45, p2.y = 30

    Input p3 (x, y) : 10 65

    p3.x = 10, p3.y = 65


    Result p4.x = 45, p4.y = 65


    Posted by 善 곽중선
    2015.05.09 13:43

    JBUG(JBoss User Group) 스터디 모임에서 "기업 통합 패턴 Enterprise Integration Patterns"을 번역하신 차정호 님의 강의를 듣는 귀한 기회를 얻었다.


     


    강의 초반에 '알고리즘의 시대에서 패턴의 시대'로 변모하는 것이 아닌가 라는 말씀을 하신다. 소프트웨어 개발에 있어서 알고리즘(algorithm)와 패턴(pattern)은 모두 중요하다고 생각한다. 어느 한 쪽이 더 중요하다 하기도 어렵고, 두 가지 기술의 적용 범위 혹은 특징이 상이하지 않은가 라는 생각에 강의를 들으면서 짧은 노트를 적어 봤다. 거듭 말하지만 두 가지 기술은 반대되는 개념은 아니다, 다만 몇 가지 면에서 차이를 비교해볼 수 있다.


    1.문제 풀이를 위한 공식(formula)인가? 아니면, 문제를 풀기 위한 행동 방식인가?


    "알고리즘"은 개별적인 '문제(사례)를 해결하기 위한 논리와 기법'이다. 즉, 알고리즘은 문제 자체를 해결하는데 쓰인다. 알고리즘은 그 자체가 가치를 지닌다. 완성된 논리이며, 코드로 씌어졌을 때 즉각적으로 유용하다. "패턴"은 빈번하거나, 다양한 문제들을 해결하는 과정에서 발견된 문제 풀이에 도움을 주는'유용한 사례들'이다. 패턴은 소프트웨어 개발자 간의 의사 소통을 돕고, 문제 해결을 위한 실마리가 된다. 패턴은 문제 자체를 해결해주지는 않는다. 패턴을 현실 세계에 비유하자면 레고 블록과 같다. 개별 레고 블럭(패턴)은 가치가 없다. 그것들을 연결했을 가치가 생겨난다.


    2. 상대적으로 좁거나 반대로 넓은 적용 범위


    대다수의 "알고리즘"은 특정 문제를 해결하기 위해 고안된 것이다. 다양한 문제가 있다면, 그만큼 많은 알고리즘이 만들어진다. 하나의 문제에 대해서도 복수의 알고리즘이 있을 수 있다. 반면에 "패턴"의 적용 범위는 넓다. 특정 문제 자체를 위한 해결책이 아니라, 본래 다양한 사례를 조사하고 그 과정에서 반복적으로 쓰이는 기법을 문장의 숙어(idiom)처럼 골라낸 것이다. 요약하면, 알고리즘은 좁은(narrow) 범위를 해결하는데 사용되고, 패턴은 넓은(wide) 범위의 문제들을 해결할 때 유용하다. (어느 한 쪽이 우월하다고 해석해서는 안된다.)


    3. 관습적이거나, 개성적이거나...


    "알고리즘"이나 "패턴"이나 모두 문제 해결을 위한 도구이다. 그러나, "패턴"은 보다 관습적이다. 누군가 패턴을 제안하거나, 발견할 수 있지만 그것이 과연 유용한 것인지는 많은 개발자들의 선호도(?) 라거나, 지지 여부에 따라 가치가 달라진다. 반면에 알고리즘은 알고리즘을 고안한 사람의 개성을 뚜렷히 드러낸다. 또한 그 성능과 가치는 (대게) 객관적으로 조사 가능하다. 각각의 패턴을 속도라거나, 자원 사용량 등으로 비교할 수는 없는 노릇이다.


    4. 논리적이거나, 직관적이거나..


    알고리즘은 수학적으로 증명 가능해야 한다. 주어진 입력에 대해 정확한 출력 값을 내놓는다는 증거(혹은 테스트)를 거친다. 하지만, 패턴은 나름 인간적이다. 증명을 거치지 않는다, 오히려 아름다운지 여부를 판단한다. 알고리즘 또한 아름다울 수 있다. 수학적 혹은 코드의 아름다움은 정교할 뿐만 아니라 간결한 형태를 통해 완벽함, 경이로움을 느끼는 것이리라. 하지만, 패턴에서 느끼는 아름다움은 정교함 보다는 단순함, 그리고 완벽함 보다는 복잡한 세상에서 찾아낸 보편성에 대한 감탄이라고 표현할 수 있다.

    Posted by 善 곽중선
    2015.05.07 15:17

    初志一貫 - 처음에 세운 뜻을 끝까지 밀고 나감.

    늘 똑같은 일상을 반복하는 것이야 말로 가장 어려운 것이다. 그저, 지금 할 수 있는 것을 한다. 당장 잡을 수 없을 것 같은 꿈에 목말라 하지 않고, 그저 한 걸음 한 걸음 나아갈 뿐이다.

    지난 날에 못한 것들, 지금 할 수 없는 것들이 안타까울지라도 지금 할 수 있는 것들을 한다. 흔들리는 마음도 자연스러운 것이나, 다잡을 줄 아는 노력도 함께 어울려야 오래 간다.

    The show must go on...


    Posted by 善 곽중선
    2015.05.07 15:16

    수학은 순수 수학(pure)나 응용수학(applied)나 모두 data를 이해하고, logic을 짜는데 더할 나위 없는 도움이 된다고 생각하고 있지만, 실제 '하드웨어'와 '컴파일러'를 이해하기 위해 컴퓨터공학에 대한 공부가 필요하죠. '수학적인 논리(logic)와 공식(formula)를 '코드'로 파싱하는 방법론에 대해서는 계속해서 공부해야 하는 성질이 아닐까 생각되어요.

    프로그래밍을 크게 두 가지 성질로 나누면,

    1. 논리(logic)를 생각하는 방법 (알고리즘 혹은 수학적 사고)

    2. 하드웨어/운영체제를 포함한 플랫폼에 대한 이해

    이렇게 보고 있는데, 수학은 1)번에 대해서는 무엇보다도 큰 힘이 됩니다. 2)번은 수학을 베이스로 깔고, 따로 공부하셔도 되는 부분이구요.

    일단 수학(혹은 논리적 사고)을 베이스로 깔고, 프로그래밍을 열심히 공부하시면, 논리(logic)를 나누는 방법, 데이터를 분류한 뒤, 각각에 대해 합리적으로 착안하는 방법 등에 대해 눈을 뜨기 쉬울 겁니다. 또한, 하드웨어의 원리, 운영체제의 동작방식, 네트워크 이론 등 컴퓨터 공학과 커리큘럼에 포함된 다양한 과목(혹은 분야)에 대한 지식을 함께 공부하셔야 프로그래밍을 잘 할 수 있습니다.


    Posted by 善 곽중선