[Spring] UserDao분리 실습으로 알아본 리팩토링과 메소드 추출
- Language/Spring
- 2018. 6. 16.
Dao의 분리 이유
개발자가 객체를 설계할 떄 가장 염두에 둬야 할 사항은 바로 미래의 변화를 어떻게 대비할 것인가 이다. 왜냐하면 오브젝트에 대한 설계와 이를 구현한 코드가 변하기 때문이다. 만약 2명의 개발자에게 동일한 기능 변경을 요청했다고 하자. 그런데 한 명은 단 몇줄의 코드만 수정하고 다른 개발자는 5시간이 걸렸다. 어떻게 변경이 일어날 때 필요한 작업을 최소화할까? 그것은 분리와 확장을 고려한 설계가 있었기 때문이다.
변화가 한 번에 한 가지 관심에 집중돼서 일어난다면, 우리가 준비해야 할 일은 한가지 관심이 한 군데에 집중되게 하는 것이다. 즉 관심이 있는 것끼리는 모으고, 관심이 다른 것은 따로 떨어져 있게 하는 것이다.
프로그래밍의 기초 개념중에 관심사의 분리(Separation of Concerns)라는 게 있다. 이를 객체지향에 적용해보면, 관심이 같은 것끼리는 하나의 객체 안으로 또는 친한 객체로 모이게 하고, 관심이 다른 것은 가능한 한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것이라고 생각할 수 있다.
모든 것을 뭉뚱그려서 한데 모으는 편이 처음엔 쉽고 편하다. 그런데 언젠가는 그 뭉쳐있는 여러 종류의 관심사를 적절하게 구분하고 따로 분리하는 작업을 해줘야 할 때가 온다. 관심사가 같은 것끼리 모으고 다른 것은 분리해줌으로써 같은 관심에 효과적으로 집중할 수 있게 만들어주는 것이다.
UserDao의 관심사항
import user.domain.User; public class UserDao { public void add(User user) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection("jdbc:mysql://localhost/toby_spring", "root", "asdf"); PreparedStatement ps = con.prepareStatement("insert into users(id, name, password) value(?,?,?)"); ps.setString(1, user.getId()); ps.setString(2, user.getName()); ps.setString(3, user.getPassword()); ps.execute(); ps.close(); con.close(); } public User get(String id) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection("jdbc:mysql://localhost/toby_spring", "root", "asdf"); PreparedStatement ps = con.prepareStatement("select * from users where id = ?"); ps.setString(1, id); ResultSet rs = ps.executeQuery(); rs.next(); User user = new User(); user.setId(rs.getString("id")); user.setName(rs.getString("name")); user.setPassword(rs.getString("password")); rs.close(); ps.close(); con.close(); return user; } } | cs |
UserDao의 구현된 메소드를 살펴보자. 자세히 들여다보면 add() 메소드 하나에서 적어도 세 가지 관심사항을 발견할 수 있다.
1. DB와 연결을 위한 커넥션과 그와 관련된것
2. 사용자 등록을 위해 DB에 보낼 SQL 문장을 담을 Statement만들고 실행하는 것
3. Statement와 Connection 오브젝트를 닫아줘서 소중한 공유 리소스를 시스템에 돌려주는것
여기서 가장 문제가 되는것은 첫째 관심사인 DB연결을 위한 Connection 오브젝트를 가져 오는 부분이다. get() 과 add()메소드에 중복되기 때문이다. 앞으로 계속해서 DAO 메소드를 만들것인데 만들 때마다 중복된 코드를 넣어주는 것은 나중에 변경이 일어날 때 엄청난 고통을 일으키는 원인이 된다.
중복코드의 메소드 추출
가장 먼저 할 일은 커넥션을 가져오는 중복된 코드를 분리하는 것이다. 중복된 DB 연결 코드를 getConnection()이라는 이름의 독립적인 메소드를 만들어주자. 이렇게 분리하여 getConnection() 메소드를 호출해서 DB 커넥션을 가져오게 만든다.
public class UserDao { private static Connection getConnection() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection("jdbc:mysql://localhost/toby_spring", "root", "asdf"); return con; } public void add(User user) throws SQLException, ClassNotFoundException { Connection con = UserDao.getConnection(); PreparedStatement ps = con.prepareStatement("insert into users(id, name, password) value(?,?,?)"); ps.setString(1, user.getId()); ps.setString(2, user.getName()); ps.setString(3, user.getPassword()); ps.execute(); ps.close(); con.close(); } public User get(String id) throws SQLException, ClassNotFoundException { Connection con = UserDao.getConnection(); PreparedStatement ps = con.prepareStatement("select * from users where id = ?"); ps.setString(1, id); ResultSet rs = ps.executeQuery(); rs.next(); User user = new User(); user.setId(rs.getString("id")); user.setName(rs.getString("name")); user.setPassword(rs.getString("password")); rs.close(); ps.close(); con.close(); return user; } public static void main(String[] args) throws ClassNotFoundException, SQLException { UserDao dao = new UserDao(); User user = new User(); user.setId("kang5"); user.setName("현수"); user.setPassword("1234"); dao.add(user); System.out.println(user.getId() + "등록 성공"); User user2 = dao.get(user.getId()); System.out.println(user2.getName()); } } | cs |
커넥션을 분리해 줌으로써 앞으로 드라이버 클래스와 URL이 바뀌거나, 로그인 정보가 변경돼도 앞으로는 getConnection() 이라는 한 메소드의 코드만 수정하면된다.
이런식으로 기능이 추가되거나 바뀐 것은 없지만 UserDao는 이전보다 훨씬 깔끔해졌고 미래의 변화에 좀 더 손쉽게 대응할 수 있는 코드가 됐다. 이런 작업을 리팩토링(refactoring)이라고 한다. 또한 위에서 getConnection()이라고 하는 공통의 기능을 담당하는 메소드로 중복된 코드를 뽑아내는 것을 리택토링에서는 메소드 추출(extract method)기법 이라고 부른다.
이일민, 『토비의 스프링 3』, 에이콘
'Language > Spring' 카테고리의 다른 글
[SpringBoot] 스프링부트 Gradle 프로젝트 빌드하고(jar파일 생성) 실행하는법 (0) | 2021.11.11 |
---|---|
[Spring] 스프링 부트의 라이브러리 의존관계와 View 환경 (0) | 2021.11.10 |
[Spring]스프링 부트 사이트를 이용해 스프링 프로젝트(Gradle) 생성하는법, IntelliJ 셋팅 방법 (0) | 2021.11.08 |
[Spring] 스프링의 이해를 위한 스프링 정의 풀이해석 (0) | 2019.08.27 |
[Spring] 스프링이란? 스프링을 이해하기 위한 방법과 실습 (0) | 2018.06.16 |