SookDev
🌳

DevFest 송도 2024 후기

목차

notion image
남편과 함께 연말을 맞아(?) 송도 2024 DevFest 에 다녀왔다.
13시부터 18시까지, 총 40개의 세션이 열렸는데, 각 시간마다 들을 수 있는 세션이 제한되었기 때문에 신중하게 골라야 했다. 남편과 데이트 겸 왔다고는 하지만 쿨하게 자기 갈 길 가는걸로.
영상제공이 따로 안되기 때문에 서로 잘 듣고 공유하기로 했다.
 
나같은 경우,
async await 구문은 어떤 원리로 비동기를 구현할까 Flex 를 알게되니 CSS Flex 가 공짜? Compose UI 조합 심화 선언형 UI 에서의 상태관리 글로벌 기업은 홈페이지에서 영어 번역을 어떻게 제공할까?
총 다섯개를 선택했다.
사실 두번째 시간의 DevRel 이 말하는 개발자의 문장력 세션을 듣고 싶었지만 사람이 많아 입장하지 못했다.💦
무료 멘토링 세션도 있었는데 행사를 너무 늦게 발견해서 이미 마감된 상태였다.
예상보다 사람이 많아 당황했고 이직 준비자로서 매우 아쉬운 부분.
 
내가 들었던 세션 중 인상깊었던 두가지 세션, Compose UI 조합 심화 와 글로벌 기업은 홈페이지에서 영어 번역을 어떻게 제공할까? 에 대해 간략히 기록하려고 한다.

1. Compose UI 조합 심화 (react compound component pattern)

얼마전 회사에서 공통컴포넌트를 합성컴포넌트(Compound Component)로 리팩토링한 과정을 글에 담았는데, 심화라고 하니 더욱 반가운 주제였다.
스피커 분께서 준비하신 기본 언어는 코틀린이었지만 컴포넌트 패턴 개념은 동일하게 적용되니 감안하고 들었다.
용어정리
Composition Compose UI 를 그리는 과정 중 하나가 아닌, 객체지향 프로그래밍에서 객체들을 조합하여 복잡한 기능을 구현하는 조합을 의미한다. 상속을 통한 재사용과 달리, 객체를 조합하여 구조를 설계하는 방식으로 유연성과 재사용성을 높일 수 있다. Component Jetpack Compose 의 UI 컴포넌트를 가리키며, 이는 하나의 컴포저블 (Composable) 함수 단위로 정의된다.

1-1 중복을 제거한 컴포넌트 분리

notion image
컴포넌트를 효율적으로 관리하려면 중복을 제거하는 것이 중요하다.
이를 통해 코드 재사용성을 높이고 유지보수를 용이하게 할 수 있다.

공유되는 부분을 유지

여러 곳에서 사용되는 공유되는 부분은 별도로 추출하여 재사용한다. 이를 통해 코드 변경을 최소화할 수 있다.

DRY 원칙

DRY 원칙은 중복을 피하고, 동일한 로직이나 구문을 반복하지 않도록 한다.
중복을 제거하면 버그를 줄이고, 가독성을 높이며, 변경 시 관리가 용이하다.

조건문 남발은 복잡도 증가

가장 직관적인 해결책은 조건문인데, 조건문을 과도하게 사용하면 컴포넌트의 복잡도가 증가한다.
다양한 경우를 처리하기 위해 조건문을 남발하다 보면, 코드가 점점 더 복잡해지고, 추후 유지보수나 변경이 어려워져 단일책임원칙을 위배할 수 있다.
DRY 원칙의 함정
  • 중복은 코드의 겉모습이 아닌, 코드 수정의 이유가 같은지에 따라 판단.
  • 만약 두 코드가 동일한 이유로 수정되어야 한다면 중복이지만, 수정되는 이유가 다르면 중복이 아님.
  • 컴포넌트 내 조건문 추가는 서로 다른 수정 이유를 갖는 컴포넌트들이 묶였다는 뜻.
    • 해당 로직은 재사용에 적합하지 않음
    • 변경에 유연하게 대응할 수 있는 UI 구조 필요

결론

중복을 제거하고 DRY 원칙을 따르되, 조건문은 최소화해야 한다.
이렇게 하면 컴포넌트의 복잡도를 줄이고, 유지보수성을 높일 수 있다.

1-2 컴포넌트 조합 아이디어 1 - Slot 패턴

Slot 패턴이란?

  • 특정 영역을 외부에서 자유롭게 구성할 수 있도록 하는 디자인 패턴
  • 컴포즈에서 컴포저블 람다를 함수 파라미터로 활용하여 구현
  • 부모컴포넌트는 자식컴포넌트의 구체적인 구현에 대한 의존성 없이 UI 구조를 정의하는 식으로 구현할 수 있음.
패턴 활용 사례로 Compose Material Design Components 를 들 수 있다.
Compose Material Design Components 가 뭔지 이해가 안가서 따로 찾아보니, 안드로이드 앱 개발에서 UI를 구성할 때, Compose 프레임워크 내에서 밑에 표시된 디자인 요소들의 컴포넌트를 구현하는 방법을 의미한다고 한다. 이렇게 구성된 컴포넌트 방식에서 대부분 slot 패턴을 쓴다고 한다.
notion image

Slot 패턴을 쓰기 좋은 상황

  • 컴포넌트의 유연함을 살려 다양한 UI 요구 사항에 대응하는 경우
    • Slot 패턴은 컴포넌트 내부에 동적인 콘텐츠를 삽입할 수 있도록 해주기 때문에, 다양한 UI 요구 사항을 충족할 수 있는 매우 유용한 방식이다.
      예를 들어, 특정 컴포넌트 내에서 위치나 스타일은 고정하되, 내부 콘텐츠만 변경해야 하는 경우에 적합하다.
  • 특히, 컴포넌트의 레이아웃 구조는 유지하면서 특정 영역의 콘텐츠만 변경해야 하는 경우
    • 컴포넌트의 구조는 그대로 두고, 그 안의 일부 콘텐츠만 변경하고자 할 때 Slot 패턴은 유용하다.
      예를 들어, 헤더와 푸터는 동일하되, 콘텐츠 영역만 다르게 보여주는 경우, Slot 패턴을 활용하여 유연하게 처리할 수 있다.

Slot 패턴의 한계

  • 요구사항이 추가될 때, UI 변경 사항이 발생할 때마다 SLOT을 추가해야 하는가?
    • 실제로 이래서 props drilling 이 늘어났지 ..
      실제로 이래서 props drilling 이 늘어났지 ..
      Slot 패턴을 사용하면 각 영역에 대해 콘텐츠를 삽입할 수 있으므로 매우 유연하지만, 요구사항이나 UI가 변경될 때마다 새로운 Slot을 추가해야 하는 상황이 발생할 수 있다.
      많은 Slot이 필요해지면, 컴포넌트의 사용 의도를 흐리게 할 수 있다.
  • 컴포넌트 API가 혼란스러워질 수 있음
    • 지나치게 많은 Slot을 정의하거나 복잡한 논리를 적용하게 되면, 코드가 과도하게 복잡해지고 관리하기 어려워질 수 있다.
  • 복잡한 로직일 경우, Slot 패턴 단독은 한계가 있다
    • Slot 패턴은 주로 단순한 UI 구성에 적합하지만, 복잡한 로직이나 상호작용을 필요로 하는 경우에는 한계가 있다. 예를 들어, 동적으로 변하는 상태나 복잡한 비즈니스 로직을 처리해야 할 때, Slot 패턴만으로는 모든 요구를 처리하기 어려울 수 있다.

1-3 컴포넌트 조합 아이디어 2 - Compound Component 패턴

Compound Component 패턴이란?

  • 하나의 컴포넌트를 여러 조각으로 나눈 후 , 외부에서 이들을 조합
  • 부모 컴포넌트가 상태를 관리, 자식 컴포넌트는 상태를 받아 UI 렌더링
    • 자식 컴포넌트들은 상태관리 로직에서 분리되어 UI 표현에만 집중
  • 리액트에서 Context API 통해 구현하는것이 일반적이지만, Compose에서는 Lamada Receiver 를 활용하여 구현 가능하다.
notion image
사진을 보면 작성된 코드만 다를 뿐, 컴포넌트를 알맞은 위치에 조합하는 것은 리액트와 동일하다.
하나의 큰 부모컴포넌트 내에 각각 독립적인 자식 컴포넌트들을 요구사항에 맞게 커스터마이징이 가능한 것이다.

Compound Component 패턴 특징

  • Scope 인터페이스 생성
    • 부모 컴포넌트는 상태 관리와 로직을 정의하는 스코프 인터페이스를 생성한다.
      이는 자식 컴포넌트들이 접근할 수 있는 범위를 제한하며, 컴포넌트의 상태나 로직을 캡슐화 한다.
  • 대상 리시버 지정
    • 부모 컴포넌트는 자식 컴포넌트들이 접근할 수 있도록 대상 리시버(state manager)를 지정한다.
      자식 컴포넌트는 이 리시버를 통해 상태를 읽고 업데이트할 수 있다.
  • 자식 컴포넌트(상태 접근)
    • 자식 컴포넌트는 부모 컴포넌트로부터 전달받은 상태를 직접 접근하거나, 필요한 이벤트 로직을 처리할 수 있다.
      자식 컴포넌트는 부모의 상태나 로직을 공유하지만, 부모 컴포넌트의 구현을 알지 못하고, 오직 인터페이스를 통해 상태에 접근한다.
  • 스코프 범위 내에서만 사용 가능
    • 부모 컴포넌트가 제공하는 스코프 범위 내에서만 자식 컴포넌트를 사용할 수 있다.
      이는 자식 컴포넌트들이 부모의 상태나 로직을 안전하게 공유할 수 있도록 하며, 다른 부분에서의 불필요한 접근을 방지한다.

Compound Component 패턴의 한계

  • 비즈니스 로직과 밀접하게 연결된 경우
    • 복잡도가 증가함에 따라 스코프 관리가 어려움.
      UI는 동일하지만 UI 에서 참조하는 클래스가 변경되는 경우 (Scope 인터페이스 수정, 관련된 모든 자식 컴포넌트에 영향)
  • 부모의 상태가 변경되더라도 자식들은 그 변경을 감지할 수 없는 경우가 있을 수 있다.
    • 컴포넌트의 상태가 자주 변경될 가능성이 있는 경우, State Wrapping 고려
  • 변경될 수 있는 상태를 들고 있는 scope interface 를 선언해야 하는 경우, 불안정한 상태로 인한 리컴포지션 트리거에 주의

Compound Component 패턴 사례 - Lazy lists

  • compose 기본적으로 레이아웃 scope 를 지정한 다양한 컴포넌트를 제공한다.
  • 대표적 : LazyColumn 과 LazyRow 같은 lazy 컴포넌트이다.
  • 이것들은 LazyListScope 를 활용하여 리스트 항목을 효율적으로 관리하고 구성한다.
( 코틀린 Jetpack Compose 에서 사용되는 리스트 컴포넌트다. 코틀린은 잘 모르지만 뭐 .. 이렇다고 한다. )

1-4 컴포넌트 조합 아이디어 정리

notion image

Slot 패턴과 Compound Component 패턴

  • 둘은 배타적인 관계가 아니라 상호 보완적 관계!
    • Slot 패턴은 컴포넌트 재사용성을 위한 기반마련, Compound Component 패턴은 이를 바탕으로 더욱 유연한 UI 구축 가능
  • stateless 컴포넌트는 ui 집중, stateful 은 상태 관리 로직 캡슐화
    • Compound Component 패턴은 이러한 Stateful 컴포넌트를 효과적으로 관리하고 활용할 수 있는 구조를 제공한다.

1-5 UI composition best practices

Steam video SDK

화상통화, 오디오 룸 및 라이브 스트리밍 앱을 구축하기 위한 SDK로, 코드가 오픈소스로 공개되어 있어 누구나 전체 코드 조회가 가능하다.
여기서의 모범사례를 보자면,
  • UI 조합 패턴으로 공유 상태와 개별 제어 동작을 UI 로직과 분리 할 수 있다.
  • 다양한 SDK 고객 요구 충족을 위해 Slot 형태로 UI 로 구성하여 유연한 커스터마이징 가능
  • Compound Component도 사용하여 유연하게 UI 컴포넌트 조합하고 확장
이곳의 오픈소스 프로젝트를 통해 디자인패턴과 소프트웨어 아키텍처를 비롯한 다양한 모범 사례를 무료로 보고 아이디어를 얻을 수 있는것이 핵심인 것 같다.

1-6 번외

조건문이 정말 나쁜가

  • 중복은 코드의 겉모습이 아닌, 코드 수정의 이유가 같은지에 따라 판단
핵심은 조건문 자체를 피하는것이 아니라, 조건문 남용으로 인해 발생하는 복잡성 증가를 경계해야한다.
UI behavior logic 과 같은 경우나 애니메이션 상태를 관리할 때에는 굳이 복잡한 패턴을 적용하는 것보다 단순한 조건문을 사용하는 것이 더 효율적일 수 있다.

중복이 정말 나쁜가

UI 개발에 지나치게 DRY 원칙에 집착하면 오히려 코드의 복잡성을 높이고 유연성을 떨어뜨릴수 있다.
예를들어, 나의 프로필과 다른 사람의 프로필 UI가 현재는 유사하지만, 미래의 비즈니스가 요구사항 변경에 따라 두 UI 가 완전히 다른 형태로 진화할 가능성도 있다.

1-7 결론

Simple is the Best
Slot 패턴과 Compound Component 패턴은 모든 상황에 적합한 해결책은 아니다.
때론 단순한 조건문이나 중복을 허용하는것이 더 나은 선택일 수 있다.
각 패턴의 장단점을 정확히 이해하고 컴포넌트의 역할과 책임, 예상되는 패턴을 고려하여 적절하게 쓰기
 
스피커 분께서 마지막 결론을 내려주시며 덧붙이셨다.
패턴이원칙중심 개발보다는 개발하다보니 이런 패턴이엇다 깨닫는게 더 좋다고.
패턴을 구현하기 위한 구현보다 적절한 도구로 사용되는것이 정답인 것 같다.

2. 글로벌 기업은 홈페이지에서 영어 번역을 어떻게 제공할까?

notion image
평소 관심있던 기업인 에어프레미아랩스의 프론트엔드 리더인 승민님께서 스피커로 나오셨다.
사실 팬심에 들어봤지만, 결론적으로 가장 유익했던 세션이 아닌가 싶다.
에어프레미아랩스는 에어프레미아 항공의 자회사로, 항공권 예약 및 관리에 대한 전반적인 부분을 담당한다.
다인종이 사용하는 사이트인 만큼, 다국어 관리는 비용으로도 이어지는 부분이라 꽤 오랜시간 고민하고 시행착오를 겪으며 지금의 다국어 번역이 완성되었다고 한다.
 

2-1 기존 다국어 관리방법과 개선 계획

기존 방법

보통 key-value 형식으로 다국어를 관리 한다고 한다.
  • Key-value 저장: 각 언어마다 동일한 key에 대응하는 value를 저장한다.
  • 언어 및 Key 값으로 접근: 사용자가 언어를 선택하면 해당 key-value 쌍을 로드해 페이지에 표시된다.
기존에는 Redis 같은 데이터베이스에 key-value 데이터를 저장하고, 이를 메모리에 올려 웹사이트에서 사용했다고 한다.

문제점 및 개선방향

  • key-value를 프론트에서 보기 어렵다
    • admin 에 직접 가서 봐야하니 코드 가독성이 하락한다.
    • → key-value 를 프론트에서 바로 볼 수 있도록 다국어 소스 다운로드하여 개선
  • 약관 같이 긴 문구도 문장 단위로 등록되어 있어 활용이 어렵다.
    • → static 장문은 마크다운(md) 로 관리하여 개선
  • 문구 변경 히스토리가 없다.
    • → 누가,언제,어떻게 변경했는지 히스토리 관리하여 개선
또한 직접 만들려면 key-value 서버관리, 값 접근 api, 어드민이 필요한데, 이는 복잡하고 리소스가 많이 소모되는 일이였다. (json/md 멀티포맷, 권한관리, 히스토리)
💡
솔루션을 쓰자
에어프레미아랩스는 이 모든것을 해결하기 위해 돈을 지불하고 솔루션을 쓰기로 했다고 한다.
Localize / crowdin 두개의 솔루션 중, 단순히 사용경험이 있는 직원이 있어 crowdin 을 선택했다고 했다.
하지만 crowdin은 세계에서 1~2를 다투는 솔루션이기도 하다.

2-2 Crowdin 으로 다국어 관리하기

source 관리, 번역 도구, 권한 관리, 자동화 도구

  • json(개발자는 이것을 선호), csv(운영팀은 이것을 선호), xml, md 다양한 포맷 지원 및 관리
  • key 가 없는 md 는 문장 단위로 번역할 수 있도록 잘라줌 (번역 에디터에서만 이렇게 보여줌)

권한 관리

매니저 수를 증가하기 위해서 돈을 많이냈어야 함.
owner, admin, developer .. 여기서 키 돌려썼다고 했다.

자동화 도구

  • API : 모든 어드민 작업 API 가능
  • CLI : 빌드 시 스크립트에 넣기만 하면 되서 용이함.ex - crowdin upload 명령어로 끗.
  • 플러그인 : 타 도구와 통합, 연계 → 슬랙으로 자동메세지 오도록 설정 및 피그마화면 문구들을 크라우딘 키와 매칭시켜주면 (귀찮긴함) 피그마에서 바꾸면 자동으로 크라우딘의 영어값으로 다 바뀜.
  • 기타기능 : AI 번역 제안(번역업체있을경우 유용, 에어프레미아는 번역업체가 있음), 스크린샷(key 에 스크린샷 등록), 진행관리(JIRA 처럼 todo 해서 태스크관리하지만 여기는 지라씀) 등등 제공

Crowdin 다국어 관리 프로세스

PO 가 한국어 소스 업로드 (CSV) → 번역 → 프론트에서 csv 다운로드, json 파싱 → 다국어 사용하기
CLI 로 받고 json 변환
기본적인 다국어 변환은 key value 가 기본이라 Next.js 로 가능.
언어판단
notion image
path 에 언어코드 포함
airpremia.com/ko/somePath airpremia.com/en/somePath
params :{lang:Locale} 넥스트에서 이렇게 동적으로 path 받아올수있다.
만약, 사용자가 ko 이렇게 정확하게 입력하지(path에 언어코드가 없으면) 않는다면 미들웨어를 통해 redirect 처리하도록 했다.

crowdin 단점

  • 마크다운에 html 넣으면 종종 버그가 발생.
  • key 생성 가능한 매니저 수 적음.
  • 문구 변경하려면 배포 필요.
    • 실시간 변경(over-the-air) 있지만 비싸다.
    •  
초기에 crowdin 은 유료지만, 다국어 관리에 매우 탁월한 툴이었다고 한다.
생태계도 크고 지원하는 것도 많아서 좋았지만 결국 문제는 자잘한 버그와 비용에 있었던 것 같다.

2-3 Strapi 로 Crowdin 단점 보완하기

에어프레미아랩스는 자체 제작없이 단점을 보완하기 위해 인스톨 headless CMS 인 Strapi 로 보완했다.
개인적으로 엔코위더스 재직할때 Next.js 에서 Strapi 에서 작성된 글을 가져온 적이 있어 괜시리 반가웠다.
또한 단순 글작성이 아닌, 다국어 관리에 접목시켜 해결했다는 점이 매우 놀라웠다.😲
💡
CMS(content management system) 콘텐츠 관리 시스템으로, 사용자가 디지털 콘텐츠를 생성, 관리, 저장, 수정할 수 있도록 지원하는 소프트웨어를 말한다. 대표적으로 워드프레스가 있다. Headless 디자인이나 프론트엔드 없이 콘텐츠만 관리하고 API를 통해 데이터를 서빙하는 시스템. 프론트엔드 디자인과 렌더링은 개발자가 원하는 방식으로 자유롭게 구현할 수 있다.
  • 빌드해서 다운받는게 아니라 스트라피에 복.붙해서 올린다.
  • 실시간 적용가능
  • 매니저 수 무제한
  • 우리 인프라에서 제공하니 비용이 싸다.

변경된 관리방식

crowdin 통해 다국어 json,md 받기는 유지 → 스트라피에 복.붙 → 프론트에서 스트라피에 api 요청해서 다국어 받고 사용

단점

  • 복붙이 귀찮다.
  • 소스가 crowdin, Strapi 두개라서 혼선이 있다.
  • crowdin↔strapi 간 동기화 플러그인이 있긴 하다. 이것으로 시도 예정이라고 하셨다.(무료임)
  • 스트라피도 결국 서버이기 때문에 트래픽관리가 필요하다
    • 모든 문구 서빙 시 (서비스 트래픽 * N) 의 부하가 생길 수 있다.

2-4 결론

승민님께서 말씀하고자 하시는 핵심은,
어느 솔루션을 쓰냐가 아닌 “문제를 해결하기 위해 솔루션을 쓰는 방법이 효율적일 수 있다” 를 강조하신것 같다.
crowdin 을 쓰든, strapi 를 쓰든 장점과 단점은 분명히 존재하고 정답은 없다.
단, 문제를 어떻게든 해결하기 위해 솔루션에 먼저 접근하고, 점차 그 비용을 최소화 하기 위해 개선하는 것이 중요한 것 같다.
🔥 나도 문제를 해결할 때 시야를 넓히고 다양한 툴을 도전해보도록 해야할 것 같다.

2-5 번외

아무래도 전직이 항공사 지상직이기도 하고 항공업계에서 너무나도 귀한 IT 회사였기에 평소에도 너무나도 관심있게 본 회사 중 하나였다.
근데 여기 .. 프론트엔드만 채용을 안해요오 ..
사실 개발바닥 유튜브에 나오신 승민님 영상만 봐도 “백엔드가 너무 모자르다” 를 강조하셔서 안뽑을걸 알았지만 직접 대면하니 미련을 버릴 수 없었다.
쉬는시간마다 에어프레미아 예약사이트 들어가서 개발자도구 열고 괜시리 개선할 사항만 엄청 찾았다.
혼자서 Next.js 로 사이트 일부를 개선해서 포트폴리오로 제출하는 상상까지 했다.
(나는 상상력 만렙, 완벽한 INFJ 임.)
에어프레미아 예약 사이트 Lighthouse 보는중 ..
에어프레미아 예약 사이트 Lighthouse 보는중 ..
세션이 끝나자마자 승민님께 쪼로로 달려가 10초 자기소개를 하고, (나 항공사 지상직 출신 프론트엔드인데 시전)
프론트엔드 채용 계획이 있으시냐고 여쭤봤더니 예상 그대로 없다고 하셨다. 대신 백엔드가 많이 모자른다고 하셨다.
그렇게 확인사살을 받고나서, 아까 홈페이지를 보고 흥분된 마음을 조금 가라앉힐수 있었다.
(이미 채용되서 일하는 상상까지 했걸랑요.)
하지만 언젠가 프론트엔드 채용이 생길 그날을 위해 열심히 공부하고 기술을 연마하기로 마음먹었다.
들어가면 진짜 재밌게 일할거같은데 .. 그럴거 같은데 ..
 
미련을 덕지덕지 남기며 DevFest 후기 끝!
 

참조
🔗 Devfest Incheon / Songdo 2024