System Design
return (code, data) 함께 반환하기
return (code, data) 함께 반환하기
2023.10.07때때로 method 내에서 정상 로직 진행에 실패한 경우에도 data를 상위 메서드에 전달해야 하는 경우가 있다. (e.g., 추가인증필요, 기처리) 기본적으로 throw Exception을 return 처럼 data 반환 용도로 사용하는 것은 불가능 하기 때문에, return 기반으로 접근해야 한다. 직접 return 타입 정의해 사용하기 data class FooResult( val code: Code, val field1OnlyIfSuccess, val field2OnlyIfSuccess, val field3OnlyIfFailure } { enum Code { SUCCESS, FAILURE } } Result 타입 R 타입에 code 없고 성공+실패 data field만 존재하는 경우 유용. 보편적..
caller는 callee를 믿지 않는 것이 좋다 (어차피 catch 해야 한다)
caller는 callee를 믿지 않는 것이 좋다 (어차피 catch 해야 한다)
2023.10.07중요한 처리로직 인 경우, 어차피 caller는 callee를 믿어서는 안된다. 여기서 callee는 다른 class 혹은 다른 class의 메서드를 의미한다. 같은 class 내 private method를 호출하는 경우라면, 자기 자신이 직접 정의한 기능이므로 믿을 수 있으나, class 바깥의 다른 class와 메시지를 주고 받는 상황이라면 신뢰하지 않는 것을 기본 전제로 깔고가야 한다. 예시 ) 금액 소진 메서드를 제공하는 callee가 Exception을 반환하지 않겠다고 docstring에 명시해두었다면 믿을 것인가? 금액 소진 기능인데, callee의 docstring과 현재 구현된 메서드 내부만 믿고 caller는 catch 안할 것인가? 그럴리가 없다는 것이다. caller 입장에서 ca..
좋은 설계란 무엇일까? : 유지보수가 쉬운 시스템을 만드는 것
좋은 설계란 무엇일까? : 유지보수가 쉬운 시스템을 만드는 것
2023.03.03우리가 하는 개발-코딩은, 진리를 추구하는 학문이나 과학이 아니다. 지식이나 법칙, 진리를 발굴한다거나 완전 무결한 최고의 시스템을 만들어내는게 우리의 목표가 아니다. 우리가 하는 것은 공학이다. 공학의 정의는 다양하나, ('실천적인 문제 해결', '기술적 해결책 제시', '현실적인 문제 해결'...) 공통으로 등장하는 키워드는 '문제 해결' 이다. 우리에게 당면한 문제를 효과적으로 해결하는 것. 그 것이 우리의 목표다. 문제를 해결하려면, '문제가 무엇인가?'에서 부터 출발해야 한다. 보통 공학에서 주어지는 문제란, 사업 방향성과 밀접하게 맞닿아 있다. '어떤 방향으로 사업을 하기 위해서, 이런 프로덕트, 서비스가 필요합니다. 비용은 가능한 적게 들면 좋겠습니다.' 주목해야 하는 포인트는 비용이다. 물..
Good design is all about trade-offs
Good design is all about trade-offs
2023.02.15이 글은 보호되어 있기 때문에 이것을 보려면 암호가 필요합니다.
[Spring] MVC Layered Architecture : DTO 전달/변환/파라미터 설계
[Spring] MVC Layered Architecture : DTO 전달/변환/파라미터 설계
2022.03.17Controller -> Service 호출 시, Service의 메서드 파라미터 설계 ```java @PostMapping("/some-path") public ResponseEntity foo(@RequestBody @Valid FooControllerRequest request) { varService.doSomething(request.getGroupId(), request.getUserId()); ... } /* foo API에 변경이 발생했다 */ @DeleteMapping("/some-path/groups/{groupId}/users/{userId}") public ResponseEntity foo(@PathVariable String groupId, @PathVariable String u..
[Spring] MVC Layered Architecture : DTO와 Domain Model을 분리해야 하는 이유
[Spring] MVC Layered Architecture : DTO와 Domain Model을 분리해야 하는 이유
2022.03.14God Class에 대한 용어 정리 god class는, 꼭 크기가 커야만(가지고 있는 필드가 많아야만) god class인 것은 아닙니다. 여러 layer에 걸쳐 사용되고 있다면, 또는 2개 이상의 책임을 가지고 있다면, 그 클래스를 사용(의존)하고 있는 클래스가 그 만큼 많다는 의미이고, 이는 곧 god class (또는 god class 유망주)입니다. god class는 크게 2가지 유형으로 나누어 볼 수 있습니다. (왼쪽) domain 책임은 제대로 나눴으나 여러 layer에 걸쳐 사용되는 경우 = 유형 1 (오른쪽) domain 책임을 제대로 나누지 못해 1개 이상의 책임을 가지는 경우 = 유형 2 유형 1 + 유형 2 = 유형3 이 글에서 주요하게 다루고자 하는 내용은 유형 1 God Cla..
[마틴파울러] Layering 관련 글 모음
[마틴파울러] Layering 관련 글 모음
2022.03.13https://martinfowler.com/bliki/PresentationDomainDataLayering.html layer를 나누는 것의 장점 1. 관심 분리 (를 통해 작업 대상 layer에 집중 가능) 마틴 파울러는 layer를 나누는 것의 최고 장점은, 작업 대상이 되는 layer에만 집중할 수 있도록 해준다는 점이라고 얘기하고 있다. It's biggest advantage (for me) is that it allows me to reduce the scope of my attention by allowing me to think about the three topics relatively independently. When I'm working on domain logic code I ..
Domain Model에 대해서
Domain Model에 대해서
2022.03.11Domain Model이란 해당 도메인에서 비즈니스적인 의미를 가지는 object 다. An object model of the domain that incorporates both behavior and data. - P of EAA Domain Model은 id 여부에 따라 두 가지로 구분할 수 있다. Entity id가 있어 각각의 개체를 고유하게 식별 할 수 있는 경우 엄밀히 불변은 아니고 시간이 지나면서 상태가 변경될 수 있는 대상임. (그러나 이와 별개로 앱단에서는 불변 객체로 처리하는 것이 좋다. 함수형.) e.g., Member VO ( value object ) id가 없음 To avoid aliasing bugs I follow a simple but important rule: val..
Repository와 DataMapper의 책임 (w/o ORM)
Repository와 DataMapper의 책임 (w/o ORM)
2022.03.09traditional Java EE 패턴에서의 정의 Spring에서 제공하는 @Repository 는 DAO 의미를 지닌다. (javadoc 참조) MyBatis에서 제공하는 @Mapper 는 sql mapper 의미를 지닌다. 따라서 layer는 아래와 같이 표현되어야 한다. ```kt @Service ---> @Repository ---> @Mapper ----> mapper.xml || annotation-string DAO sql mapping ``` 관습적으로 @Repository와 @Mapper를 동일한 layer로 간주하는 경우가 많은데, 서로 다른 layer로 간주해야 한다. "dao와 mapper의 차이" 로 검색해보면, 마치 두 개념이 같은 추상화 수준이며 서로 양립 불가한 것 처럼 보..
API 응답 코드 계층 구조 설계
API 응답 코드 계층 구조 설계
2022.02.26HTTP | | httpStatusCode는 해당 서버로부터 오는 모든 api 응답의 일관된 처리를 위한 error code로서 의미를 가짐 body: { code: ?, --> body.code는 해당 서버로부터 오는 모든 api 응답의 일관된 처리를 위한 error code로서 의미를 가짐 data: { code: ? --> body.data.code는 api의 성공/실패 보다는 코드값 자체로서의 의미. } } } // **body.code 가 httpStatusCode로 모두 커버가 된다면 통합하여 1depth 줄일 수 있음** @FE에서 받는 다면 http.get(`/api-1/example`) .then(resultCodeHandler( --> body.code 에러 처리 data => { da..
[리팩터링 2판] 3장 Bad Smells in Code
[리팩터링 2판] 3장 Bad Smells in Code
2021.10.14이번 챕터는 언제 리팩터링 해야 하는가? 어떤 코드가 리팩터링이 필요한 코드인가?에 대해서 다룬다. (적어도 나는)코드가 구조적으로 예쁘지 않아서, 보고 있자니 뭔가 마음 한켠이 불편해서, 같은 '느낌'을 감지하고 리팩터링을 하게 되는데 이런 모호한 기준을 끄집어 내서 문장으로 구체화한 챕터이다. 리팩터링이 필요한 코드가 가지고 있는 공통점, bad smell에 대해서 얘기한다. 무엇이 문제인지 알아야, 그에 따른 해결 방안도 떠올릴 수 있다. 부록B에 보면 bad smell case와 해법이 잘 정리되어 있음. 정리하면서 평소 개발하면서 정립했던 나의 개인적인 의견도 같이 적어 두었음. (인용구로 되어 있는 부분) 3.1 기이한 이름 함수든, 변수든, 클래스든 이름만 보고도 각각이 무슨 일을 하고 어떻..
CQRS : Command and Query Responsibility Segregation
CQRS : Command and Query Responsibility Segregation
2021.04.21martinfowler.com/bliki/CQRS.html (번역) https://martinfowler.com/bliki/CommandQuerySeparation.html CRUD를 모두 하나의 도메인 모델을 사용해 처리했었다면, CQRS는 CUD를 Command용 모델로, R을 Query용 모델로 분리하여 설계하는 방법 하지만 문서 전체에서 CQRS는 잘 들어맞는 부분에만 일부 사용할 것을 권장하고 있다. 문서에서 발췌 CQRS는 시스템의 특정한 부분(DDD 표현으로는 Bounded Context)에서만 사용돼야 하고, 시스템 전체에서 사용해서는 안 된다. 이러한 사고방식은 각 Bounded Context는 개별적으로 모델링을 해야 한다는 의미다. (Bounded Context: https://www..