Go언어 에러처리

프로그래밍 2016. 11. 2. 10:11 Posted by 정직한 UnHa Kim

Go언어를 쓰면서 느끼는 가장 큰 불편은 '에러처리'이다.

try-catch 같은 예외처리 기능이 없으며,  if문(!)에서 에러발생 여부를 확인해야 한다.


 

if 반환값, 에러 := F실행할_함수(인수1, 인수2....); 에러 != nil {

<여기에서 에러처리....>

}


이 방식은 소스코드가 지저분해지는 문제점이 있다.

1. 실행할_함수()는 if문에 파묻혀서 잘 보이지 않는다.

2. 소스코드가 지저분해진다. 소스코드 중간중간에 if문이 끼어들어서 흐름을 끊어놓는다.


그럼에도 불구하고 장점도 있다.

1. 예상하지 못한 동작이 발생하는 것이 예방된다. -> 오작동이 치명적인 경우에는 장점이 된다.

2. 각 에러마다 정확한 개별 대응이 쉽다.


이런 장점에도 불구하고, if문을 사용하는 에러처리 패턴이 불편하게 느껴지는 것은 사실이다.

defer, recover, panic을 조합하면 예외처리 기능처럼 에러를 뭉뚱그려서 한 번에 처리할 수 있다.


try-catch문은 예외가 발생하면 실행이 중단되고, catch문 내용이 실행된다.

Go언어에서는 패닉이 발생하면 실행이 중단되고, defer문으로 등록한 함수가 실행된다.


try문에서 예외가 발생해도 catch문에서 적절한 처리를 해준다면 프로그램 실행이 중단되지 않고 계속 실행된다.

패닉이 발생해도 defer문에 등록한 함수는 실행되며, 그 부분에서 recover함수를 호출한다면, 프프로그램 실행이 중단되지 않고 계속 실행된다.

실행 흐름은 '에러발생->패닉발생->defer->recover->에러처리' 로 이루어진다.

 

func F함수_정의(인수A, 인수B,...) {

defer func() {    // 3함수 실행이 종료될 때 자동으로 실행된다. 패닉이 발생해도 실행된다.

if r := recover(); r != nil {    // 4recover함수를 실행해서 패닉된 경우 복구한다.

<여기에서 뭉뚱그려서 에러처리>

}

}()


.....

반환값, 에러 := F실행할_함수(인수1, 인수2....)

if 에러 != nil {    // 1 : 에러가 발생하면 패닉을 발생시켜서 함수의 실행을 종료하도록 한다.

panic(에러)    // 2  :  패닉이 발생하면 실행이 중단되고,  defer로 함수로 넘어간다.

}

....

}

 

언뜻 보면 소스코드가 오히려 더 복잡해진 느낌이다.

그러나, 다음 2개의 도우미 함수를 사용해서 반복되는 부분을 제거할 수 있게 된다.


 

func F에러2패닉(에러 error) {

if 에러 != nil {    // 에러가 발생하면 패닉 되도록 한다.

panic(에러)

}

}


func F패닉_처리(함수 func(r interface{}) {

if r := recover(); r != nil {    // 패닉이 발생한 경우 패닉을 복구하고 지정된 함수를 실행한다.

함수(r)

}

}


도우미 함수를 이용해서 소스코드를 간단하게 수정하면 다음처럼 된다.

func F함수_정의(인수A, 인수B,...) {

defer F패닉_처리(func(r interface{}) {

<여기에서 뭉뚱그려서 에러처리>

})


.....

반환값1, 에러 := F실행할_함수_1(인수1, 인수2....)

F에러2패닉(에러)    // 에러는 패닉으로 전환되고, defer에 등록된 패닉처리 함수가 실행됨.

 

// 여기까지만 보면 크게 좋은 점을 모르겠으나, 

// 처리해야 할 에러가 많아지면 이러한 방식의 장점이 드러난다.

....

반환값2, 에러 := F실행할_함수_2(인수1, 인수2....)

F에러2패닉(에러)

....

반환값3, 에러 := F실행할_함수_3(인수1, 인수2....)

F에러2패닉(에러)}

...

}

 

타 언어의 try-catch 방식의 예외처리문보아야 여전히 불편하긴 하지만,

if문을 사용해서 모든 에러를 일일이 확인하는 기존의 방식보다는 훨씬 간편하다.

 

Go언어는 예외처리도 if문으로 대체할 정도로 최소한의 기능만을 가지고 있는 대신,

언어가 간단해서 배우기 쉽고, 다른 사람의 소스코드를 읽기도 쉬우며,

컴파일 속도가 빨라서 코딩 및 디버깅 생산성도 높고,

소스코드를 자동으로 정리해 주는 기능도 존재한다.

 

Go언어를 처음 접하면 컴파일 속도를 빼면 어느 것 하나 특출난 것 없이,

이것 저것 부족한 기능이 불편하게 느껴지지만,

쓰면 쓸 수록 

- 꼭 필요한 것은 다 있는 기능성.

- 높은 개발 생산성

- 빠른 실행속도

3가지 요소가 골고루 균형 잡혀있는 것에 감탄하게 된다.

댓글을 달아 주세요