일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- SpringSecurity
- gitignore
- 알고리즘 #코딩테스트 #프로그래머스 #C++ #vector #string
- index.html
- springboot
- JPA autiding
- 프로그래머스
- baekjoon
- JPA
- 코딩테스트
- DB
- C++
- mustache
- test case
- tdo
- SpringBean
- DynamicProgramming
- SpringFramework
- spring
- rombok
- testcode
- kotlin
- 해싱
- TDD
- Java
- SpringDataJPA
- 알고리즘
- Gradle
- Comparable
- API
- Today
- Total
천천히, 한결같이
[Spring] 코드 재사용으로 클린 코드 만들기 본문
본 코드는 필자의 프로젝트 백엔드 파트의 Controller 계층에 해당하는 부분입니다. SpringBoot 라이브러리를 사용해 개발하고 있으며, Kotlin 언어로 개발중입니다. 학부생이 스스로 공부하는 내용이라 틀린 부분이 있을 수도 있고, 잘못된 부분이 많을 수도 있습니다. 언제나 많은 지적바랍니다.
Clean Code_클린코드
클린 코드가 중요하다는 이야기는 많이 들어보았습니다. 결론부터 이야기하면 클린 코드라고 하면 “읽기 쉬운 코드” 라고 정의할 수 있습니다.
클린 코드가 중요하다는 이야기는 익히 들었으나, 평소 코딩 시에 저만의 간단한 원칙들만 생각하며 개발하고 있었고 (else 예약어 사용하지 않기, 반복문 중첩하지 않기, 객체 이름 의미 부여해서 짓기 등) 클린 코드를 위한 노력은 따로 하지 않았습니다.
기존에 진행하였던 프로젝트를 사이드에서 계속 진행하게 되었고, 필자는 기존 Java로 개발하고 있던 프로젝트를 Kotlin으로 개발해보자 하는 생각에 Kotlin으로 SpringBoot 프레임워크를 활용, 백엔드 파트를 개발하고 있었습니다.
Controller 계층을 Kotlin으로 다시 작성하며 리펙토링 하던 도중, 반복적으로 사용되는 코드를 확인할 수 있었습니다.
Code Review_코드리뷰
@RequiredArgsConstructor
@RestController
public class UsersController {
private final UsersService usersService;
@PostMapping("/api/v1/users")
public ResponseEntity<Messages> save(@RequestBody UsersSaveRequestDto requestDto) {
String user_id = usersService.save(requestDto);
UsersResponseDto responseDto = usersService.findByUserId(user_id);
UsersReturnDto returnDto = new UsersReturnDto(responseDto);
Messages messages = Messages.builder()
.httpStatus(200)
.message("Users is saved well")
.data(returnDto)
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
return new ResponseEntity<>(messages, headers, HttpStatus.OK);
}
@PutMapping("/api/v1/users/{planner_id}/{user_id}")
public ResponseEntity<Messages> addPlanners(@PathVariable Long planner_id, @PathVariable String user_id) {
usersService.addPlanners(planner_id, user_id);
Messages messages = Messages.builder()
.httpStatus(200)
.message("Add planner, id : " + planner_id + ", with User, id : " + user_id)
.data(null)
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
return new ResponseEntity<>(messages, headers, HttpStatus.OK);
}
@GetMapping("/api/v1/users/{user_id}")
public ResponseEntity<Messages> findById(@PathVariable String user_id) {
UsersResponseDto responseDto = usersService.findByUserId(user_id);
UsersReturnDto returnDto = new UsersReturnDto(responseDto);
Messages messages = Messages.builder()
.httpStatus(200)
.message("Load user with id : " + user_id)
.data(returnDto)
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
return new ResponseEntity<>(messages, headers, HttpStatus.OK);
}
...생략
현재 제 프로젝트에서 Users 엔티티와 관련되는 Controller를 담당하는 UsersController 클래스입니다. 리펙토링을 위해 코드리뷰를 진행하고 있는 도중 반복적으로 사용되는 코드를 찾을 수 있었습니다. 혹시 반복적으로 사용되는 코드가 보이시나요?
Messages messages = Messages.builder()
.httpStatus(200)
.message("Load user with id : " + user_id)
.data(returnDto)
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
return new ResponseEntity<>(messages, headers, HttpStatus.OK);
바로 이 부분입니다. Controller 계층에서 활용되고 있는 모든 함수에서 다음과 같이 ResponseEntity
그런데 만약, 이렇게 모든 함수에서 반복되는 코드를 따로 빼서 private한 함수로 만든 다음에 객체 내부에서만 private한 함수를 사용하면 어떨까? 하는 생각이 들었고, JSON파일에 message를 담기 위한 String, data를 담기 위한 Object (Any? In Kotlin)를 매개변수로 가지는 함수를 만들어서 사용해 보았습니다.
private fun sendResponseHttpByJson (message : String?, data : Any?) : ResponseEntity<Messages> {
val messages : Messages = Messages(
httpStatus = 200,
message = message,
data = data
)
val headers : HttpHeaders = HttpHeaders()
headers.*contentType*= MediaType (“application”, “json”, Charset.forName(“UTF-8”))
return ResponseEntity<Messages>(messages, headers, HttpStatus.*OK*)
}
위 함수는 message와 data를 매개변수로 받아서 ResponseEntity
//변경 전
@PostMapping("/api/v1/users")
public ResponseEntity<Messages> save(@RequestBody UsersSaveRequestDto requestDto) {
String user_id = usersService.save(requestDto);
UsersResponseDto responseDto = usersService.findByUserId(user_id);
UsersReturnDto returnDto = new UsersReturnDto(responseDto);
Messages messages = Messages.builder()
.httpStatus(200)
.message("Users is saved well")
.data(returnDto)
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
return new ResponseEntity<>(messages, headers, HttpStatus.OK);
}
//변경 후
@PostMapping("/api/v1/users")
public fun save (@RequestBody requestDto: UsersSaveRequestDto) : ResponseEntity<Messages> {
val user_id : String? = usersService.save(requestDto)
val responseDto : UsersResponseDto = usersService.findByUserId(user_id)
val returnDto : UsersReturnDto = UsersReturnDto(responseDto = responseDto)
return sendResponseHttpByJson("User is saved well", returnDto)
}
재사용 함수를 만든 후 리펙토링 전과 후를 비교한 모습입니다. 함수의 코드도 한 눈에 들어오고 코드의 길이도 대폭 감소한 것을 알 수 있습니다. (변경 전 언어는 Java이고 변경 후 언어는 Kotlin입니다.) 전체 코드는 167줄에서 91줄로 대폭 감소하였습니다!
리펙토링 후에 다시 코드를 보니, 변경 전 함수는 어떻게 보면 두 가지 일을 하고 있다고 해도 무방할 것 같습니다. (Service 계층으로 정보 전달과 함께 로직 요청, Service 계층에서의 응답을 바탕으로 클라이언트에게 발송할 Json파일 작성) 하지만 이 두가지 일을 분리하였고, 보다 깔끔하게 코드를 작성할 수 있었습니다.
클린코드라는 것이 중요하면서도 동시에 어려운 내용이긴 하지만 평소 관심을 가지고 코드를 보면 다음과 같이 조금씩 변경할 수 있는 것 같습니다. 클린코드에 대해서 확실하게 공부를 해 보아야 하겠지만 평상시에 이러한 점들에 항상 유념하며 개발을 진행한다면 클린코드 작성에 한 걸음 더 다가갈 수 있지 않을까 생각해 봅니다 :)
'Spring' 카테고리의 다른 글
[Spring] {entity class} cannot be cast to java.lang.comparable 해결하기 (0) | 2022.07.20 |
---|---|
[Spring] 프로젝트 생성 시 spring security 사용 후 localhost:8080/login (0) | 2022.02.27 |
[Spring] IntelliJ exit with non-zero value 1 오류 (0) | 2022.01.18 |
[Spring] 스프링 시큐리티, OAuth2를 사용해서 Google 서비스 등록하기 (0) | 2022.01.08 |
[Spring] 글 등록 화면 만들기 (0) | 2022.01.02 |