Gradle로 멀티 모듈 환경 구성하기

토이 프로젝트를 진행하면서 크롤링 애플리케이션, 조회 애플리케이션을 나누어서 개발하는 상황이 필요했다. 이 때, 두 애플리케이션에서 공통으로 사용되는 엔티티들이 일부 존재했다. 두 애플리케이션에서 공통으로 사용되는 엔티티의 코드를 복사, 붙여넣기로 구현할 수도 있지만 이럴 경우 엔티티의 수정이 있을 때 두 코드에 매번 똑같이 적용해야 되기 때문에 불편함이 있었다. 이를 해결하기 위해 멀티 모듈을 사용해보기로 했다. 구성 hy-notice-core: 두 애플리케이션에서 공통적으로 사용되는 엔티티들을 담고있는 모듈 hy-notice-client: 크롤링에 필요한 로직을 구현 해놓은 모듈 hy-notice-api: 크롤링한 데이터를 조회하기 위해 필요한 api들을 구현 해놓은 모듈 방법 1....

2024-09-15 · 2 min · 347 words

given vs when

목표 mockito의 given과 when 함수의 차이점을 이해한다. Mockito vs. BDDMockito 기본적으로 given과 when함수의 동작은 같다. 둘 다 특정 객체를 목킹하여 함수의 동작을 정의할 때 사용할 수 있다. given은 when을 BDD 스타일로 작성할 수 있도록 만든 함수다. given은 BDDMockito에 정의되어있고, when은 Mockito에 정의되어 있다. BDDMockito는 Mockito 를 상속한 클래스다. BDD(Behavior Driven Development) TDD의 한 종류로 시나리오를 기반으로 테스트 케이스를 작성하여, 개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 테스트 코드를 작성하는 것이다....

2024-09-15 · 1 min · 117 words

Github의 GPG key가 무엇인가

목표 GPG가 무엇인지 알아본다. Github의 verified commit이 무엇인지 알아본다. Github에서 GPG key가 무엇인지 알아본다. GPG란 GPG는 GNU Privacy Guard의 약자로, 파일을 암호화하여 전송할 수 있는 툴이다. GPG는 여러가지 암호화 기술을 제공하지만 기본적으로 RSA 암호화를 사용한다. Github에서 verified commit이 무엇인가? 레포지토리에 커밋을 push할 때, 마치 다른 사람이 커밋한 것처럼 위조할 수 있는 문제점이 있다. git config --global user.name junroot git config --global user.email junroot0909@gmail.com 위의 명령어로 현재 커밋하는 사람의 이름과 이메일만 바꾼다면 쉽게 위조가 가능하다....

2024-09-15 · 1 min · 141 words

Github Actions 개념 이해하기

목표 GIthub Actions를 사용하기 위한 기본 개념을 이해한다. 개념 Workflow 한 개 이상의 job이 실행되는 자동화된 과정 .github/workflows 디렉토리에 yaml 파일로 정의할 수 있다. workflow가 다른 workflow를 참조할 수도 있다. Event workflow 실행을 트리거하는 레포지토리 내의 활동 pull request, issue, push 등 Job 같은 runner에서 실행되는 step의 집합 job들 간에는 기본적으로 의존성이 없고 병렬로 실행된다. 만약 job이 다른 job에 의존성을 설정하면, 의존하는 job이 완료될 때 까지 실행을 기다린다. Step 실행될 수 있는 셸 스크립트 또는 action 각 step은 순차적으로 의존성을 가지고 실행된다....

2024-09-15 · 1 min · 146 words

Git 시작하기

Git이란 버전관리 도구 리누스 토발즈, 2005년 Git 실습 macOS 기준 macOS는 기본적으로 설치되어 있다. sudo brew install git 설치 후 설정 git config --global user.name "MY NAME" git config --global user.email "MY EMAIL" 기존 프로젝트를 git으로 관리하고 싶을 때 git init 새로운 디렉토리를 생성하여 git 저장소를 만들 때 git init (directory path) 파일 상태 확인하기 git status git 파일 관리를 위한 3가지 영역 git directory: 프로젝트의 메타데이터와 객체 데이터베이스를 저장하는 곳 (....

2024-09-15 · 4 min · 704 words

getDeclaredMethods() 와 getMethods() 차이

getDeclaredMethods()는 해당 클래스로부터 직접 정의한 모든 메소드(protected, private 포함)를 반환된다. 하지만 getMethods()는 public 메소드만 반환하지만 부모 클래스로부터 정의된 메소드도 함께 반환된다. https://stackoverflow.com/questions/43585019/java-reflection-difference-between-getmethods-and-getdeclaredmethods

2024-09-15 · 1 min · 22 words

Gatling을 이용한 성능 측정기

시작 하기 Gatling의 시작 방법은 단순하다. 링크에서 압축 파일을 받아서 풀면된다. 주로 유저 시나리오 코드를 user-files/simulations 경로에 넣어두고 bin/gatling.sh 를 통해 실행시키면 된다. 시나리오 작성 하기 시나리오 코드를 작성하고 싶은데 엄청 간단한 툴이 있었다. Gatling에서 Recorder라는 애플리케이션을 제공해주는데 이를 이용하면 아래 두 가지가 가능하다. 브라우저 작업을 추적해 시나리오 코드 작성 HAL 파일을 통해 시나리오 코드 작성 나 같은경우 1번 방법을 사용하면 HTTPS의 웹사이트는 추적이 불가능 한 경우가 있어서 2번 방법을 사용했다....

2024-09-15 · 3 min · 638 words

File 경로 찾기

String resourceName = "example_resource.txt"; ClassLoader classLoader = getClass().getClassLoader(); File file = new File(classLoader.getResource(resourceName).getFile()); String absolutePath = file.getAbsolutePath(); System.out.println(absolutePath); assertTrue(absolutePath.endsWith("/example_resource.txt")); ClassLoader를 사용하면 classpath에서 해당 파일의 위치를 찾는다. 서브 디렉토리까지 찾지 않는 점의 유의해야된다. 참고 자료 https://www.baeldung.com/junit-src-test-resources-directory-path

2024-09-15 · 1 min · 35 words

FactoryBean

상황 코드에서 FactoryBean이라는 인터페이스를 빈으로 등록하는 부분이 있었는데, 어떤 용도인지 궁금했다. Factory Bean의 역할 다른 Bean을 생성하고 Spring IoC 컨테이너에 등록하는 Bean이다. 사용 예시 JndiObjectFactoryBean: JNDI에서 데이터 소스를 조회하는데 사용 ProxyFactoryBean: AOP를 사용하여 bean에 대한 프록시를 생성하는데 사용 Factory Bean 생성하는 방법 FactoryBean 인터페이스의 구현체를 빈으로 등록한다. AbstractFactoryBean을 확장한다. 이 추상 클래스는 getObjectType()과 createInstance() 메서드만 구현하면된다. 해당 추상 클래스에서는 싱글톤 패턴을 사용하고 있어 쉽게 싱글톤으로 빈을 관리할 수 있게해준다. 참고 자료 https://www....

2024-09-15 · 1 min · 72 words

express에서 request body 가져오는 법

express에서 POST 요청의 request body를 가져오지 못하는 문제가 있었다. 이를 해결하기 위해서는 express가 body 정보를 parsing할 수 있도록 별도의 설정을 해야된다. body-parser이라는 패키지를 가져와서, express app에서 사용하도록 설정해준다. 여기서 body-parser는 이름과 같이 raw body를 가져와서 파싱을 해준다. 나는 json content-type의 body 정보를 가져올 것이기 때문에 아래와 같이 설정했다. 다른 content-type을 사용할 경우에는 아래와 동일한 방법으로 추가해줄 수 있다. const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app....

2024-09-15 · 1 min · 71 words

ExecutorService 이해하기

목표 ExecutorService의 역할을 이해한다. ExecutorService의 대표적인 메서드를 이해한다. Runnable 스레드에 의해 실행될 작업을 나타내는 함수형 인터페이스 void run() 메서드를 가지고 있다. Executor Runnable 작업을 실행시켜주는 인터페이스 실행 작업과 각 작업이 실행되는 메커니즘(스레드 사용, 스케쥴링 등)을 decoupling 시켜주는 인터페이스이다. 일반적으로 executor에서 실행되는 작업은 다른 스레드에서 실행된다. class ThreadPerTaskExecutor implements Executor { public void execute(Runnable r) { new Thread(r).start(); } } 하지만 Executor의 구현체가 항상 비동기나 다른 스레드로 실행되어야 한다는 제한은 없다. class DirectExecutor implements Executor { public void execute(Runnable r) { r....

2024-09-15 · 2 min · 355 words

Enum을 JPA로 저장 하기

@Enumerated 구현 자체는 간단하다. 필드에 @Enumerated 어노테이션을 붙여주면 된다. @Entity public class Article { @Id private int id; private String title; @Enumerated(EnumType.ORDINAL) private Status status; } 하지만 속성 값을 어떻게 주냐에 따라 두 가지로 나뉜다. ORDINAL 위 코드 예시와 같이 ORDINAL을 속성으로 주면, Enum.ordinal() 값을 DB에 저장하는 방식이다. enum의 순서가 바뀌면 기존에 DB에 저장되어 있는 값과 충돌하는 문제가 있다. STRING @Enumerated(EnumType.STRING) 로 저장하게되면 Enum.name() 값을 DB에 저장하게 된다. enum의 순서가 바뀌어도 문제가 없다....

2024-09-15 · 2 min · 422 words

EnumSet

목표 EnumSet 의 정의 EnumSet의 장단점 EnumSet 정의 enum 클래스에서만 사용할 수 있는 Set 이다. null 값을 추가하면 NPE가 발생한다. 스레드로부터 안전하지 않다. 내부 구현 비트 벡터를 사용해서 각 enum의 포함 여부를 저장한다. EnumSet.of() 등을 통해서 생성하면, enum 값의 개수에 따라 두 가지 구현이 존재한다. RegularEnumSet: long 타입을 통해서 저장하며, long은 64비트 타입이므로 64종류를 저장할 수 있다. JumboEnumSet: long의 배열을 통해서 저장하며, 64개 이상의 종류를 저장할 수 있다. 장단점 장점 모든 연산이 비트 연산을 사용하기 때문에 처리 속도가 빠르다....

2024-09-15 · 1 min · 132 words

Enum 생성자에서 companion object 함수 호출

배경 개발 중인 프로젝트의 kotlin 버전을 1.5.30에서 1.9.0으로 올렸는데, 컴파일 에러가 발생했다. 에러 내용은 Companion object of enum class ... is uninitialized here 으로, 아래 사진과 같이 enum의 생성자 부분에서 enum class의 companion object 함수를 호출하지 못하고 있었다. 원인 분석 kotlin 1.9.0 이전 버전에서 이런 구조는 런타임에 NullPointerException나 ExceptionInInitializerError가 발생할 가능성이 존재했다. kotlin 1.9.0 에서 이를 해결하기 위해 컴파일 타임에 enum 생성자에서 companion object를 호출하는 것을 막도록 수정되었다. 참고 자료 https://kotlinlang....

2024-09-15 · 1 min · 72 words

Enum class의 entries 프로퍼티

목표 Enum 클래스의 entries 프로퍼티가 무엇인지 이해한다. 기존에 있던 Enum values() 메서드와 차이점을 이해한다. entries kotlin 1.9.0부터 enum 모든 값을 반복해서 처리하고 싶은 경우 entries 프로퍼티를 사용할 수 있다. CardType.entries.forEach { println(it.code) } values()와 차이점 values() 호출시마다 배열을 생성하고 복제한다. (상대적으로 성능이 나쁨) mutable 하다. Array 타입 반환으로 kotlin의 확장 함수를 사용하기 불편하다. entries 미리 생성된 리스트를 반환한다. immutable List를 상속한 EnumEntries를 반환하여 kotlin의 확장 함수들을 사용하기 용이하다. 참고 자료 https://www....

2024-09-15 · 1 min · 73 words

embedded-redis macOS 호환성 문제 해결

배경 통합 테스트에서 로컬 환경을 위한 embedded-redis 를 사용하고 있었다. 다른 사람 환경에서는 테스트가 통과하는데, 내 컴퓨터에서는 아래와 같은 에러로 테스트가 실패했다. java.lang.RuntimeException: Can't start redis server. Check logs for details. at redis.embedded.AbstractRedisInstance.awaitRedisServerReady(AbstractRedisInstance.java:61) at redis.embedded.AbstractRedisInstance.start(AbstractRedisInstance.java:39) at redis.embedded.RedisServer.start(RedisServer.java:9) 원인 macOS 14 Sonoma 에서 it.ozimov embedded-redis 0.7.3 기준으로 redis server 실행이 실패하고 있었다. https://github.com/kstyrc/embedded-redis/issues/135 macOS 14 를 지원하는 redis server 바이너리가 해당 라이브러리 내에 존재하지 않기 때문에 발생하는 이슈다. 해결 해당 라이브러리가 2020년 이후로 커밋이 끊긴 상태여서, redis server 바이너리 파일을 직접 받아서 실행하도록 수정했다....

2024-09-15 · 1 min · 191 words

Elasticsearch 시작하기

Elasticsearch 내부 동작을 이해한다. Elasticsearch에 새로운 컬럼?을 추가해본다. 구조 데이터 색인 색인(indexing): 데이터가 검색될 수 있는 구조로 변경하기 위해 원본 문서를 검색어 토큰들로 변환하여 저장하는 과정 인덱스(index): 색인을 거친 결과물, 또는 색인된 데이터가 저장되는 저장소. Elasticsearch에서 도큐먼트들의 논리적인 집합을 표현하는 단위이기도 하다. 검색(search): 인덱스에 들어있는 검색어 토큰들을 포함하고 있는 문서를 찾아과는 과정 질의(query): 사용자가 원하는 문서를 찾거나 집계 결과를 출력하기 위해 검색 시 입력하는 검색어 또는 검색 조건 Elasticsearch 환경 설정 config/jvm....

2024-09-15 · 6 min · 1166 words

EJB, Java Bean, POJO, Spring Bean

EJB(Enterprise JavaBeans): J2EE(Java EE)가 자바 웹 애플리케이션 시장을 차지하고 있을 때, 사용되었던 애플리케이션측의 컴포넌트 모델. 여기에는 Session Bean, Entity Bean, Message-driven Bean 등이 있다. 하지만 이는 객체지향적이지 못하고 특정 환경/기술에 종속적이라는 단점이 있다. Java Bean: J2EE(Java EE)에서는 데이터를 표현하기 위해서 어떤 규약을 지켜야했다. 이 규약을 Java Bean이라고 부른다. POJO: 위의 EJB의 단점을 지적하여 일반 자바 객체로 비즈니스 로직을 구현하자는 주장이 만들어졌다(마틴 파울러). 이 때 이 자바 객체를 POJO라고 부른다. Spring Bean: 컨테이너에 의해서 생명주기가 관리되는 객체로 이 때 객체를 POJO 형식을 따르고 있다....

2024-09-15 · 1 min · 83 words

EhCache 알아보기

목표 EhCache가 무엇인지 이해한다. EhCache가 다른 캐싱 기술과 어떤 차이점이 있는지 이해한다. EhCache를 사용 방법을 이해한다. EhCache란? Java 기반의 오픈 소스 캐시다. 메모리, 디스크 저장, 리스너, 캐시 로더, RESTful API, SOAP API 등을 지원한다. EhCache? Redis? EhCache, Redis 여러 형태의 캐시 기술이 존재한다. 각 기술의 특징을 비교해본다. EhCache Java에서만 사용할 수 있고, 객체를 단순 직렬화해서 저장하는 형태다. 기본적으로 로컬 환경에서 메모리에 데이터가 저장된다. Redis 미리 정의된 데이터 구조(String, List, Set 등)에 따라 데이터를 저장한다....

2024-09-15 · 2 min · 359 words

EC2 vs Lightsail

Lightsail 컴퓨팅, 스토리지, 네트워킹 및 DNS를 제공하는 VPS(가상 사설 서버)다. VPS는 하나의 물리서버를 여러 개의 가상 서버로 쪼개서 사용하는 것을 의미한다. 그래서 하나의 물리 서버를 여러명의 클라이언트와 나누어 쓰게된다. 하지만 나누어진 서버들은 독립 적인 서버 공간을 가진다. EC2와 다른 점 Lightsail 인스턴스는 실제로 t2클래스의 EC2 인스턴스다. 하지만 Lightsail은 여러 가지 기능이 간소화 되어있다. 고정된 EBS SSD 볼륨 중지되어도 청구되는 요금 유연하지 않은 보안 그룹 Lightsail을 사용해야되는 경우 단순한 인프라 구조를 가지는 경우에 유리하다....

2024-09-15 · 1 min · 99 words