[LUCYTATO] 20240309 스터디 정리: Reactive Programming과 GitFlow

스터디 주제

오늘의 핵심 주제는 Spring Webflux와 Reactive Programming, Git의 운영 방식, AOP(Aspect-Oriented Programming), 그리고 특정 프로젝트 내용의 최적화 방안에 대한 심층 분석이다.

Spring WebFlux와 Reactive Streaming

리액티브 프로그래밍은 비동기 데이터 처리와 이벤트 기반 시스템의 효율성을 극대화하는 프로그래밍 패러다임이다. 특히, 리액티브 프로그래밍의 ‘Non-blocking IO’ 특성은 시스템의 처리량과 응답성을 대폭 향상시킨다. PUB/SUB 모델을 기반으로 하는 이 패러다임은, 데이터가 준비될 때까지 기다리는 대신, 데이터가 방출되는 즉시 이를 구독하고 처리함으로써, 애플리케이션의 확장성과 반응성을 높일 수 있다. Spring WebFlux에서는 MonoFlux와 같은 리액티브 스트리밍 타입을 통해 실현되며, 이들을 사용하여 다양한 데이터 처리 시나리오를 지원한다.

기준Reactive Programming(반응형 프로그래밍)Imperative Programming (명령형 프로그래밍)
처리 방식비동기적, 데이터 스트림과 이벤트에 의존동기적, 명령어의 순차적 실행에 의존
프로그램의 흐름데이터 흐름과 변화의 전파에 중점명령어의 명시적인 흐름 제어
대응 모델PUB/SUB 모델, 구독자가 데이터의 변화를 감지하고 반응직접적인 함수 호출로 결과를 반환
사용 사례고성능 비동기 처리가 필요한 어플리케이션, 실시간 데이터 처리일반적인 어플리케이션, 순차적 로직이 중요한 경우
주요 이점확장성, 비동기 처리, 반응성단순성, 직관적인 코드 흐름, 쉬운 디버깅
Reactive Programming vs Imperative Programming

Git Flow / Github Flow / GitLab Flow

  1. Git Flow: 기능 개발 시 feature 브랜치에서 작업 후 develop으로 병합. 릴리스 준비 시 release 브랜치를 생성하고, 완료 후 masterdevelop에 병합. 긴급 수정 필요 시 hotfix 브랜치 사용.
  2. GitHub Flow: 모든 개발 작업을 feature 브랜치에서 진행 후, 코드 리뷰를 거쳐 master 브랜치에 직접 병합. 단순하고 지속적인 배포를 지원.
  3. GitLab Flow: feature 브랜치에서 개발, master 브랜치로 병합. 환경 별로 production, staging 등의 브랜치를 사용하여 배포 관리. GitLab CI/CD와 통합하여 더 효율적인 배포 프로세스 구현.

Flow별 장단점

  • Git Flow: 복잡한 릴리스와 핫픽스 관리에 강점. 구조가 복잡하고 학습 곡선이 있음.
  • GitHub Flow: 단순성과 빠른 배포에 유리. 복잡한 릴리스 관리에는 한계.
  • GitLab Flow: 유연성과 보안성이 강점. 설정과 관리에 더 많은 노력이 필요.

Flow별 배포 및 버저닝

  • Git Flow: release 브랜치에서 버전을 관리하고, master로 병합 시 태그를 사용하여 버전을 명시.
  • GitHub Flow: master 브랜치에서 직접 배포. 배포 시점에서 태그를 사용해 버저닝.
  • GitLab Flow: 환경 별 배포 브랜치를 통한 배포 관리. 필요에 따라 태그를 사용하여 버저닝.

참고자료

rebase? squash?

Git에서는 효율적인 버전 관리와 협업을 위해 rebasesquash 같은 기능을 활용한다.
rebase는 중복 커밋 없이 타겟 브랜치에 변경 사항을 통합하는 방법으로, 깔끔한 커밋 히스토리를 유지하게 돕는다. 반면, squash는 여러 커밋을 하나로 합쳐 메세지를 단순화한다.

LUCYCATO 프로젝트 코드 분석

프로젝트 링크

  • LoggingAspect
@Aspect
@Component
@RequiredArgsConstructor
public class LoggingAspect {
    private final LoggingProducer loggingProducer;

    @Before("execution(* org.lucycato.*.adapter.in.web.*.*(..))")
    public void beforeMethodExecution(JoinPoint joinPoint) {
        // * Mono: 0 ~ 1개를 방출, Flux: 0 ~ N개 방출
        // * 즉 Mono는 1개 방출 후 dispose 된다 (방출 후 dispose 된다는 것은 메모리 누수가 발생을 안한다.)
        Mono.just(joinPoint.getSignature().getName())
                .flatMap(methodName -> loggingProducer.sendLogMessage("logging", "Before executing method: %s".formatted(methodName)))
                .subscribe();
    }
}

Spring Boot에서 @Aspect는 AOP의 핵심으로, 반복되는 보조 로직을 최소화할 수 있는 도구이다. @Aspect를 적용한LoggingAspect는 AOP를 통해 로깅 로직을 애플리케이션 전반에 걸쳐 쉽게 적용할 수 있게 해준다.

  • ObjectMapperConfig

프로젝트 내부에서, ObjectMapper = new ObjectMapper()로, 객체를 사용하는 것이 아니라, ObjectMapperConfig의 생성과 커스텀 ObjectMapper을 Bean에 등록함으로써 JSON 객체 변환 시 발생할 수 있는 타입 오류를 방지한다. 이를 통해 데이터의 안정성과 신뢰성을 보장한다

public class ObjectMapperConfig {
    @Bean
    public ObjectMapper objectMapper() {
        com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();

        objectMapper.registerModule(new Jdk8Module());

        objectMapper.registerModule(new JavaTimeModule());

        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.LowerCamelCaseStrategy());

        return objectMapper;
    }
}
  • 커스텀 어노테이션, @ProducerAdapter
package org.lucycato.common.annotation.out;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ProducerAdapter {
    @AliasFor(annotation = Component.class)
    String value() default "";
}

@ProducerAdapter 같은 커스텀 어노테이션을 통해 헥사고날 아키텍처 내에서 데이터가 어떤 경로로 이동하는지 명확히 할 수 있다.

[LUCYTATO] 20240309 스터디 정리: Reactive Programming과 GitFlow

댓글 남기기

Scroll to top