레이블이 readability인 게시물을 표시합니다. 모든 게시물 표시
레이블이 readability인 게시물을 표시합니다. 모든 게시물 표시

20130903

가독성을 높이는 오류 처리

  유비무환. 이런 저런 책이나 강의에서 수도 없이 들어온 말이지만, 미리 준비한다는게 그리 쉽지만은 않다. 열심히 만든 SW도 여러 오류 상황들에 품질에 대한 혹평을 받게 되기도 한다. 나름 잘 나가는 수많은 SW 엔지니어들이 개발하고 있는 윈도우는 많이 좋아졌다고는 하나 알수 없는 오류를 종종 내뱉곤 한다.
  이러한 현실에 대처하는 초보 개발자의 모습은 크게 두가지중 하나일 것이다. 똑똑한 내가 만들었으니 버그가 없을 거라고 자신하는 멍청한 낙관 주의자이거나, 여기 저기 에러 체크 if문을 남발하는 지저분한 비관주의자 일 것이다. 경험이 풍부한 개발자라면 이러한 상황 둘 다 좋지 않음을 알 것이다. 오류 처리는 반드시 필요하지만 처음에 우리가 구현하고자 했던 로직을 덮어버려 읽을 수 없도록 해서는 안된다.
  자바 문법책 한두권 보고 자바를 할 줄 안다고 하는 개발자들의 코드를 들여다 보면 코드가 읽기 어려운 경우가 종종 있다. 의외로 경력도 제법 되고 회사에서 인정도 받는 사람이 이렇다면 난감할 뿐이다. 추상화가 안되어 있고 긴 함수에 상속을 남발하는 등의 문제가 복합적으로 나타난다. 그러나 이중 제일 난감하면서도 이해시키기 힘든 부분중 하나가 오류 처리이다. if( result == ***) 이런식의 코드로 오염된 코드는 혼돈이 넘실거린다. 그러나 코드를 작성한 사람은 그 부분을 제일 자랑 스러워 할 지도 모르겠다. 나는 경험이 많아서 이렇게 오류 처리를 꼼꼼히 했노라고. 이런 사람은 노력을 통한 자기 발전을 뒤로한채 관성에 의해서만 일해왔을 가능성이 많다.
  이해가 안될 수도 있다. 아래의 예제를 보자.




 위의 함수는 자바코드이지만 전형적인 C언어 스타일이다. 이래선 객체고 상속이고 열심히 해봐야 좋은 코드를 만들기 어렵다. 이런 코드는 아래와 같이 오류 처리의 책임을 담당하는 함수를 만들어서 오류처리와 비즈니스로직을 분리해야 한다.













  어떤가? 읽기 쉽지 아니한다. 물론 위의 코드가 아래 처럼 되려면 많은 refactoring 단계를 거쳐야 할 것이다. 이 과정은 이번 주제에서 벗어남으로 생략하겠다. 궁금하다면 마틴 파울러의 Refactoring 이란 책을 구해서 보길 바란다.
  위의 두 예제에서 이야기하고자 하는 것은 두가지이다. 첫째, 오류코드를 반환하는 함수보다 자바의 예외를 적극 활용하자. 자바라는 언어를 만든 언어 개발자들이 예외를 왜 만들었는지 생각해보자. 우리는 자바가 나오기 전에도 잘 개발해 오지 않았는가. 그러나 오류 코드를 반환하는 코드는 클라이언트에 오류체크를 강요 할 수도 없었고, 여기 저기 지저분한 코드만 양산했을 뿐이다. 대부분의 오류 상황은 로그를 남기거나 오류 메세지를 보여주거나 하는 등의 대처밖에 할 수 없다. DB 접속이 안되거나 파일을 읽을 권한이 없거나 사용하려는 값이 null 인 상황에서 할 수 있는 것은 많이 없다. 그러나 해결할 수 없는 상황을 위한 코드들이 코드의 보수 유지성을 망치도록 두어서는 안된다.
  둘째, 오류처리 자체를 하나의 책임으로 봐야 한다. 오류 처리를 여기저기 붙여 넣기 하고 중첩된 if문을 남발하지 말자. try-catch 문이라도 다르지 않다. try-catch 구문은 트랜잭션과 같이 다루어야 하고 하나의 중요한 기능으로 보아 별도의 함수로 구현해야 한다. try-catch 구문을 읽느라 중요한 비즈니스 로직을 구현한 코드의 가독성을 망쳐서는 안된다. 위 예제에서 보면 예외처리만 별도의 함수로 구성한 것을 볼 수 있다. 물론 처음부터 저런 구조가 아닐 수 도 있다. 그러나 리팩토링을 통해서 저런 코드를 commit하도록 하자.

Checked exception은 가급적 사용하지 말자
  자바 언어를 만든 언어개발자들은 checked exception이란 것을 만들었다. 이 함수는 어떤 예외가 발생할 수 있으니 함수를 호출할 때 예외 처리를 명시적으로 하지 않으면 컴파일도 못하게 하겠다는 것이다. 어떤 함수가 성공하면 0을 반환하고 실패하면 1~100 사이의 에러코드를 반환하는 경우 대부분 결과값이 0인지만 체크한다. 이렇게 못하게 하겠다는 것이다. 아름답지만 실용적이지 못했다. C#, C++ 은 checked exception을 지원하지 않지만 멋진 프로그램을 만드는데 지장이 없다.
  Checked exception은 좋은 의도에서 시작하였지만 너무 비싼 비용때문에 사용하지 않게 되었다. SOLID 법칙 중에 Open Closed Principle(OCP)를 위반하는 비용을 치뤄야 한다. 하나의 변화에 여기저기 수정하는 것은 직관적으로도 보수유지를 어렵게 한다는 것을 알 수 있다. 하위 로직에서 checked exception을 던지면 이를 호출하는 상위 함수와 그 함수들을 호출하는 더 상위의 함수들은 모두 이 exception을 정의 해야 한다. 여기 저기 지저분안 throws 구문이 들어갈 뿐 아니라, 하위에서의 변경이 모든 상위 함수로 전파된다. 다른 계층의 코드들이 강한 결합도를 갖게 되는 것이다.
  물론 checked exception도 그 태생이 가지는 장점이 있다. 중요 라이브러리의 공개 인터페이스에서는 예외를 선언해 주는 것이 좋을 수도 있다. 클라이언트에세 어떤 예외가 발생할 수 있으니 명시적으로 알려주는 것이다. 사용자는 예외를 처리하는 wrapper를 만들 수 있을 것이다. 그러나 일반적인 용도로는 이익보다 비용이 비싸다는 것을 기억하자.

Null을 반환하지도 전달하지도 말자.
  함수를 한줄 호출할 때마다 결과 값이  null인지 체크하는 if문이 들어간 코드는 읽기에 불편하다. Null object pattern은 이런 경우 좋은 해결법일 수 있다. 그러나 Null object pattern은 매우 주의 깊게 코딩하지 않으면 통계가 중요한 어플리케이션에서 오동작 할 수 있다. 그리고 List를 반환하는 함수라면 null대신 빈 List를 반환하도록 하자. 클라이언트에 null체크의 책임을 전가하는 것은 가독성을 해치는 것을 넘어서 실수로 인한 null pointer exception을 유발한다. 이러한 오류는 비교적 잡기 쉬운 버그이지만 고객은 이미 마음이 상한 다음일 수도 있다.
  Null을 매개변수로 넘기는 것도 문제가 있다. 매개변수를 사용하기 전에 null 체크를 하라고 학교에서 배웠을 수도 있다. 사용전에 validation check를 하는 것을 좋을 수도 있다. 그러나 이런 코드가 여기 저기 들어갈 수록 가독성을 멀어진다. 실수도 잦아진다. If문이던 assert문이던 가독성을 해친다는 것은 변치 않는다. 애초에 null을 넘지기 않는다는 정책이 깨끗한 코드를 만드는 큰 발걸음이 될 것이다. 알수 없는 오류의 발생도 적어지니 소프트웨어의 품질도 올라갈 것이다.
  물론 null 검사를 완전히 제거하기는 어렵다. 로버트 마틴과 켄트백은 null pointer exception이 발생한다면 그것은 null 발생에 대한 테스트 코드가 부족해서 라고 말한다. 우리가 어렵지만 TDD를 해야 하는 또 하나의 이유이다.

출처 : http://dsmoon.tistory.com/entry/%EA%B0%80%EB%8F%85%EC%84%B1%EC%9D%84-%EB%86%92%EC%9D%B4%EB%8A%94-%EC%98%A4%EB%A5%98-%EC%B2%98%EB%A6%AC

Articles