김주엽
1. 📌 핵심 개념 정리
✅ 요약하기
- 적절한 행 길이를 유지하라
소스 코드의 세로 길이는 얼마나 길어야 적당한가?Junit
,FitNesse
,testNG
,Time and Money
,JDepend
,Tomcat
등 프로젝트 조사 결과 평균 파일 크기는 약65줄
이다. 프로젝트에서 가장 긴 파일은400줄
이고 짧은 파일은6줄
이다. 여기서JUnit
,FitNesse
,Time and Money
는 상대적으로 파일 크기가200줄
정도로 작았다.- 코드 길이
200줄
정도로도 커다란 시스템 구축이 가능하다. - 코드 길이에 대해서 엄격한 규칙이 있는 것은 아니지만 이해하기 쉽도록 작은 길이를 유지하자.
-
개념은 빈 행으로 분리하라
모든 코드는 왼쪽에서 오른쪽으로 위에서 아래로 읽힌다.
각 행은 수식이나 절을 나타내며 행 묶음은 완전한 개념 하나를 표현하므로 개념 사이에는 빈 행을 넣어야 한다.-
개선 전
@WebServlet("/api/youtube/*") public class YoutubeController extends Controller { private final YoutubeService youtubeService; public YoutubeController() { ServletContext servletContext = CustomServletContextListener.getServletContext(); youtubeService = (YoutubeService) servletContext.getAttribute("YoutubeService"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); if (pathInfo != null) { routeGetMethod(req, resp); return; } List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList); } private void responseYoutubeListAsJson(HttpServletResponse resp, List<GameItem> gameItemList) throws IOException { resp.setContentType("application/json"); resp.setCharacterEncoding("UTF-8"); resp.getWriter().write(JsonUtil.toJson(gameItemList)); } private void routeGetMethod(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); String[] pathParts = pathInfo.split("/"); if (pathParts.length < 3) { // 올바른 요청이 아닐 경우 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid API request format."); return; } String type = pathParts[1]; String value = pathParts[2]; switch (type) { case "title" -> requestTitleAPI(resp, value); case "theme" -> requestThemeAPI(resp, value); default -> resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid endpoint."); } } }
개선 전 코드의 경우 각 행을 분리하지 않아 코드를 읽고 해석하기 어렵다.
-
개선 후
@WebServlet("/api/youtube/*") public class YoutubeController extends Controller { private final YoutubeService youtubeService; public YoutubeController() { ServletContext servletContext = CustomServletContextListener.getServletContext(); youtubeService = (YoutubeService) servletContext.getAttribute("YoutubeService"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); if (pathInfo != null) { routeGetMethod(req, resp); return; } List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList); } private void responseYoutubeListAsJson(HttpServletResponse resp, List<GameItem> gameItemList) throws IOException { resp.setContentType("application/json"); resp.setCharacterEncoding("UTF-8"); resp.getWriter().write(JsonUtil.toJson(gameItemList)); } private void routeGetMethod(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); String[] pathParts = pathInfo.split("/"); if (pathParts.length < 3) { // 올바른 요청이 아닐 경우 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid API request format."); return; } String type = pathParts[1]; String value = pathParts[2]; switch (type) { case "title" -> requestTitleAPI(resp, value); case "theme" -> requestThemeAPI(resp, value); default -> resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid endpoint."); } } }
행 분리 후 메서드에 대한 구분을 이해하기 쉬워진 것을 볼 수 있다.
-
- 변수 및 함수 선언
- 지역 변수는 사용하는 위치에 최대한 가까이 선언한다.
- 멤버 변수는 클래스 맨 처음에 선언하고 변수 간에 세로로 거리를 두지 않는다.
- 종속 함수는 호출하는 함수를 호출되는 함수보다 먼저 배치하고 가까이 배치한다.
- 종속 함수: 함수에서 다른 함수를 호출할 때 종속 관계에 놓여져 있다고 볼 수 있다.
- 가장 중요한 개념을 가장 먼저 함수로 작성한다.
-
들여쓰기
블록 단위로 이뤄진 계층을 표현하기 위해서 들여쓰기를 사용한다.
때로는 간단한if문
,짧은 while문
,짧은 함수
에서 들여쓰기를 무시하는데 이는 피하도록 하자.-
개선 전
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String pathInfo = req.getPathInfo(); if (pathInfo != null) {routeGetMethod(req, resp); return;} List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList);}
-
개선 후
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); if (pathInfo != null) { routeGetMethod(req, resp); return; } List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList); }
-
2. 🤔 이해가 어려운 부분
🔍 질문하기
책을 읽으며 이해하기 어려웠던 개념이나 명확하지 않았던 내용을 정리합니다.
- 종속 함수
- 어려웠던 부분
처음 봤을 때 단어가 생소한 단어여서 이해하는데 어려움이 있었다. - 이해한 점
- 종속 함수는 다른 함수에 직접적으로 의존하여 독립적으로 동작할 수 없는 함수를 의미한다.
- 함수 간의 종속성이 강하면 코드의 유지보수성이 낮아지고 재사용성과 테스트가 어려워진다.
- 어려웠던 부분
3. 📚 참고 사항
📢 논의하기
관련된 자료가 있다면 공유하고, 더 깊이 논의하고 싶은 아이디어나 의견을 정리합니다.
- 관련 자료 공유
- 추가 자료
[우아한 테크 세미나 - 리팩터링 정리# 1. 📌 핵심 개념 정리
- 추가 자료
✅ 요약하기
- 적절한 행 길이를 유지하라
소스 코드의 세로 길이는 얼마나 길어야 적당한가?Junit
,FitNesse
,testNG
,Time and Money
,JDepend
,Tomcat
등 프로젝트 조사 결과 평균 파일 크기는 약65줄
이다. 프로젝트에서 가장 긴 파일은400줄
이고 짧은 파일은6줄
이다. 여기서JUnit
,FitNesse
,Time and Money
는 상대적으로 파일 크기가200줄
정도로 작았다.- 코드 길이
200줄
정도로도 커다란 시스템 구축이 가능하다. - 코드 길이에 대해서 엄격한 규칙이 있는 것은 아니지만 이해하기 쉽도록 작은 길이를 유지하자.
-
개념은 빈 행으로 분리하라
모든 코드는 왼쪽에서 오른쪽으로 위에서 아래로 읽힌다.
각 행은 수식이나 절을 나타내며 행 묶음은 완전한 개념 하나를 표현하므로 개념 사이에는 빈 행을 넣어야 한다.-
개선 전
@WebServlet("/api/youtube/*") public class YoutubeController extends Controller { private final YoutubeService youtubeService; public YoutubeController() { ServletContext servletContext = CustomServletContextListener.getServletContext(); youtubeService = (YoutubeService) servletContext.getAttribute("YoutubeService"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); if (pathInfo != null) { routeGetMethod(req, resp); return; } List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList); } private void responseYoutubeListAsJson(HttpServletResponse resp, List<GameItem> gameItemList) throws IOException { resp.setContentType("application/json"); resp.setCharacterEncoding("UTF-8"); resp.getWriter().write(JsonUtil.toJson(gameItemList)); } private void routeGetMethod(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); String[] pathParts = pathInfo.split("/"); if (pathParts.length < 3) { // 올바른 요청이 아닐 경우 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid API request format."); return; } String type = pathParts[1]; String value = pathParts[2]; switch (type) { case "title" -> requestTitleAPI(resp, value); case "theme" -> requestThemeAPI(resp, value); default -> resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid endpoint."); } } }
개선 전 코드의 경우 각 행을 분리하지 않아 코드를 읽고 해석하기 어렵다.
-
개선 후
@WebServlet("/api/youtube/*") public class YoutubeController extends Controller { private final YoutubeService youtubeService; public YoutubeController() { ServletContext servletContext = CustomServletContextListener.getServletContext(); youtubeService = (YoutubeService) servletContext.getAttribute("YoutubeService"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); if (pathInfo != null) { routeGetMethod(req, resp); return; } List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList); } private void responseYoutubeListAsJson(HttpServletResponse resp, List<GameItem> gameItemList) throws IOException { resp.setContentType("application/json"); resp.setCharacterEncoding("UTF-8"); resp.getWriter().write(JsonUtil.toJson(gameItemList)); } private void routeGetMethod(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); String[] pathParts = pathInfo.split("/"); if (pathParts.length < 3) { // 올바른 요청이 아닐 경우 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid API request format."); return; } String type = pathParts[1]; String value = pathParts[2]; switch (type) { case "title" -> requestTitleAPI(resp, value); case "theme" -> requestThemeAPI(resp, value); default -> resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid endpoint."); } } }
행 분리 후 메서드에 대한 구분을 이해하기 쉬워진 것을 볼 수 있다.
-
- 변수 및 함수 선언
- 지역 변수는 사용하는 위치에 최대한 가까이 선언한다.
- 멤버 변수는 클래스 맨 처음에 선언하고 변수 간에 세로로 거리를 두지 않는다.
- 종속 함수는 호출하는 함수를 호출되는 함수보다 먼저 배치하고 가까이 배치한다.
- 종속 함수: 함수에서 다른 함수를 호출할 때 종속 관계에 놓여져 있다고 볼 수 있다.
- 가장 중요한 개념을 가장 먼저 함수로 작성한다.
-
들여쓰기
블록 단위로 이뤄진 계층을 표현하기 위해서 들여쓰기를 사용한다.
때로는 간단한if문
,짧은 while문
,짧은 함수
에서 들여쓰기를 무시하는데 이는 피하도록 하자.-
개선 전
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String pathInfo = req.getPathInfo(); if (pathInfo != null) {routeGetMethod(req, resp); return;} List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList);}
-
개선 후
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); if (pathInfo != null) { routeGetMethod(req, resp); return; } List<GameItem> gameItemList = youtubeService.readAllYoutubeItem(); responseYoutubeListAsJson(resp, gameItemList); }
-
2. 🤔 이해가 어려운 부분
🔍 질문하기
책을 읽으며 이해하기 어려웠던 개념이나 명확하지 않았던 내용을 정리합니다.
- 종속 함수
- 어려웠던 부분
처음 봤을 때 단어가 생소한 단어여서 이해하는데 어려움이 있었다. - 이해한 점
- 종속 함수는 다른 함수에 직접적으로 의존하여 독립적으로 동작할 수 없는 함수를 의미한다.
- 함수 간의 종속성이 강하면 코드의 유지보수성이 낮아지고 재사용성과 테스트가 어려워진다.
- 어려웠던 부분
3. 📚 참고 사항
📢 논의하기
관련된 자료가 있다면 공유하고, 더 깊이 논의하고 싶은 아이디어나 의견을 정리합니다.
- 관련 자료 공유
- 추가 자료
우아한 테크 세미나 - 리팩터링 정리
- 추가 자료
No Comments