전체 글
-
Git 커밋 메시지 바꾸는 방법Git 2023. 3. 24. 00:01
가장 최근의 commit 수정 git commit --amend 위의 커밋 메시지를 수정하고 :wq를 통해 저장해 줍니다. 여러 개의 commit 수정하기 맨 위에서부터 5개의 커밋을 수정하고 싶은 상황입니다. git rebase -i HEAD~5 위의 명령어를 사용하면 다음과 같이 5개의 commit 내역이 보입니다. pick c348121d refactor: 사용하지 않는 로컬 변수 및 사용하지 않는 주석코드 제거 pick e312034f refactor: local 변수 가까히 배치 pick 1faac36a style: 코드 포맷팅 pick 77985046 refactor: 사용하지 않는 로컬 변수 제거 pick a6f193fc refactor: 메서드 추출 pick을 reword로 바꿔주고 :wq..
-
구글 구독시 3일 후 자동 환불 케이스 분석장애대응 2023. 3. 23. 00:01
개요 및 영향범위 분석 사용자가 구독상품을 결제한 뒤 3일 뒤에 자동으로 환불되는 경우가 발생하였습니다. 서버로직에서는 사용자가 결제한 구독상품에 대한 정보를 저장하고, 해당 상품의 구독 정보를 제3의 외부 저장시스템에 저장합니다. 이때 무료상품에 대한 만기일은 1 달이지만 유료상품에 대한 만기일은 무기한입니다. 이런 경우 사용자는 구독중이라고 뜨지만 실제로 구독을 해지하러 가는 경우 구글 플레이스토어에서는 구독 중인 상품이 보이지 않습니다. (이미 자동으로 환불되었기 때문) 사용자에게는 실제로 돈은 청구되지 않지만 구독중이며 N월 N일부터 매월 N원 자동 결제 예정이라는 문구가 표기됩니다. 이로 인해 사용자는 혼란에 빠질 수 있으며 VOC가 발생합니다. (문구를 보고 구독을 취소하러 갔지만 구독 중인 ..
-
Controller에서 List 받기(+ dto로 받고 validation)Spring Framework 2023. 3. 22. 00:01
Controller에서 List 받기 Controller 코드 구성 import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @RestController class TestController { @GetMapping("/test/list") fun inputList( @RequestParam("list") list: List ): String { println(list) return list.toString() } } Postman으로 요청하기..
-
35장 - 복잡한 객체를 생성하기 위한 DSL을 정의하라Kotlin/Effective Kotlin 요약 2023. 3. 21. 00:01
코틀린을 활용하면 DSL을 직접 만들 수 있습니다. DSL을 만드는 것은 수고스러우나, 한 번 만들고 나면 보일러플레이트와 복잡성을 숨기면서 개발자의 의도를 명확하게 표현할 수 있습니다. Spring Kotlin개발자에게는 다음과 같은 DSL이 친숙할 수 있습니다. Kotest를 활용하여 테스트 케이스를 정의할 때 Gradle의 설정을 정의할 때 사용자 정의 DSL 만들기 DSL을 만들기 전 리시버를 사용하는 함수 타입에 대한 개념을 이해해야 합니다. 람다식을 떠올리면 좋으며 함수 타입의 몇 가지 예시입니다. () -> Unit 아규먼트를 갖지 않고 Unit을 리턴 (Int, Int) -> Int Int타입 아규먼트 2개를 받고, Int를 리턴하는 함수 함수 타입을 만드는 기본적인 방법들 람다 표현식 익..
-
34장 - 기본 생성자에 이름 있는 옵션 아규먼트를 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 20. 00:01
객체를 생성하고 사용하는 가장 기본적인 방법 class User(var name: Stirng, var surname: String) val user = User("Marcin", "Moskala") 이처럼 객체의 초기 상태를 나타내는 아규먼트를 전달합니다. 데이터 모델 객체 data class Student( val name: String, val surname: String, val age: Int, ) 하지만 생성자에 선언된 아규먼트 이외에도 클래스의 필드로도 프로퍼티를 가질 수 있습니다. 이럴 때는 어떻게든 초기화된 되면 상관없습니다. 일반적으로 기본생성자가 제일 좋은 방식인 이유를 이해하려면, 점층적 생성 패턴과 빌더 패턴에 대해 이해하는 것이 좋습니다. 점층적 생성 패턴 class Pizza{..
-
33장 - 생성자 대신 팩토리 함수를 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 19. 00:01
클라이언트가 클래스의 인스턴스를 만들게 하는 다양한 방법을 알아보겠습니다. 가장 일반적인 방법 - 생성자 class MyLinkedList{ val head: T, val tail: MyLinkedList? } val list = MyLinkedList(1, MyLinkedList(2, null)) 하지만 굉장히 다양한 생성 패턴이 존재하며, 별도의 함수를 통해 생성할 수 있습니다. 팩토리 함수 fun myLinkedListof( vararg elements: T ): MyLinkedList? { if(elements.isEmpty()) return null val head = elements.first() val elementsTail = elements.copyOfRange(1, elements.si..
-
32장 - 추상화 규약을 지켜라Kotlin/Effective Kotlin 요약 2023. 3. 18. 00:01
규약과 위반 규약은 개발자들의 단순한 합의에 불과합니다. 따라서 한쪽에서 규약을 위반할 수도 있습니다. 간단한 예시로 리플렉션을 활용하면 private property의 값을 변경할 수 있습니다. 하지만 이를 위반하면 안 됩니다. 프로젝트에서 규약을 위반하는 경우 이는 내부에 시한폭탄을 설치한 것과 같습니다. 상속된 규약 모든 클래스는 equals와 hashCode 메서드를 가진 Any 클래스를 상속받습니다. 이러한 메서드는 모든 우리가 반드시 존중하고 지켜야 하는 규약을 갖고 있습니다. 이를 지키지 않는다면 HashSet과 함께 사용할 때 제대로 동작하지 않을 수 있습니다.
-
31장 - 문서로 규약을 정의하라Kotlin/Effective Kotlin 요약 2023. 3. 17. 00:01
아이템 27에서 추상화를 통해 메시지를 출력하는 함수를 만들었습니다. fun Context.showMessage( message: String, duration: MessageLength = MessageLength.Long ){ val toastDuration = when(duration){ SHORT -> LENGTH.LENGTH_SHORT LONG -> LENGTH.LENGTH_LONG } Toast.makeText(this, message, toastDuration).show() } enum class MessageLength {SHORT, LONG} 이때 showMessage라는 함수이름을 통해 토스트가 아니라 다른 타입으로도 출력할 수 있도록 이름을 붙였습니다. 하지만 다른 개발자는 이 코드를..