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 善 곽중선