DMS Android 리팩토링을 시작하며

DMS Android 리팩토링 계획에 대해서 소개합니다.

Junsu Park
Team Aliens

--

들어가며

안녕하세요, Team Aliens에서 DMS Android 개발에 참여하고 있는 박준수입니다.

프로젝트에 참여하면서, 코드 리팩토링을 경험해 보신적이 있으신가요? 이 글에서 Team Aliens에서 개발하고 있는 DMS의 Android 리팩토링 작업에 대해 소개해 드리려 합니다.

리팩토링에 대한 의견

코드 품질 vs 개발 속도

기존에 저희 서비스를 개발할 당시, 바쁜 학교 일정과 빠듯한 스프린트 기간으로 코드 품질보다는 개발 속도를 우선시 할 수밖에 없었습니다. 그렇게 다른 팀원 분들께서 인수인계를 받았고, 프로젝트에 새로운 기능을 추가할 때마다 코드가 복잡하다는 것을 계속해서 인지할 수 있었고, 기능들에 대한 버그를 수정할 때도 거듭 어려운 작업임을 느낄 수 있었습니다. 또한, 코드 컨벤션이 존재하지 않아 프로젝트 내 sign in, login 등을 함께 사용하는 등의 용어 문제 등이 발생하였습니다.

리팩토링

리팩토링 제안

수평적이고 자유로운 팀 분위기 덕분에, 팀에 갓 들어온 신입인 제가, 선뜻 리팩토링 진행에 대한 의견을 낼 수 있었습니다.

정말 감사하게도, Android 팀원분들 모두, 리팩토링에 대한 긍정적인 의견을 주셨고, 오히려 열정적으로 구체적인 작업 내용들을 제안해 주신 덕에, 제 단촐한 의견을 말씀드렸을 때 더욱 구체적이고 개선된 아이디어로 바뀔 수 있었습니다.

리팩토링 계획

의존하는 다른 모듈이 적은 레이어(또는 모듈)을 우선시하여, 모듈 하나하나의 단위로 리팩토링을 진행하기로 하였습니다. DMS Android 프로젝트를 기준으로, domain -> data -> presentation -> .. 순으로 진행할 계획입니다. 또한, 기존에 체계가 잡혀져 있지 않던 코드 컨벤션을 위해, 정기적으로 컨벤션 회의를 하고 있습니다. 또한, 앞서 언급한 용어 통일 등의 문제 해결을 위해 DMS Lint 제작을 계획중에 있습니다.

무자비한 4월 DMS Android 개발 계획

코드 작성

기존 코드 옆에 새로 코드를 작성하여, 기존 코드와 새 코드가 공존하도록 하는 방법을 선택하였습니다. 이와 같이 리팩토링을 진행할 경우,

  • 기존 코드에 대한 변경이 존재하지 않습니다. 예를 들어, domain 레이어의 기존 코드에 변경이 발생할 경우, 해당 코드를 참조하고 있는 다른 레이어의 변경을 요하기 때문에, 모듈 단위의 리팩토링이 어렵습니다.
  • 리팩토링 진행 중, 기존 코드에 새로운 기능을 추가할 수 있습니다. 현재 리팩토링이 진행되고 있는 중에도, DMS에는 새로운 기능이 계속 추가되고 있습니다. 기존 코드와 새 코드가 공존하는 방법을 선택하여, 새로운 기능이 추가되었을 때 기존 코드에서 대처할 수 있습니다.
  • 새로운 컨벤션을 적용한, 기존 코드 스타일과 연관이 적은 새로운 코드를 작성할 수 있습니다. 기존 코드를 수정하게 되면, 개발자가 작성된 코드를 바탕으로 코드를 수정하여 컨벤션에 어긋나는 코드를 작성할 수도 있습니다.

위와 같은 이점이 존재합니다.

기존 코드와 식별을 위해, 새로 작성한 코드는 패키지 이름 앞에 _를 붙여 구분하였습니다.

간단한 회의

가벼운 질문, 또는 한 이슈 내에서 코드를 작성하던 중, 팀원 모두가 알아야 하는 부분은 페이스북 메신저 등으로 가볍게 질문 및 확인하였습니다.

아키텍처

기존 아키텍처

  • data 레이어의 remote, local로의 관심사 분리가 미흡하다고 판단되었습니다.
  • domain과 local_domain이 공존하는 이유를 찾을 수 없었습니다.
  • local_domain, local_database를 data 레이어의 하위 계층인 local로 구성하여, 관심사를 분리할 수 있다고 판단되었습니다.

새로운 아키텍처

  • data 레이어와 remote, local을 각각 분리하여, data 레이어가 remote, local 중 소스를 선택하여 사용하도록 구현하였습니다.
  • local_domain을 제거하였습니다.
  • local_domain, local_database와 관련된 로직을 모두 local 레이어에 포함하였습니다.

domain

DMS Android의 모든 비즈니스 로직의 추상 클래스를 가지고 있으며, 그리고 앱 전체에서 사용하는 domain model(다이어그램 상으로는 domain entity 및 param)을 포함하고 있는 계층입니다.

  • usecase : Sign in, Fetch notices 등 각 비즈니스 로직을 나타냅니다.
  • repository : usecase에 의해 호출되어 실질적인 비즈니스 로직을 수행합니다.
  • domain model(다이어그램 상으로는 domain entity, param) : DMS Android 프로젝트 내에서, usecase의 함수 파라미터 또는 반환 타입, 또는 core model 등, 공통적으로 사용되거나, 비즈니스 로직을 나타내는 클래스입니다.
  • exception : 애플리케이션 실행 중 발생할 수 있지만 개발자가 handling 가능한 예외를 정의합니다.

data

domain의 repository 인터페이스를 구현한 구체 클래스를 포함하고 있으며, 해당 구현체가 실제 동작하기 위해서 생성자 주입받는 remote, local datasource 인터페이스를 포함하고 있습니다.

  • repository impl : domain 레이어에서 정의한 repository 인터페이스를 구현한 구체 클래스입니다.
  • remote datasource : remote 데이터의 source를 정의한 인터페이스입니다.
  • local datasource : local 데이터의 source를 정의한 인터페이스입니다.

remote

data 레이어보다 세부적인, 즉 낮은 수준의 remote 로직을 포함하고 있으며, Retrofit, OkHttp 등의 Http Client 라이브러리를 사용하여 서버에 API 요청을 보냅니다.

  • remote datasource impl : data 레이어에서 정의한 remote datasource 인터페이스를 구현한 구체 클래스입니다.
  • api : Retrofit, OkHttp를사용하여, 서버와 약속된 명세를 바탕으로 API 요청을 보냅니다.
  • interceptor : OkHttp Client로부터 API 요청을 intercept하여, 헤더에 토큰 삽입, 토큰 재발급 등의 작업을 수행합니다.
  • api request/response : API 요청을 처리하기 위해 remote에서만 존재하는 model 클래스입니다.
  • mapper : remote model과 domain model 간의 상호 변환을 위한 확장 함수입니다.
  • exception handler : 서버와의 통신에서 발생하는 HTTP 오류를, 그에 상응하는 DMS Android의 domain에 정의된 exception으로 변환합니다.

local

data 레이어보다 세부적인, 즉 낮은 수준의 local 로직을 포함하고 있으며, Room, DataStore 등의 라이브러리를 사용하여 디바이스의 Local Storage에 크거나 적은 용량의 값을 저장, 조회합니다.

  • local datasource impl : data 레이어에서 정의한 local datasource 인터페이스를 구현한 구체 클래스입니다.
  • database : Room Database 및 관련 컴포넌트의 모음으로 구상하였으나, DataStore 등의 사용을 위해 추후 명명을 변경할 예정입니다.
  • local entity : Room Entity 등, local 라이브러리에서 사용하는 model입니다.
  • mapper : local model과 domain model간의 상호 변환을 위한 확장 함수입니다.

presentation

사용자에게 보여지는 화면을 구현하는 레이어입니다.

  • viewmodel : domain의 usecase, model을 참조하며, 사용자로부터 action을 받아 domain의 비즈니스 로직을 호출하거나, 받아온 데이터를 필요에 맞게 가공합니다.
  • state : 한 화면에서 사용자에게 표시되어야 할 모든 데이터의 집합입니다.
  • event : 한 화면에서 발생할 수 있는 모든 사용자의 action을 정의하는, 클래스의 집합입니다.
  • feature : 사용자에게 표시되는 화면과, 그 화면을 구성하는 로직입니다.

design system

재사용이 가능한 DMS 디자인 컴포넌트들의 집합입니다. 추후 새로운 Github Repository에서 구현하여, DMS Android 프로젝트에서 외부 라이브러리로 사용할 계획입니다.

  • component : 여러 디자인 컴포넌트들을 묶어 구현한, 큰 컴포넌트들입니다.
  • theme : DMS 애플리케이션의 테마입니다.
  • typography : DMS 디자인에 정의된 Typography들의 집합입니다.
  • icon : DMS 디자인에 정의된 Icon들의 집합입니다.
  • color : DMS 디자인에 정의된 Primary, Secondary color 등의 색상 집합입니다.

마치며

아직 Android 리팩토링 초기 단계입니다. Android 리팩토링을 진행하면서, 다른 분야와의 소통, 특히 Back-end 분야와의 소통이 자주 발생하였고, Back-end 분야와 Client 분야 개발자 분들께서 더 자주 소통을 하며, 더욱 유지보수가 용이하고 생산성을 높일 수 있는 코드를 작성할 수 있으면 좋겠습니다.

Team Aliens는 고등학생들로 구성되어 있는 팀인만큼, 개발자 각각의 의견을 마음껏 이야기할 수 있는 수평적인 구조를 가지고 있습니다. 여러 분야의 팀원 분들과 열린 소통을 나누며, 각 팀원분들 모두에게 실무에 투입되기 전, 협업의 능력을 마음껏 기를 수 있는 좋은 경험이 되었으면 좋겠습니다.

또한, 우리 프로젝트를 진행하면서 실무에서 경험하기 어려운 일, 예를 들어, 대규모 리팩토링과 같은 작업을 진행해보는 등의 많은 경험을 쌓고, 모든 팀원분들께 좋은 추억으로 남을 수 있는 일들을 했으면 합니다.

--

--