함수를 만들때 에러처리를 어떻게 하는게 좋은지 조언부탁드립니다.

superkkt의 이미지

항상 함수를 만들때 아래와같이 만들고 있습니다.

1. 함수 내에서 시스템콜이 에러를 반환하거나 기타 해당 함수가 에러를 반환해야할 상황에선 그자리에서 바로 에러를 출력(stdout이나 파일로..)하고 음수를 리턴합니다.

2. 위 함수를 호출했던 함수는 리턴값이 음수이면 바로 음수를 리턴합니다. 에러처리를 1번에서 다했기때문에 아무것도 하지않고 그냥 음수만 리턴합니다.

3. 이런식으로 main()까지 올라간후 음수가 리턴되었으면 exit(EXIT_FAILURE)로 종료합니다.

아! 그리고 위 상황은 치명적인 에러가 발생했을때입니다.

별 생각없이 이런식으로 만들고 있다가 표준 함수들의 구조에 대해서 가만히 생각해보니 함수자체가 에러를 처리하는 경우가 없더군요. 다들 음수를 리턴하면서 errno를 셋팅한다던가.. 그래서 해당 함수를 호출한 함수가 리턴값을 보고 에러처리를 하는식으로 만들어져 있는데요.

이걸보니 제가 만드는 방식이 아주 잘못된 방식이라는 생각이 드는데.. 다른 분들은 어떠신지 조언좀 부탁드립니다. 함수를 만들때 사용하는 방식이라던지 아니면 어떤 룰 같은게 있다면 좀 알려주세요~

chadr의 이미지

어떤 함수에서 에러가 발생했을때 해당 에러를 어떻게든 코드상에서 알아낼수만 있다면 어떤 방법을 사용하든 상관은 없다고 생각합니다..

그렇기 때문에 질문자께서 올리신 1,2,3번의 방법은 조금 미비한것 같네요..

저는 가능하면 에러라는 표시를 리턴하고 errorno에 세팅하는 방법을 선호합니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

superkkt의 이미지

제가 계속 함수의 구조때문에 머리 아파한 이유가 어떤 함수에서 치명적인 에러가 발생했을 경우 그자리에서 바로 exit하지 않고 에러를 리턴하면서 상위 함수들이 할당한 자원을 해제한 후 종료할 수 있도록 만들기 위해서였습니다.

main()
{
	fd = open(..);
	ptr = malloc(..);

	if(func_a() < 0) {
		close(fd);
		free(ptr);
		exit(1);
	}
}

func_a()
{
	ptr = malloc(..);

	if(func_b() < 0) {
		free(ptr);
		return -1;
	}
}

func_b()
{
	if(write(..) < 0) {
		log_error("error");
		return -1;
	}
}

그런데 함수의 호출관계가 복잡해지면서부터 코드가 깔끔하지 못하고 뭔가 구조적이지못한 느낌을 주더군요. 그래서 그냥 fatal error가 발생하면 에러 리턴하지않고 그자리에서 바로 종료하도록 바꿨습니다. 어차피 프로그램이 종료하면 OS가 알아서 자원을 해제해주니까 그냥 그렇게 하는게 머리가 덜 아프더군요.

func_b()
{
	if(write(..) < 0) {
		log_error("error");
		exit(1);
	}
}

======================
BLOG : http://superkkt.com

moonzoo의 이미지

제가 보기엔 최초에 설계한 구조가 더 괜찮아 보입니다.

당장은 func_b()에서 바로 exit하는 것이 편해보이겠지만

유지의 측면에서 보자면, func_b()에서 exit로 인해

프로그램 종료가 일어난다는 사실을 기억해야 하는 단점이있습니다.

복잡함을 줄여보고 싶다면

차라리 main에서 exit하면서 자원해제에 신경을 안쓰는 것이

속편하지 않을까요. 다음과 같이요.

if(func_a() < 0) exit(1);

======================

doldori의 이미지

superkkt wrote:
제가 계속 함수의 구조때문에 머리 아파한 이유가 어떤 함수에서 치명적인 에러가 발생했을 경우 그자리에서 바로 exit하지 않고 에러를 리턴하면서 상위 함수들이 할당한 자원을 해제한 후 종료할 수 있도록 만들기 위해서였습니다.
그런데 함수의 호출관계가 복잡해지면서부터 코드가 깔끔하지 못하고 뭔가 구조적이지못한 느낌을 주더군요.

C로는 어쩔 수 없는 문제입니다. 언어 차원에서 이를 해결할 만한 별다른 지원이 없으니까요.
뭔가 새로운 해결책을 찾으신다면 다른 언어를 고려해야겠죠.
익명 사용자의 이미지

개인적으로, C에 try/catch가 없는 것이 굉장히 불만입니다. 이게 있으면 많은 것들이 훨씬 수월해 질텐데 말입니다.

superkkt의 이미지

아... 남겨주신 글들을 읽어보니 또 갈등이 생깁니다. 최초 설계로 다시 바꿔야하나... 말아야하나...

유명한 오픈소스 프로그램들은 어떻게 하나 궁금해서 proftpd를 일단 살펴봤는데요... fatal error 발생하면 그자리에서 바로 exit(1) 하더군요..

moonzoo wrote:
유지의 측면에서 보자면, func_b()에서 exit로 인해 프로그램 종료가 일어난다는 사실을 기억해야 하는 단점이있습니다.

프로그램이 끝나는 지점을 하나만 만드는게 좋은 방법이라는 얘기를 전에도 여기서 본적이 있습니다. 그런데 사실 왜 그게 좋은 방법인지 와닿지가 않습니다. func_b()에서 프로그램 종료가 일어날 수 있다는 사실을 "그냥 여기서도 종료가 될 수 있구나.." 이렇게 생각하고 넘어가는데요..

지금은 만드는 프로그램이 덩치가 작아서 그런것일수도 있겠지만.. 곰곰히 생각을 해봐도 나가는 문이 여러개인게 왜 문제가 되는지 잘 모르겠네요. 그냥 여기서도 끝날수있고 저기서도 끝날수있고.. 그렇게 만들어져있구나.. 아직 초보라 이렇게만 생각이 듭니다.

또 에러 발생시 main()까지 리턴해서 종료시키도록 만들기위해 코드가 어수선(?)해 보이는게 좋은 방법일까 의문이 들기도 하구요..

아~~ 이걸로 머리 아파하지 말아야겠다고 다짐했는데.. 또 고민을 해봐야겠네요..

======================
BLOG : http://superkkt.com

cinsk의 이미지

어떤 기능을 수행하는 함수가 error 처리까지 다 하게 작성하는 것은 항상 좋다고 할 수 없습니다. 보통은 기능을 수행하는 함수에서 error가 났다는 정도만 알리게 하고, 이 함수를 호출한 상위 함수에서 error를 처리하게 하는 것이 좋습니다. (왜냐하면, error를 처리할 user interface가 상황에 따라 달라지게 때문입니다.)

무조건 error를 만나면 나몰라라하고 exit(1)를 하는 것도 항상 좋다고 할 수 없습니다. 한 번 실행되고 바로 끝나는 류의 utility라면 상관없겠지만, 장기간 동작해야 하는 daemon type이라든가, embedded system에 들어가서 안정적으로 동작해야 될 프로그램일 경우, exit(1)를 부를 수 없는 상황이 많습니다.

프로그램 구조가 복잡해져서, function call depth가 깊고, 빨리 상단으로 복귀해야 할 경우, setjmp()/longjmp()가 유용합니다. (사실 toy software가 아닐 경우, sigsetjmp()/siglongjmp()가 더 자주 쓰입니다.)

C++에 있는 try/catch도 위 함수들을 활용해서, macro로 흉내내는 것도 가능합니다.

아주 드문 경우이긴 하지만, setjmp()/longjmp()를 쓰기 곤란한 경우도 있습니다. 이 경우, 특별한 해결책이 있는 것은 아니지만, 모든 함수에 공통적인 인자를 제공하고, 그 인자 값에 따라서 자동으로 함수 호출을 끝내는 방법도 있습니다.

예를 들면, 특정 함수들은 struct foo *를 첫번째 인자로 받게 설계한 후:

struct foo {
  int errno;
  ...
}

모든 함수 첫 부분에서 foo->errno가 0이 아닐 경우 return하게 합니다.

void bar(struct foo *f, ...)
{
  if (f->errno)
    return;
  /* ... */
}

물론 이런 방법이 꼭 좋다고 할수는 없지만, 봐 줄 수 있는? 상황이 있기도 합니다. 이 경우 각 함수의 return type에 따라서 if (f->errno) .... 를 macro로 등록시켜두고 쓰는 것이 좋습니다. 예를 들면:

#define FOO_ERR_RET(foo, err, ret)     do {                                \
                                          (foo)->error = err;               \
                                          return (ret);                     \
                                        } while (0)

#define FOO_ERR_GOTO(foo, err, label)  do {                                \
                                          (foo)->error = err;               \
                                          goto label;                       \
                                        } while (0)

#define FOO_ERR_STMT(foo, err, stmt)  do {                                \
                                          (foo)->error = err;              \
                                          do {                             \
                                            stmt;                          \
                                          } while (0);                     \
                                        } while (0)
ssehoony의 이미지

fatal error 이 어떤 경우는 말하는지 모르겠지만
저의 경우 금용권 서버를 만들기 때문에 segment fault 나 bus error 같은게 아니라면 절대 스스로 종료하지 않습니다.
에러 처리는 공용 라이브러리에서는 가급적 피하는 편입니다.

에러 로그는 superkkt님의 1번 방식을 사용합니다.
에러로그를 파일로 남기고 함수는 에러값을 반환하지요.

seg. falult 같은게 발생해서 죽는다면, 관리자에게 알리고 프로세스는 재구동합니다.
(별도의 모니터링툴이 이 역할을 자동으로 수행하죠. 개발이 아닌 운영중에 이렇게 죽는경우는 99.999% 없지만 0.001% 의 만약의 경우는 대비해 이렇게 해두는 거지요.)

프로세스가 정상작동하는지 여부를 확인하기 위해 데몬은 로그를 많이 남기는데, 그러다 보니 너무 로그양이 많습니다.
이 방식이 역시 경험적으로 유비/보수/관리에 최고( :?: )였습니다.
하지만 너무 로그가 많으면 없는 것과 다름이 없지요.
그래서 로그 남기는 함수는 몇단계 나누어서 DEBUG 가 define 되어 있을 때만 찍는 로그, 일반 정보 로그, 에러로그 등 몇개 나누어서 기록을 하는데 특히 에러로그의 경우는 별도의 에러로그 기록 파일을 둬서 에러로그 전용 파일에도 기록을 하도록 하는 방식을 사용했습니다.
전체 소스 코드중 에러 처리 코드가 일반 코드 보다 많을 듯 하네요.

그런데 다음과 같은 문제가 발생하더군요.
데몬이 다른 데몬으로 접속을 하는데 접속이 될 수도 있고, 안될 수도 있고 하는데 접속이 안되는 사항이 에러가 아닌 구조인데도, 네트워크 라이브러리에서는 connection fail 로그를 남깁니다.
그냥 한번 접속 시도하고 그만 두는게 아니고 접속이 될때까지 일정 간격으로 계속 시도하는 정상사항에서도 계속 에러로그가 남는 그런 문제가 있더군요.
이런 특수한 경우에만 함수에 로그 기록 여부를 결정하는 추가 인자를 둬서 기본값은 로그를 남기는 것으로 하고, 남기지 않는게 좋을 때는 임의로 남기지 않는게 가능하도록 했습니다.

그리고 또 로그의 종류(일반, 에러, 디버그 등등) 안시 코드를 이용해 컬러를 입혀서 눈에 잘 들어오게 하는 컬러로그 와 vi 등으로 보기 좋게 안시코드가 제거된 일반 로그 로 구분해서 남김니다. 컬러로그 역시 DEBUG 가 define 가 되어 있을 때만 처리가 되도록 되어 있어서 개발시에만 이용하도록 하고있죠.
그래서 데몬이 mydaemon 이라고 한다면, 로그는 mydaemon.log , mydaemon.color , all_error.log 이렇게 3개의 로그가 생성되는데, 하나의 솔루션에 대한 여러개의 데몬의 에러로그는 모두 all_error.log 에 기록이 되므로 에러 발생 여부를 확인하기 위해 각 데몬을 로그를 확인하는게 아니고 all_error.log 만 확인하면 되도록 했습니다.

그리고 assert 함수 사용을 많이 했는데, assert 는 abort 시그널을 던지기 때문에 gdb 로 작동중이면 어디의 assert 에서 걸렸는지 알 수 있지만, 그냥 데몬으로 작동중에 걸리면 어디의 assert 를 통과하지 못한건지 알 수가 없더군요. 그래서 myassert 라는 것을 만들에서, myassert 를 통과하지 못했을 때 해당 파일명, 라인넘버, 함수명을 로그에 남기도록 했습니다.
(assert 는 개인적으로 강추입니다. 이 녀석을 소스코드에 남발하니, 디버깅 시간이 많이 단축되더군요. 물론, assert 를 처음 사용하면 어디에서 assert 를 사용하고 어디에서 if 를 사용해야 할지 판단하는데 고민을 좀 하지요. "assert를 서버에서 사용하는건 문제가 있다."라고 하는 분들도 있을 정도니깐요.)

-----------------------------------------------------------------------------------

글을 나름대로 길게 썼네요. 하하하 :D
에러핸들링과 로그 기록 방식은 저도 여전히 연구하고 개선하고 하는 부분이라, 하고 싶은 말이 많았나 봅니다.
다른 경험 많은 분들의 이야기도 듣고 싶네요.

spacelee의 이미지

저도 관심있는 주제였는데 토론이 되서 반갑네요. ㅎㅎ

저도 함수내에서 exit를 부르는 것은 반대입니다.
전체적인 함수 구성이 모듈화,계층화 원칙을 지킨다면
함수 내에서 exit를 부르는 것은 전체 처리 플로우를 결정해버리는 것이
되버리니깐 모듈화가 깨지는 것으로 봐도 무방하지 않을까 생각됩니다.

즉 모듈화의 장점을 유지하기가 어렵죠.
따라서, SW가 커지면 커질수록 재사용이나 유연한 확장성 같은
모듈화의 장점을 고스란히 가져가기가 어려울듯 싶습니다.
위엣분들 말씀대로 데먼 같은 경우 더더욱 그럴 수는 없구요.

cinsk님 말씀대로 함수는 성공했는지,실패했는지 여부만 알려주고
처리 플로우에 대한 선택은 콜하는 주체에서 선택하게 하는게
모듈화라는 원칙하에서 맞지 않을까 싶습니다.

저같은 경우 에러 처리는
success,error,info,warn 등의 수평레벨과
normal,verbose,high,extrem의 수직레벨을 나누어서
각 로그들을 두 개의 적절한 조합으로 선택하고
수직레벨은 컨피그에서 선택하여
필요한 로그 이상만 로그하는 방식으로 구현했습니다.
즉 컨피그에서 verbose라고 되어 있으면 normal,verbose만 찍는 방식입니다.

제가 만드는 SW는 고객에게 제공되는 패키지이기 때문에
위 로그 레벨은 고객이 참조하는 로그들이고,
추가로 수평레벨에 개발자용 로그를 추가했습니다.(debug 모드)
이 모드 역시 컨피그에서 on/off로 선택하게 하여
고객이 문제가 생겼다고 리포트할 경우는
debug 모드를 온 시키고 모니터링 하도록 했습니다.
(물론 그럴경우 로그는 과다)

그리고, 고객들이 눈에 띄게 해서 저희쪽으로 리포트해야되는 로그들만
ERR로그로 찍고 나머지는 info나 warn으로 찍었습니다.
그리고 서후니님 말씀처럼 저도 connection fail 같은 경우는 처음에 error로그로 찍었었는데, 고객들 클레임이 자주 들어오더군요.
그런 경우 대부분 error이 아닌데...
따라서, memory short, file full, app logic error 같은 경우만 error로 찍고,
connection fail 같은 경우는 모두 info로 처리했습니다.

그리고 connection 함수를 부르는 놈이 connection fail 에러 상황에 대한
serious 여부 판단을 해서 고객이 인지해야 하는 경우는
그 함수 상위에서 다시 error로그를 다시 잘 설명해서 찍어주는 방식으로 만들었습니다.

그런데, 저도 몇년동안 그렇게 만들어 오기는 했지만,
그런데 함수 자체에 로그가 있는 방식에 대해서
그대로 좋은 것인지 아니면 c standard library처럼
함수 내부는 로그가 없이 errno 같은 형태로 에러 상태만 전달해주는
방식이 맞는지 항상 좀 의문점을 가졌었습니다.

물론 라이브러리의 사용 범위가 한정 패키지에만 쓰이는 것이 아니라
좀 더 넒은 범위의 SW들에서 공유가 되어야 한다면 로그를 쓰지 않고
errno 형태의 에러 전달방식을 쓰는 것이 맞겠지만,
한정 SW라면 로그를 쓰는 것 자체가 문제가 될것인지에 대해서 많이 고민을 하고 있습니다.

모든 라이브러리에 로그를 썼다가 고생한 적이
file io 관련 라이브러리에도 에러 상황에 로그를 썼는데
그 경우에 로그->file io->에러 상황 로그->file io 이런 식으로
루프를 도는 경우가 생겨서 고생한 적이 있습니다.
따라서 로그용 file io(내부적으로 로그 없음)랑
일반 사용용 file io 라이브러리를 구분해서 만들어 놓고 사용하고 있습니다.

서후니님 말씀처럼 저도 일반 로그랑 에러 로그 파일의 구분에 대해서는
고민하고 있었는데, 컬러 로그까지 만드신다니, 좋은 것을 배웠습니다.^^

그런데 저희같은 패키지용 SW에서 로그에 대한 궁극적인 고민의 방식은
결국 고객의 입장에서 편하고, 쉽게 이해하도록 하는 것이 첫번째고,
그 다음은 개발자가 문제를 잘 추적할 수 있도록 만드는게 두번째 기준인 것 같더군요.

두서없이 주저리주저리 써봤습니다.^^;;

권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -

나는오리의 이미지

저도 cinsk님과 같은 생각입니다.
함수의 기능은 최소화 하는게 가장 좋다고 봅니다.

그리고 글을 읽다보니 궁금한게 생기는데요.

superkkt wrote:
어떤 함수에서 치명적인 에러가 발생했을 경우 그자리에서 바로 exit하지 않고 에러를 리턴하면서 상위 함수들이 할당한 자원을 해제한 후 종료할 수 있도록 만들기 위해서였습니다.
프로세스가 비정상 종료되면 OS에서 해제해주지 않나요?
spacelee의 이미지

욕심많은오리 wrote:
저도 cinsk님과 같은 생각입니다.
함수의 기능은 최소화 하는게 가장 좋다고 봅니다.

그리고 글을 읽다보니 궁금한게 생기는데요.

superkkt wrote:
어떤 함수에서 치명적인 에러가 발생했을 경우 그자리에서 바로 exit하지 않고 에러를 리턴하면서 상위 함수들이 할당한 자원을 해제한 후 종료할 수 있도록 만들기 위해서였습니다.
프로세스가 비정상 종료되면 OS에서 해제해주지 않나요?

메모리같은 리소스는 기본적으로 OS에서 해제해주기는 하지만,
어떤 resource는 해제해주지 않는 경우도 있었습니다.
전 솔라리스에서 프로세스가 죽을때 posix semaphore lock을 해제해주지 않아서 고생한 적이 있었습니다.
솔라리스는 man -s 2 exit에서 프로세스가 죽을때
OS가 어떤 일을 하는지 상세히 설명을 해놓았습니다.
리눅스는 그런 내용은 잘 못찾겠더군요.

어찌됐든 기본적으로 OS는 확실히 믿지 말고 프로그래밍하는
습관을 들이는 것이 좋지 않을까 싶습니다.

권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -

IsExist의 이미지

호출되는 함수를 만드는 입장에서는 그걸 사용하는 쪽에 선택권을 부여할수 있는 오류를 리턴하는 방식이 좋아 보입니다.

그리고 함수 내에서 이루어진 리소스 할당은 그 함수를 빠져 나가기 전에 해제하는 방식으로 사용하는것도 좋은 방식입니다. 라이브러리 수준의 리소스 할당이라면 그 라이브러리 수준에서 리소스 해제를 지원해야 겠지요.

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

ssehoony의 이미지

흐.... 이건 주제에 어긋나지만...

spacelee wrote:
전 솔라리스에서 프로세스가 죽을때 posix semaphore lock을 해제해주지 않아서 고생한 적이 있었습니다.

위에건 원래 세마포어의 작동 원리입니다.
프로세스가 죽어도 unlock 안되는게 정상입니다.
(저도 처음에 놀랬습니다.)
하지만, 별도의 옵션 셋팅으로 프로세스가 죽으면 초기 상태로 가도록 할 수 있습니다.

semop 의 man 페이지를 보면

Quote:
If an operation specifies SEM_UNDO, it will be automatically undone when the process terminates.

라는게 있습니다.

공유메모리를 생성한 프로세스가 죽어도 공유메모리가 남아 있는 것과 비슷한 느낌이지요.(이 사실을 처음 알았을 때도 역시~ 놀랬습니다. ^^)

아! 그리고 쎄후니 라고 읽어 주세요 ^^;

spacelee의 이미지

ssehoony wrote:
흐.... 이건 주제에 어긋나지만...

spacelee wrote:
전 솔라리스에서 프로세스가 죽을때 posix semaphore lock을 해제해주지 않아서 고생한 적이 있었습니다.

위에건 원래 세마포어의 작동 원리입니다.
프로세스가 죽어도 unlock 안되는게 정상이죠. (아니 꼭 그래야 합니다. 세마포어는 프로세스간 lock 을 하기 위한거니깐요.)
하지만, 별도의 옵션 셋팅으로 프로세스가 죽으면 초기 상태로 가도록 할 수 있습니다.

semop 의 man 페이지를 보면

Quote:
If an operation specifies SEM_UNDO, it will be automatically undone when the process terminates.

라는게 있습니다.

아! 그리고 쎄후니 라고 읽어 주세요 ^^;

약간의 부연 설명...^^;;

세마포어의 동작이 그렇게 되야 하는 것은 맞지만,
소스가 방대한 데먼이 예상치 못하게 죽는다는 가정을 안할 수가 없습니다.
만약 그럴 경우 unlock이 안되면 다른 데먼들의 연속적인
동작이 보장이 안되거나, 그 데먼이 다시 뜨더라도 문제가 생길
소지가 있기 때문에..
그런 가정하에서라면 세마포어가 프로세스가 죽을때 자동적으로 풀어지는 것이 application 입장에서는 맞을것 같더라구요.

그런데, sem_init 함수등을 쓰는 posix semaphore 쪽에서는 그 옵션이 지원이 안되는데, system v 계열의 semaphore(semop 등등)에서는 그 옵션이 지원이 되어서,

posix를 쓰다 semop 함수등을 쓰는 system V 계열의 세마포어로 구조를 바꿨습니다. 저는 개인적으로 이 부분에서 posix 표준이 실패했다고 보거든요.
OS system call에서는 기능원칙 상은 맞지만, 프로세스 죽을때 어떤식으로 처리할 지에 대한 부분에서는 system V 처럼 그런 부분을 옵션으로 기능 지원해줘야 할 것 같구요.
사실 세마포어를 쓰는 대부분의 application들은 프로세스 죽을때
unlock이 되는 형태를 더 많이 쓰지 않을까 싶습니다.^^

권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -

superkkt의 이미지

다시 설계를 바꿨습니다. 모듈화의 장점을 살리기위해 함수는 에러 발생시 직접 에러를 처리하지 않고 errno 셋팅하는걸로 바꿨습니다.

이렇게 작업을 하고 있는데... 근데 이렇게하니까 main함수가 모든 에러를 다 처리하네요. :cry: 메인 함수가 호출하는 덩치가 큰 함수들은 직접 에러를 처리하도록 만들어도 괜찮을것 같은데 일단은 이 함수들도 에러처리를 안하고 모두 main 함수가 하도록 했습니다.

어차피 지금은 공부할려고 프로그램 만드는 중이니 이렇게 만들어놓고 계속 프로그램 확장을 해보면서 안좋은점이 발견되면 그때가서 다시 생각을 해봐야겠습니다. :twisted:

======================
BLOG : http://superkkt.com

spacelee의 이미지

superkkt wrote:
다시 설계를 바꿨습니다. 모듈화의 장점을 살리기위해 함수는 에러 발생시 직접 에러를 처리하지 않고 errno 셋팅하는걸로 바꿨습니다.

이렇게 작업을 하고 있는데... 근데 이렇게하니까 main함수가 모든 에러를 다 처리하네요. :cry: 메인 함수가 호출하는 덩치가 큰 함수들은 직접 에러를 처리하도록 만들어도 괜찮을것 같은데 일단은 이 함수들도 에러처리를 안하고 모두 main 함수가 하도록 했습니다.

어차피 지금은 공부할려고 프로그램 만드는 중이니 이렇게 만들어놓고 계속 프로그램 확장을 해보면서 안좋은점이 발견되면 그때가서 다시 생각을 해봐야겠습니다. :twisted:

모듈화가 중요하긴 하지만..^^;;
거꾸로 함수들의 모듈화에 원리적으로 집착하시지 않는 것도
중요하다고 생각합니다.

함수들을 만들 때 앞으로 재사용될 것 같아 보이는 함수,기능들은
철저히 모듈화 원칙을 따르는 것이 중요합니다.

하지만, 항상 그런 함수들만 있는 것이 아니라
전체 소스 라인이 길 경우 가독성을 좋게 해주기 위해 쓰이는
단발적인 함수들도 있습니다.
그런 함수들이라면 굳이 모듈화 원칙을 안지켜도 되지 않을까 싶습니다. (대신 가독성이 더 나빠지거나 하지는 않아야겠죠.)
함수들의 성격이 천차만별이기 때문에 근본적인 원리를 이해한다면 적절하게 원칙을 적용하시는게 중요할 듯 싶습니다.

바둑 격언 중에 '정석은 배우면 잊어버려라' 라는 말이 있습니다.
규칙과 원칙은 배우되,
그 원리를 이해하고 살려 적용하는게 중요하지,
규칙과 원칙 자체에 원리적인 집착은 하지 않는게 중요하다고 생각합니다.

소프트웨어 개발할 때도 '균형감각'이 중요하다고 생각합니다.

권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -

superkkt의 이미지

spacelee wrote:
superkkt wrote:
다시 설계를 바꿨습니다. 모듈화의 장점을 살리기위해 함수는 에러 발생시 직접 에러를 처리하지 않고 errno 셋팅하는걸로 바꿨습니다.

이렇게 작업을 하고 있는데... 근데 이렇게하니까 main함수가 모든 에러를 다 처리하네요. :cry: 메인 함수가 호출하는 덩치가 큰 함수들은 직접 에러를 처리하도록 만들어도 괜찮을것 같은데 일단은 이 함수들도 에러처리를 안하고 모두 main 함수가 하도록 했습니다.

어차피 지금은 공부할려고 프로그램 만드는 중이니 이렇게 만들어놓고 계속 프로그램 확장을 해보면서 안좋은점이 발견되면 그때가서 다시 생각을 해봐야겠습니다. :twisted:

모듈화가 중요하긴 하지만..^^;;
거꾸로 함수들의 모듈화에 원리적으로 집착하시지 않는 것도
중요하다고 생각합니다.

으흠.. 지금 제 상황에 딱 맞는 충고를 해주신것 같습니다. 안그래도 너무 에러핸들링에 변태적(?)으로 집착하고 있는게 아닌가하는 걱정도 듭니다. 하루종일 앉아서 코딩하는 시간보다 어떻게 에러 핸들링을 하고 어떻게 함수 모듈화를 시킬까하는 생각을 더 오래하고 있으니.. 지금 뭐가 잘못되도 한참 잘못된것 같습니다. :(

======================
BLOG : http://superkkt.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.