2008년 05월 전체 글 목록
2008/05/23 Java에서 Checked Exception은 언제 써야 하는가?
2008/05/21 JDBC에서 Connection, Statement,ResultSet의 close [2]
Amazon에서 예약주문 단계에서 판매상태로 바뀌었습니다.
http://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1212115691&sr=8-1
회사에서 Yes24에서 책을 주문할 수 있는 쿠폰을 주기 때문에 저는 공짜로 보기 위해서 거기서 주문할 수 있을 때까지 기다리고 있는 중입니다.
Joshua Bloch과의 인터뷰를 보니 역시 Generics등 Java5 이후의 주제들에 대해서 내용이 보강되었다고 하네요. 정확히는 21개의 항목과 83페이지가 늘어났다고 합니다. 기대가 되는군요.
Book Excerpt and Interview: Effective Java, Second Edition
더불어 121페이지의 예제코드의 실수도 언급되어 있길래 옮겨봅니다.
지금 인쇄판에 들어간 코드
static Object reduce(List list, Function f, Object initVal) {
Object[] snapshot = list.toArray(); // Locks list internally
Object result = initVal;
for (Object o : list)
result = f.apply(result, o);
return result;
}
수정된 내용
static Object reduce(List list, Function f, Object initVal) {
Object[] snapshot = list.toArray(); // Locks list internally
Object result = initVal;
for (Object o : snapshot)
result = f.apply(result, o);
return result;
}
Joshua Bloch의 말에 따르면 다음에 찍는 인쇄판에서는 수정을 하겠지만 현재 시중에 나가는 판에는 이 오류가 포함이 되어 있다고 합니다.
이 책의 초판에 대해서 저도 워낙 많이 추천과 인용을 하고 다녀서 저를 아시는 분들은 이 책 이야기가 이제 지겹다고도 느끼실지도 모릅니다. 그래도 또 한번 해보겠습니다.
Java 개발자는 크게 두 종류로 나눌 수 있습니다. Effective Java의 내용을 아는 사람과 모르는 사람. 이 책을 읽지 않은 개발자가 Java의 API 설계에 참여했던 Joshua Bloch만큼 Java에 대해서 알거나 그만큼 천재가 아닌 경우를 빼고는 이 책을 읽은 개발자보다 좋은 Java 코드를 짜기는 힘들다고 생각합니다. 이 책을 읽지 않고도 자기가 짠 Java 코드를 공개한 적이 있는 사람이라면 읽고 나서는 당장 그 코드를 수정하고 싶어질 것입니다. 이 책을 읽지 않고도 '나는 괜찮은 Java개발자야' 라고 생각한다면 그것이 자만이나 착각일 가능성이 더 높습니다.
2001년도에 초판이 나온 이후로 Java 개발자의 필독서라고도 불려지고 있지만, 여기저기서 만나는 코드를 보면 아직도 이 책을 안 읽은 사람이 많은 것을 알 수 있습니다. 회사 전체에서 쓰는 프레임웍들에 들어간 코드에도 이 책에서 나오는 지침에 어긋나서 잠재적인 문제점을 가지고 있는 경우를 몇 번이나 봤습니다.
Ruby를 배우는 것도 좋고, 디자인 패턴이나 프레임웍을 공부하는 것도 좋습니다. 아니면 Java Language Spec를 바닥부터 공부하는 것도 중요할 수 있습니다. 하지만 그 이전에, Java를 쓰는 프로젝트에 있는 사람이라면 이 책을 읽는 것이 우선일 것입니다. 리팩토링을 배우는 것도 그 대상언어가 Java라면 마틴파울러의 책보다 이 책이 더 중요하다고 생각합니다. 마틴파울러의 리팩토링은 고민을 하고 프로그래밍을 하는 개발자라면 그 책을 읽지 않아도 이미 실천하고 있는 기법들이 많을 것입니다. 그러나 Effective Java의 교훈들은 책을 안 본 사람이 스스로 깨닳기에 힘든 내용도 많습니다.
사실 저도 최근에 책을 다시보니 처음 볼 때 깨닳지 못했던 것도 많이 배우고 있습니다. 그래서 저도 Effective Java의 교훈을 다 익히고 잘 활용하고 있는 사람이라고 말할 수는 없습니다.
그래도 이 책 덕분에 저는 많은 것을 얻었습니다. 이 책에서 배운 것을 바탕으로 쓴 글 덕분에 많은 분들을 알게 되기도 했으니까요. 널리 알려서 좋은 정보가 있으면 가끔이라도 정리해서 여기저기 올리는 일도 이 책을 읽고난 후부터 하게 되었던 것 같습니다.
# by | 2008/05/30 15:57 | 개발 이야기 | 트랙백 | 덧글(0)
Java 의 Exception 처리는 C++에서 도입되었지만 checked exception은 Java만의 독특한 특징입니다. 아시다시비, 컴파일러가 exception을 꼭 처리해라고 강요하는 것이죠. 이것은 java 이후에 설계된 언어인 C#이나 루비에도 채택되지 않았습니다. 즉 Java 이외의 다른 언어들의 Exception 처리 방식은 Java의 unchecked exception과 동일한 방식입니다.
Java의 초기에 checked Exception의 사용을 권장하던 것에 대해서 지금은 많은 반론이 제기되고 있습니다. 극단적으로 Java언어의 Checked Exception 도입 자체가 실패라고 주장하는 사람도 많습니다. Thinking in Java의 저자인 Bruce Eckel도 그 중 한 사람입니다. Spring framework의 아버지 Rod Johnson도 Checked Exception이 쓰여야 할 때도 있지만 그 것이 과도하게 선호되어 온 것은 지적하고 있습니다.
어쨓든 Exception 부분은 Java로 API 설계와 코딩를 할 때 가장 어려운 부분이라고 느껴집니다. Java 아키텍트와 개발팀의 실력을 측정하는 좋은 방법은 그들이 만든 Exception 처리 코드를 보라는 말까지 있으니까요.
Effective Java 중 Chapter 8 (Item 39~47)
Expert One-on-One J2EE Design and Development 중 Chapter 4 Design Techniques and Coding Standards for J2EE Projects, Exception Handling 부분
Barry Ruzek의 EFFECTIVE JAVA EXCEPTIONS
Jim Cushing Three Rules for Effective Exception Handling
13 Exceptional Exception Handling Techniques
Gunjan Doshi의 Best Practices for Exception Handling
Rob Walling의 Exception Handling에 관한 글 The Two Fundamental, No Frills, Square One Rules of Exception Handling
Alan Griffiths의 Exceptional Java
An Exception Handling Framework for J2EE Applications
Brian Goetz의 글: Java theory and practice: The exceptions debate
Bruce Eckel, Rod Johnson, Joshua Bloch등의 주장을 정리해 놓은 글입니다. Checked Exception이 상세한 구현을 부적절하게 노출함,불안정한 메소드 시그너처,읽기힘든 코드,Exception 삼키기,너무 많은 Exception wrapping의 문제점 있는 것을 나열하고 있습니다. unchecked exception은 Documentation이 더욱 중요하다고 강조하고 있습니다.
Rod Waldhoff의 글 : Java's checked exceptions were a mistake
Bruce Eckel의 견해(Thinking in Java의 저자): Does Java need Checked Exceptions?
Bill Venners(C#의 아키텍트)와 Bruce Eckel의 인터뷰 : The Trouble with Checked Exceptions
이미 많이 알려진 내용이지만, 아직도 문제를 많이 일으키는 주제입니다. 그래서 보다 이 주제를 검색엔진에서 쉽게 찾을 수 있었으면 하는 마음에서 이 글을 정리해봤습니다.
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // <---- !!!
try{
conn = ...<getConnection()>...;
pstmt = conn.prepareStatement("select .....");
rs = pstmt.executeQuery(); // <----- !!!
while(rs.next()){
......
}
} catch(Exception e){
....
} finally {
if ( rs != null ) try{rs.close();}catch(Exception e){}
if ( pstmt != null ) try{pstmt.close();}catch(Exception e){}
if ( conn != null ) try{conn.close();}catch(Exception e){}}
이것이 JDBC API 사용시에 권장되는 코딩방식입니다. 코드는 참조자료에 있는 이원영님의 글에서 인용했습니다.
JDBC 스펙을 찾아보면 Statement가 닫힐 때 ResultSet은 닫히고, Connection이 닫히면 Statement도 닫힌다고 되어 있습니다. 하지만 Staement close 시에 Exception이 발생한다면 이것이 따로 Exception을 catch되지 않고서는 뒤에 Connection을 닫는 코드가 실행되지 않습니다. 그리고 Connection pool에서 얻어온 Connection객체는 connection.close()로 처리하는 것이 pool로의 반환을 의미하는 것이지 실제로 connetion을 close하는 것이 아니기 때문에 Statement까지 닫아준다고 장담할 수 없습니다. ResultSet의 경우도 WAS에도 제공하는 Statement cache 기능 때문에 명시적으로 close해주는 것이 확실한 자원해제를 보장할 수 있습니다.
DBMS에서 "maximum open cursor exceed !" 나 "Limit on number of statements exceeded " 에러를 내고 있다면 위와 같이 코딩했는지 한번 확인해보시기 바랍니다.
각 벤더별 드라이버의 구현이나 WAS의 Connection Pool의 구현등에 따라서 저 정도까지 안 해도 문제가 안 생길 수도 있습니다. 그리고 독립적으로 돌아가는 배치프로그램이나 커넥션풀을 쓰지 않는 경우에는 보다 덜 엄격해도 될 때도 있습니다. 그래도 어떠한 경우에도 안심하고 있을만한 코드는 위와 같은 구조입니다.
javaservice.net에서 이원영님이 처음에 이 문제에 대한 글을 쓰신것이 2000년 9월입니다. 그래서 많은 분들이 알고 계시지만 그래도 정말 반복적으로 만나게 되는 문제입니다. 저의 경험이 편향된지도 모르겠지만, 지금까지 제가 만났던 JDBC AP를 그대로 쓰는 개발팀은 세 팀이였었는데, 모두 이렇게 코딩하지 않을 경우 문제가 생길 가능성이 있다는 것을 모르고 있었습니다. 결국 그 중 한 팀은 시스템 전체를 몇 일동안 매시간마다 재부팅시키게 만들게 했었습니다.
미국의 모 대형항공사의 예약시스템을 3시간동안 멈춘 코드도 위와 같은 방식을 따르지 않았었습니다. finally절이 다음과 같았다고 합니다.
}finally{
if (stmt!=null) stmt.close();
if (conn!=null) conn.close();
}
그 예약 시스템은 이중화된 DB로 구성되어 있었고, 그 DB들은 가상IP주소로 어플리케이션과 연결되어 있었습니다. 정기 점검을 위해 DB중 하나를 수동 fail-over 시키는 순간 내려간 DB의 JDBC연결에서 나온 statement객체의 close문장은 Exception을 일으켰습니다. 이 문장은 별도로 catch 되지 않았기 때문에 그 다음의 conn.close()는 실행되지 않았습니다. 결국 이 때문에 반환되지 않은 Connection 자원들로 인해 리소스 풀은 곧 바닥이 났습니다. 그 후에 새로 Connection을 얻고자 하는 다른 프로그램들은 블록되어서 전체 시스템을 멈추었습니다.
아마도 JDBC API를 쓰는 곳에는 언제나 생길 수 있는 문제일 것입니다. 좋은 API는 문서를 안 보고 자연스럽게 써도 사용하기 쉽고 문제를 안 일으키는 것일텐데, JDBC는 제대로 사용하기가 오히려 더 어려운 API입니다. 위의 항공사 사건 같이 전 세계에서 JDBC로 인해 야기된 장애,생산성 저하를 다 따져본다면, 가히 이 API가 인류에게 끼친 해악이 엄청나다는 생각까지도 듭니다. 요즘은 Framework 기반 개발로 JDBC를 직접 안 쓰는 것이 이런 점에서는 다행입니다.
JDBC API에서 대표적으로 지적받는 문제점은 Checked Exception을 남발했다는 것입니다. catch 절에서 아무 것도 하지 않는 것은 바람직하지 않은 코딩이지만 JDBC API에서는 정말 할 것이 없습니다. 그래서 이런 문제점을 알고서 그 후에 나온 JDBC를 활용한 API들, Spring의 JdbcTemplet, Hibernate의 Query 인터페이스, JPA의 Query 인터페이스, JDO의 Query 인터페이스에서는 Checked Exception인 SqlException을 볼 수 없게 설계되어 있습니다.
그리고 JDBC에서는 접속에러, 쿼리에러, 제약조건 에러 등 다양한 원인으로 생기는 Exception을 SqlException 1개로 다 때우는 문제도 있습니다. Spring에서는 이것을 더 섬세하게 구분한 Exception들을 정의를 하고 있습니다. DataAccessException의 하위 클래스를 보면 CleanupFailureDataAccessException, DataIntegrityViolationException, DataRetrievalFailureException 등이 보입니다.
Java의 Checked Exception 처리 문제에 관한 글은 따로 정리했습니다.
Release It 릴리스 잇 : 성공적인 출시를 위한 소프트웨어 설계와 배치 (마이클 나이가드 저/신승환,정태중 역, 위키북스)
2장 사례연구 : 항공사를 정지시킨 예외(Exception) 사건
Javaservice.net에 이원영님이 올린 글
같은 내용으로 zdnet에 올라온 글
◀ 이전 페이지 다음 페이지 ▶