AWS 이것만 외우자

로컬 vs 클라우드 차이: Networking 백엔드 개발을 처음 배울 때, Hello World 를 출력하는 앱을 만들어본다. 예를 들어, 아래와 같이 요청에 대해 “Hello World” 를 응답하는 것이다 (Spring Boot 사용). @RestController class DemoController { @GetMapping fun getDemo() = "Hello World" } 이 애플리케이션을 로컬 컴퓨터에서 구동한 후, 로컬 브라우저에서 localhost:8080 을 입력해 Hello World 를 브라우저 화면에서 확인할 수 있다. 애플리케이션을 AWS 에서 구동하는 것 역시 이와 거의 동일하다. 로컬 환경이 클라우드 환경으로 변한 것뿐이다....

March 9, 2024

Kotlin Coroutines

왜 coroutine 을 사용해야 할까? Kotlin coroutine 은 효율적으로 thread 를 사용하고, 프로그래머가 편하고, 퍼포먼스가 좋다. 효율적으로 thread 를 사용한다 Thread 를 생성하는 데에는 큰 비용이 든다. 그런데 Coroutine 를 사용하기 위해 추가적인 thread 생성이 필요 없다. 또한 coroutine 은 non-blocking 이다. 즉, coroutine 이 완료될 때까지 thread 가 멈춰있지 않고 다른 작업을 처리할 수 있다. 아래 예시를 보자. fun showOrderInfo(details: Details) = async { val orderId = orderProduct(details).await() val orderData = loadOrderData(orderId)....

September 26, 2023

JPA: 단뱡향 @ManyToOne만 써라

자극적인 제목 미안하다. 물론 장단점이 있을 수 있다. 하지만 글의 결론부터 말하자면, 단방향 (unidirectional) @OneToMany보다는 양방향 (bidirectional) @OneToMany가 좋고, 양방향 @OneToMany보다는 단방향 @ManyToOne이 좋다. @OneToMany를 사용한다면 무조건 양방향이 좋다. Spring Boot Persistence Best Practices 책의 저자는 @OneToMany가 단방향으로 설정됐을 때 얼마나 안 좋은지를 서술한다. JPA 에서 엔티티 관계를 양방향으로 설정할 경우 귀찮은 일이 생긴다. 그렇기 때문에 단방향으로 설정하는 경우가 있다. 하지만 @OneToMany는 단방향을 선택하면 안 된다. 비효율적인 쿼리가 발생하기 때문이다. 여기서는 실험을 통해 이를 확인한다....

March 19, 2023

특정 커밋만 제외하고 모두 git merge

Develop 브랜치의 여러 개의 커밋 중 특정 커밋만 제외하고 나머지를 모두 master 브랜치에 merge하는 방법이 없을까? 상황 먼저 이런 상황은 어떤 때 발생할까? 실제로 겪은 상황으로, 세부 사항은 아래와 같다. Develop 브랜치의 총 다섯 개 커밋 중 두 번째, 세 번째 커밋만 테스트가 완료되지 않았다. 나머지 커밋은 당장 master에 merge 후 deploy해야 한다. 언제든 테스트가 완료되면, 두 번째 및 세 번째 커밋도 master에 merge해야 한다. 해결 방법: cherry pick Develop 브랜치의 commit log는 아래와 같다....

December 4, 2022

Hibernate가 무슨 쿼리를 만드는지 눈으로 확인하지 말자

JPA hibernate는 편리하지만 때로 치명적이다. 의도하지 않은 여러 쿼리가 실행돼 db에 부하가 걸리거나, 영속성 컨텍스트와 실제 db 데이터가 다를 수 있는 등의 문제가 발생할 수 있기 때문이다. 여기서는 첫 번째 문제를 보완할 수 있는 방법을 소개한다. Hibernate가 어떤 쿼리를 생성하는지 보통은 눈으로 확인한다. 아래와 같은 로그를 보고 말이다. [ Test worker] org.hibernate.SQL : select book0_.id as id1_0_0_ from book book0_ where book0_.id=? [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [0] 로그를 눈으로 보면 select 쿼리가 한 번 발생하는 것을 확인할 수 있다....

August 31, 2022

Interface vs Abstract Class

Interface와 abstract class의 차이를 알아보자. Java 8부터 interface에는 default method가 생겼다. 이로 인해 interface와 abstract class의 차이가 하나 줄었다. Interface와 abstract class의 차이는 크게 두 가지다. Abstract class는 interface와 달리 다중 상속의 대상이 될 수 없다. Abstract class는 state를 가질 수 있지만 interface는 state를 가질 수 없다. 이외에도 lambda expression과 관련한 차이도 있다. 하지만 여기서는 다루지 않는다. 위에 명시한 두 가지 차이에 대해서 알아보자. 다중 상속 Effective Java를 보면 abstract class보다는 interface를 사용하라고 한다....

August 7, 2022

Garbage Collection

자바 메모리 관리에 대해 알아보자. 메모리 관리란 새로운 object를 메모리에 할당하고, 오래된 object를 메모리에서 제거하는 과정을 말한다. Garbage Collection Garbage Collection이란 objects를 할당하기 위해 heap 또는 nursery 공간을 확보하는 과정을 말한다. Java에서는 사용자가 직접 메모리를 통제하는 게 아니라 JVM의 Garbage Collector가 한다. 물론 예외적으로 Reference variable에 null을 할당하거나, System.gc() 메서드를 호출하는 방법이 있다. 후자는 시스템 성능에 예기치 못한 영향을 미칠 수 있으니 사용하면 안 된다. Java objects는 heap에 위치한다. Heap이 생성되는 시점은 JVM이 시작될 때이며, heap의 사이즈는 애플리케이션이 구동하면서 증감한다....

July 10, 2022

백엔드 프레임워크와 UTF Encoding

백엔드 프레임워크 만들기 (개정판), 제로 - 인프런 에서 배운 내용을 정리한다. 컴퓨터를 사용하다 보면 아래와 같이 알 수 없는 문자를 본 적이 한 번쯤은 있다. 한글이 깨졌다. 궢귛귍귪궻귺긏긘깈깛 이런 난감한 상황을 막으려면 character set 기준을 정해야 한다. Character set: 사람의 문자 문자열을 컴퓨터의 문자 비트열로 저장하기 위한 규칙. Encoding: 문자열과 비트열간 변환 작업. Decoding: Encoding된 대상을 원본으로 되돌리는 작업을 의미한다. Character set에 맞춰 어떻게 encoding/decoding 할지 결정한다. character set에 맞지 않게 인코딩되면 데이터를 해석할 수 없다....

June 7, 2022

네트워크 상식

개발자에게 필요한 네트워크 상식 백엔드 프레임워크 만들기 (개정판), 제로 - 인프런 에서 배운 내용을 정리한다. 개발자라면 다음과 같은 문제에 대답할 수 있어야 한다. private IP 주소를 사용하는 외부 서버에 접속할 수 있는 방법 웹 브라우저의 MAC 주소를 알 수 있는 방법 IP 주소를 사용자 식별자로 사용할 수 있는 방법 80 포트를 사용하는 톰캣을 여러 개 실행할 수 있는 방법 나는 첫 두 개는 모르고 있었다. 갈 길이 멀다. private IP 주소를 사용하는 외부 서버에 접속할 수 있는 방법: public IP 주소를 할당받아야 함....

May 23, 2022

Abstract Class

Spring 은 IoC container 에 bean 객체를 생성한 후 그 객체를 등록한 후, 필요할 때 사용한다. Interface 는 객체를 생성할 수 없기 때문에 bean 이 될 수 없다. 그렇다면 Abstract Class 는 어떨까? 아래 코드를 보면 일단 bean 으로 등록할 수 없다. @RestController class Controller( val abstractService: AbstractService, ) { @GetMapping("/abstract") fun getAbstract() = abstractService.abstractFunction() } @Service abstract class AbstractService { fun abstractFunction() = "" } 아래와 같은 메시지가 뜨면서 애플리케이션이 멈춘다....

March 16, 2022