티스토리 뷰
프로젝트를 시작하면, 항상 고민하는 것은 아키텍처에 대한 고민이라고 할 수 있다. 우리는 회사가 가진 리소스에서 가장 효율적으로 프로젝트를 셋업 하기 위해 어떠한 아키텍처를 사용할지 매 순간 고민한다. MVP 개념으로 빠르게 시장 반응을 알기 위해 빠르게 개발이 필요한 경우가 있다. 이러한 경우 개발 빠르게 하기 위하여, vanillaJS를 사용하여 만들 수도 있고, Nextjs를 사용하여 백엔드 없이 하나의 Product으로 개발을 할 수도 있다. 그리고 SSR / SSG /CSR 중 어느 것을 사용하는게 프로젝트에 최적화할 수 있을까? 상태관리는 어떻게 할까? 컴포넌트는 어떻게 나누는 것이 좋을까? 와 같은 끊임없는 고민을 한다. 이러한 고민에는 기본적인 프론트엔드에 대한 포괄적이고 전반적인 지식을 알아야, 상황에 맞는 아키텍처를 선택할 수 있다고 할 수 있다. 이 글을 통해 전반적인 프런트엔드 아키텍처에 대한 기초 지식을 살펴 보자.
UI(User Interface)
Frontend를 만든다는 말을 UI를 그린다는 말로도 많이 쓰인다. 프런트엔드 아키텍처로 넘어가기 전에 UI에 대해 간단히 알아보자. 모든 프로그래밍은 입력(Input)과 출력(Output)으로 이루어져 있다. Frontend 관점에서 생각해 보면, 사용자가 입력(touch 같은 이벤트)을 주면 프로그래밍은 유의미한 값(화면 변경)을 출력해 주는 것이다. 과거 컴퓨터는 현재 컴퓨터와 다르게 문자열 자체가 UI이었다. 따라서 데이터 자체를 보거나 수정하는 것이 어려웠지 때문에, 사용자가 조금 더 편리하게 프로그래밍을 사용할 수 있도록 변화하여야 했고 사용자 인터페이스(User Interface)가 생기게 되었다. 사실 최근에는 사용자의 편의보다는 기술에 대한 이해가 중요 시 되고 있긴 하지만, Frontend의 근본은 사용자가 편리하게 제품을 사용할 수 있도록 만들어야 함을 잊으면 안 된다. 정리하면, UI(User Interface)란 사용자와 컴퓨터 프로그램 사이에서 의사소통 할 수 있도록 만들어진 매개체를 뜻한다.(위키백과)
UI의 관점에서 크게 2가지로 나누어 생각해 볼 수 있다. 바로 데이터를 시각화하는 부분(View)과 데이터를 조작(Bussiness Logic)하는 부분이다. 우리(개발자)가 만드는 제품과 사용자와의 상호작용이 User Interface라는 것을 알았다. 그렇다면, UI 관점에서 Frontend를 뜯어보자. 우선 사용자가 브라우저를 통해 화면을 보는 부분이 있고, 그 화면에서 사용자가 터치하거나 입력하여 데이터를 등록하거나 수정하는 부분이 있을 것이다. 전자 부분이 View라고 할 수 있고, 후자 부분이 Bussiness Logic이라고 할 수 있다.
1. View
프런트엔드 기준으로 데이터를 시각화한다는 것은 무엇일까? 데이터를 사용자가 확인할 수 있도록 화면에 보여주는 것이다. frontend를 배우는 입장에서는 이는 HTML, CSS, JavaScript를 활용해 웹을 사용자에게 보이게 하는 부분이라고 할 수 있다.
2. Bussiness Logic
그렇다면 데이터 조작이란 무엇일까? View 단계에서 시간화된 데이터를 사용자는 볼 수 있다. 그리고 사용자는 데이터를 보면서 상호작용(CRUD)을 할 수 있다. 이는 사용자가 특정 이벤트를 발생시키고, 이벤트에 따른 화면 변환이나 데이터 변경을 진행하게 된다. 즉, View를 제외한 모든 부분이 Bussiness Logic이라고 한다. 혹자는 Domain Logic이라고도 한다.
위에서 알아본 내용을 토대로, 프런트엔드 아키텍처라는 것은 View 로직과 Bussiness Logic을 분리하여 프로젝트를 만드는 것인가 라는 추론을 할 수있다. 반은 맞고 반은 틀리다. 이러한 관점을 이해하기 위해서는 프론트 엔드가 만들어진 역사를 보면서 조금 더 이해를 할 필요가 있다.
프런트엔드 아키텍처
프런트엔드 개발자란, View 로직과 Bussiness Logic을 둘 다 커버가능해야 한다. 그렇기 때문에 웹 이 발전하면서, 다양한 관점으로 새로운 아키텍처들이 생겨나기 시작한다. 프로젝트 코드 정리나 재사용성의 관점으로 아래의 글들을 확인해 보자. 간단하게 훑고 넘어가는 것이기 때문에, 디테일한 내용은 구글링을 통해 지식 습득을 하도록 하자.
1. Web 1.0
Web 1.0은 1990년 초반부터 2000년 초반까지는 초창기 인터넷이라고 할 수 있다. 이러한 Web의 시작은 우리가 현재 보고 있는 화려한 웹페이지는 아니었다. 단순하게 가상공간에 HyperText가 적힌 문서를 링크를 통해 확인할 수 있을 뿐이었다. 이러한 HyperText가 모든 사람이 쉽게 공유할 수 있도록 만든 것이 바로 HTML(Hypertext Markup Language)라고 할 수 있다. 추가로 이러한 하이퍼텍스트 공유를 위해 HTTP(Hypertext Transfor Protocol)를 이용했다.
이때는 Web은 읽기 전용의 웹이었고, 사람들이 접속해서 정보를 검색하는 것에 초점이 맞춰있었다. 왜냐하면, 초기 HTML은 UI 관점에서 데이터를 변경할 수 없었기 때문이다. 따라서 만약 변경이 필요하다면, 서버의 HTML 파일을 변경하여 저장하는 방식으로 수정이 가능했다. 그 후로 동적으로 서버에서 페이지를 생성가능하게 된다. 쉽게 말하면, 페이지를 이동해야 다른 정보를 가지고 올 수 있게 된 것이다.(같은 주소에서 CSR처럼 화면이 변경되는 것은 아니다.) 이때 PHP가 탄생하게 되고 여러 서버 스크립트 언어가 생겨나기 시작한다.
2. JavaScript 등장
HTML이라는 글자를 핸들링하기 위해서 스크립트 언어가 필요하다는 고민을 개발자들이 하게 된다. 그래서 서버와의 통신을 통한 UI 변환이나 데이터 검증을 위해 JavaScript가 탄생하게 된다. 이때는 JavaScript는 Nodejs의 JS가 아니다. 브라우저 자체에서 돌아가는 JavaScript라고 할 수 있다.
3. CSS 등장
HTML 자체에서 스타일을 줬었는데, 유지보수가 어려워 콘텐츠와 서식을 분리하기 위해 CSS가 만들어지게 된다. 초기 CSS는 <style> 태그에 넣었다. 그러다 추후 별도의 파일로 css를 저장하여, <link> 태그로 인베드 하는 방식으로 변경되었다.
4. Internet Exploer 대중화
마이크로소프트의 컴퓨터가 세계적으로 유명해지기 시작 한다. 따라서 Windows가 대중화되고 Internet Exploer가 각각의 컴퓨터에 기본으로 설치가 되게 된다. 이러한 수요로 기업에서는 홈페이지를 만드는 것이 명함을 만드는 것과 같게 되기 시작한다. 따라서 기업의 수요로 인해, 웹 자체를 만드는 것이 솔루션화 되기 시작한다. 이러한 현상을 통해 수많은 웹 디자이너와 HTML/CSS를 다루는 웹 개발자라는 직업이 생기기 시작한다. 하지만 이때까지는 웹 자체가 회사의 메인 사업이 아니었고, javascript 자체가 비즈니스 모델과 상관이 없었기 때문에 개발자들 사이에서 웹 개발자는 비주류 개발자로 취급되기도 하였다.
5. Ajax
기본적으로 지금의 JavaScript와 다르게 브라우저 환경자체가 굉장히 열악했다. 따라서 Application 자체를 웹으로 만들 필요 없이 ActionX나 Flash를 많이 활용을 해서 만들었다. 이 시기에 구글에서는 OS를 만드는 것이 아닌 웹 자체를 OS로 만들기 위한 고민을 하였고, 대중화된 Internet Exploer를 능가하는 브라우저를 만들기를 착수한다. 이러한 준비를 통해 구글에서 Google Maps을 javascript 비동기를 활용해 만들어 출시한다. 이 시기 웹 자체로만 다른 도움 없이 동적으로 만든다는 것은 굉장한 혁신이었고, 이를 통해 javascript가 재평가를 받게 된다.
그렇다면 Google Maps을 탄생시킨 Ajax에 대해 알아보자. Ajax(Asynchronous JavaScript and XML)를 이해하려면, 2000년 초반에 등장한 RIA(Rich Internet Application) 패러다임에 대해 먼저 알 필요가 있다. RIA란 웹은 설치가 필요 없다는 장점을 유지하면서, 데스크톱 application에 비해 늦은 응답속도나 조작(단점)을 개선하는 기술의 통칭이라고 할 수 있다. RIA 패러다임 이전과 이후의 가장 큰 변화는 정적에서 동적으로 변한 것이라고 할 수 있다. 즉, RIA 이전 웹은 화면에 표시된 이후로 변화가 없었다. 하지만, RIA 이후에는 현대 웹 브라우저처럼, 화면 렌더 이후에도 사용자의 이벤트에 따라 화면이 변화하는 것을 의미한다. 동적으로 변환될 때, 페이지 전체가 로딩되지 않는 것이Google Map의 비동기라고 할 수 있다. 이러한 기술을 구현할 수 있게 도와주는 것이 바로 Ajax이다.
6. 웹 표준
이전 HTML 1.0에서는 사실상 표준이 없었다. 따라서 현재 사용하는 태그 element도 이름과 기능이 다 달랐다. 따라서 같은 웹 화면을 만들려면, 기업마다 제공하는 브라우저 정책에 맞게 따로 개발을 해야 했다. 하지만, 웹 사용자가 증가함에 따라 W3C(World Wide Web Consortium)에서는 각 기업마다 만드는 웹에서는 HTML/CSS/JAVASCRIPT이 같다면, 같은 화면을 보여주기 위한 표준에 대한 고민을 시작한다. 그래서 HTML 2.0부터는 표준화를 위한 노력을 시작했고, HTML 4.01부터는 CSS와 HTML을 분리하여 HTML에서는 전반적인 구조만 명시하도록 변경되었다. 그 후 W3C에서는 XML과 HTML을 합성하여 만든 XHTML을 웹 표준으로 만들려고 했다. 그러나 당시 대중적인 브라우저를 가진 기업(MS, Apple, Mozilla, Opera)은 WHATWG(Web Hypertext Application Technology Working Group)를 출범하고, 표준기관의 XHTML을 반대하고 기존의 HTML을 발전시켜 HTML의 표준을 만들려고 했다. 그것이 바로 현재 우리가 사용하고 있는 HTML5의 시초이다. 결국 W3C는 XHTML을 웹 표준으로 하지 않고 WHATWG에서 정의한 표준을 따르기로 한다. 결국엔 HTML5와 CSS3이 표준으로 확정되게 되고 현재 우리가 사용하는 HTML5가 된 것이다.
7. jQuery 등장
위에서 웹 개발도구가 표준화되고 발전하면서, 웹 개발 자체가 개발자들 사이에서 관심을 받게 된다. 또한 Ajax의 탄생으로 서버자체는 HTML을 매 순간 만들 필요 없이, 비동기 데이터 교환만으로 UI 처리가 가능해졌다. 따라서 javascript의 라이브러리들이 발전하고 사용법도 발전하게 된다. 사실 크로스 브라우저에서 JavaScript를 작성하는 것은 쉬운 문제는 아니었다. 그래서 John Resig가 이러한 문제를 해결하기 위해 jQuery 라이브러리를 개발하게 된다. 웹 표준 API와 Ajax까지 해결할 수 있는 jQuery 라이브러리는 현재 가장 유명한 라이브러리 중 하나라고 할 수 있겠다.
8. 크롬 브라우저 탄생
OS는 Window의 대중화로 독보적으로 마이크로소프트가 가져갔다고 할 수 있다. 하지만, 구글에서는 OS를 만드는 것이 아닌 웹 자체를 OS로 만들기 위한 고민을 하였고, Internet Exploer를 능가하는 브라우저를 만들기를 시작한다. 이러한 이유의 초석으로 JavaScript의 성능을 높이는 것이 중요 과제가 된다. 이러한 이유로 V8 JavaScript 엔진을 개발하고 오픈소스로 공유하게 된다. 그 이후 safari 오픈소스 브라우저 엔진인 webkit을 결합시킨 크롬 브라우저가 탄생하게 된다. 크롬 브라우저의 탄생으로 매우 빠른 속도의 브라우저뿐만 아니라 최적의 디버깅 환경을 개발자들이 사용할 수 있게 되었다.
9. Nodejs
기본적으로 JavaScript자체는 웹 바라우저에서만 동작을 했다. V8 오픈 소스의 등장 이후에 서버사이드 환경에서 개발할 수 있는 Node가 탄생한다. 이는 기본적으로 JavaScript는 언어가 아니라는 지배적인 의견이 변하는 계기가 된다. 또한 JavaScript로 서버 개발까지 할 수 있어, 앞으로의 express/nestjs의 토대가 생긴 것이라 할 수 있다. Node는 module 방식을 채택하여 추후 나올 번들러나 es module의 토대가 되었다.
module이 없는 경우에는 한 파일에 대부분의 로직을 다 작성을 해야 했기 때문에, 디버깅이 어렵고 재사용이 어려웠다. module 자체가 발전하면서 module을 패킹징하여 등록하고 관리할 수 있는 npm 이 등장하게 된다. 이때부터 JavaScript 생태계 자체가 폭발적으로 성장하게 된다. 추가로 webpack, babel 등과 같은 Node 기반의 dev-ops도 등장하면서 기업들에서 prod로 만들 수 있을 가능성들이 보이기 시작한다.
10. MVC (Model / View / Controller) 패턴
HTML / CSS / JavaScript로 관리하면서, jQuery 같은 DOM을 잘 다룰 수 있도록 발전하다 보니 HTML과 JavaScript를 합치려는 시도가 나타나기 시작했다. 즉, 데이터 조작과 DOM 조작을 하나로 관리하기 시작했다. 따라서 화면 단위가 아니라 컴포넌트 단위로 개발을 진행하기 시작하면서 MVC 컴포넌트가 탄생했다. MVC 패턴이란 각 컴포넌트(Model, Vide, Controller)가 담당하는 역할을 나누어 구현하는 방식이다.
간단히 설명해 보면, Model은 데이터와 비즈니스 로직을 담당한다. 따라서 컨트롤러에 의해 원하는 값을 제공하고, 추가 비즈니스 로직을 수행한다. View는 입출력 인터페이스를 담당한다. Controller는 출력 정보를 Model에게 가져와 view와 연결해 주거나 View에게서 받은 데이터를 모델에서 전달하는 역할을 한다. 각각의 컴포넌트 들은 다른 컴포넌트의 정보를 알면 안 되고, 책임 분리가 필요하다. 즉, Controller는 비즈니스 로직과 입출력 인터페이스에 대한 책임이 없어야 하고, Model과 View도 다른 컴포넌트에 대한 정보를 포함하면 안 된다.
Model 자체의 정의를 조금 더 알아보자. Model은 상태 / 구조/ 유저의 행동을 나타내는 역할을 한다. 그리고 View는 하나 / 여러 개의 Model로부터 받은 정보를 나타낸다. Model이 변경 시 View에 적절한 UI 변경을 위해 Model에 View를 등록하여 Model이 변경됨을 알려줘야 한다. 정리하면, Model Layer는 View가 화면에 무엇을 그리고 변경해야 하는지 알려주는 Layer라고 할 수 있다.
아래는 MVC에 대한 대략적인 다이어그램을 그린 것이다. 아래의 그림에서는 View와 Model이 데이터를 주고받지 않는다. 하지만 (Observer 패턴) 정책에 따라 View와 Model이 데이터를 주고받을 수도 있다. 정리하면, MVC 패턴이란 Model View Controller를 활용하여 아키텍처를 만든 총칭이라고 할 수 있다. MVC 패턴 안에서도 어떤 디자인 패턴을 추가로 사용하는지에 따라 변경될 수 있다.
- User의 Event/Input 이 Controller에 들어온다.
- Controller는 필요한 데이터를 Model에 요청한다.
- 요청받은 Model은 변경된 데이터를 Controller에 전달한다.
- 전달받은 Controller는 변경이 필요한 View에 요청한다.
- View는 필요시 Model에게 상태를 요청하고, 화면을 그린다.
11. MVVM(Model / View / ViewModel) 패턴
MVVM은 MVC의 변형 패턴으로 View를 추상화하여 ViewModel을 만드는 것이 핵심이라 할 수 있다. View는 자신이 가진 상태를 표현하고 명령을 내릴 수단을 가진다. 따라서 선언적으로 Model을 실행하는 것이 가능하게 된 것이다. 이는 추상화된 ViewModel은 당연히 View자체에 대해 몰라야 하고, 다른 플랫폼에서도 재사용될 수 있다. 쉽게 말하면, HTML을 class나 id로 접근하는 것이 아니라, 직접적인 HTML에 접근하여 핸들링하는 방식으로 확장되었다고 할 수 있다.
여기서 선언적(Declarative) 프로그래밍이라는 말이 나온다. 선언형 프로그래밍을 보면, 내부적으로는 절차적 프로그래밍으로 되어 있지만, 절차적인 명령형 프로그래밍이 추상화되어 선언형 프로그래밍이 된다고 할 수 있다. 어떤 일을 어떻게 하는지가 절차적(명령형) 프로그래밍이라면, 무엇을 할지가 선언적 프로그래밍이라고 할 수 있다.
MVVM 패턴에는 데이터 바인딩이라는 개념이 나온다. 추상화된 View와 물리적이 View를 연결하는 것이바로 데이터 바인딩(data binding)이다. 기본적으로 MVC에서는 Controller가 View와 Model을 연결한다. 하지만, MVVM에서는 작업흐름의 제어보다는 View와 ViewModel을 동기화하는데 집중한다. 따라서 MVVM 은 데이터 바인딩에 의존하여 동기화를 진행한다. 데이터 바인딩을 통해 ViewModel의 상태 변경 시 View도 상태가 함께 변경된다.
- 사용자의 Action이 View를 로 전단된다
- View에서 Action이 들어오면, Command 패턴(선언적)으로 ViewModel에 Action을 전달한다
- ViewModel은 Model에게 데이터를 전달한다
- Model은 ViewModel에게 요청받은 데이터에 대한 응답을 준다
- ViewModel은 응답받은 데이터를 가공하여 저장한다
- View는 ViewModel과 데이터바인딩하여 화면에 표현된다
데이터 변경 시 html 변화 없이 템플릿 자체로 변화시키는 방법에 대한 연구가 계속되었다. 이러한 과정 속에서 angaulr.js 같은 MVVM 아키텍처 웹 프레임워크가 만들어진다. angaulr.js를 보면 DOM을 직접적으로 조작하는 코드는 사라지고, 데이터를 angaulr에 전달하면 알아서 그려준다.
12. Frontend와 backend의 분리
거대 웹서비스들이 등장하면서, 규모가 커지기 시작하면서 유지 보수를 위해 기존과는 다른 방법의 관리가 필요했다. 이러한 이유로 데이처 치리/ 화면 개발을 분리 하여 전문성을 높이는 것이 바로 Frontend와 Backend의 분리라고 할 수 있다. Facebook에서 JSX를 기본으로 하는 React Framework(2013)를 탄생하면서 프런트엔트라는 직업이 자리 잡기 시작한다.
13. Container - Presenter 방식
사실상 여기서부터의 컴포넌트는 React 컴포넌트라고 할 수 있을 것 같다. UI 컴포넌트를 만드는 이유가 UI의 재사용과 유지보수를 위해서라고 할 수 있다. 그러나 프로젝트가 복잡해지면서 데이터가 컴포넌트마다 들어가니 로직이 복잡해지기 시작했다. 이러한 문제를 해결하기 위해 컴포넌트의 책임을 크게 2가지로 분리하여 사용하기로 한다. 데이터를 받아서 보여주기만 하는 Presenter 컴포넌트와 데이터를 조작하는 Container 컴포넌트로 분리한 것이 바로 Container - Presenter 방식이다. Presenter 컴포넌트 자체가 UI만을 나타내기 때문에 재사용에 최적화된 컴포넌트이고, 현재도 많이 사용되고 있는 패턴이라고 할 수 있다.
14. Props Drill
Container - Presenter 방식으로 컴포넌트를 나누어, 데이터를 조작하는 하나의 Container에 포함된 UI 컴포넌트들이 많아지기 시작했다. 따라서 중간 컴포넌트에서는 데이터를 사용하지 않더라도 하위 컴포넌트로 데이터를 보내기 위한 props들이 필요해졌다. 사실상 컴포넌트 독립과 재사용을 위해 컴포넌트를 분리했지만, 중간 컴포넌트로 인해, 상위 컴포넌트와 하위 컴포넌트의 결합도가 올라가는 현상이 발생한 것이다. 이러한 문제는 또한 하위 컴포넌트의 deps가 깊어질수록 props로 길게 데이터를 보내야 했다. 이러한 문제가 바로 Props Drilling 문제라고 할 수 있다.
15 상태 관리(State Management)의 발전
위와 같이 Props Drilling 문제가 발생하다 보니, 비즈니스 로직을 컴포넌트 계층구조에 포함시킬 필요를 느끼지 못하게 된다. 따라서 상태 관리(State Management) 개념이 나오게 된다. View와 비즈니스 로직을 완전히 분리하여 단방향 데이터 구조를 가지는 FLUX 패턴이 등장했고, FLUX 패턴을 근본으로 한 Redux의 등장으로 이러한 패턴이 주류가 되었다.
하지만, Redux 자체는 많은 보일러플레이트가 필요했지 때문에, 대규모 프로젝트가 아닌 경우에는 오버엔지니어링이 되었다. 이는 하나의 간단한 로직 추가하는데도 엄청난 많은 코딩을 써야 했기 때문에, Redux를 대체할 상태관리 기술들이 발전하기 시작한다. React 본진에서는 Hooks를 만들어 외부 비즈니스 로직과 쉽게 연동하여, 화면을 변환시킬 수 있도록 되었고, Context를 통해 하위 컴포넌트에서 데이터를 공유할 수 있도록 만들었다. 또한 조금 더 전역 상태 관리를 용이하게 하기 위해 Atom을 활용해 데이터를 저장하고 변경된 데이터를 View로 전달하는 Recoil도 등장하게 되었다.
16. API 상태관리
사실 Frontend에서 상태관리를 하고 있지만, 데이터의 CRUD는 서버에서 이루어진다고 할 수 있다. 그렇다면 비즈니스 로직은 벡엔드에서 처리하고 API 자체를 통한 상태관리를 하는 방향으로 변화하게 된다. 이러한 API 상태관리로는 React Query와 SWR이 있다고 할 수 있다. API로 상태를 관리한다는 말이 어색할 수 있다. 쉽게 설명하면, API의 결괏값을 받은 후에 API를 캐싱한다. 이러한 캐싱을 통해 전역 API를 관리하는 것이 가능해진다고 이해하면 된다. 물론 디테일한 부분은 구글링을 해보면 좋을 것 같다.
17. MVI(Model / View / Intent) 아키텍처
MVI의 View는 기본적인 화면을 의미한다. View에서 사용자가 Event를 발생시키는 것을 사용자의 의도라고 할 수 있다. 이러한 사용자의 의도가 포함된 비즈니스 로직을 Intent라고 한다. 이러한 Intent에 따라서 데이터를 변환시키는 비즈니스 로직을 Model이라고 한다. 따라서 단반향으로 2개의 비즈니스 모델을 처리한다고 생각하면 된다. 언듯 보면, MVC / MVVM과 비슷해 보이지만, 가장 다른 점은 하나의 컴포넌트의 기준이 아니라 프로젝트 전체에 적용이 된다는 점이다. MVI를 아래의 함수로 많이들 표현을 하는데, 직관적인 이해가 된다.
view(model(intent(user(view(model(intent(user())))))))
유저가 의도를 가지고 intent를 보내면 model에서 데이터를 변경하거나 필요한 데이터를 View로 보내서 화면이 변경됨을 나타내는 함수라고 할 수 있다. 이러한 cycle이 반복되어 실행되는 게 MVI 아키텍처라고 할 수 있다.
글을 읽다 보면 느낄 수 있겠지만, 기존에는 재사용이 가능한 컴포넌트를 이용하여 서비스를 구성하는데 집중했다. 최근 방향은 View와 비즈니스 로직을 분리를 우선이 한다. 비즈니스 로직을 순차적으로 정리하면 다음과 같다고 할 수 있다. 사용자의 Action을 Intent로 표현한다. 그리고 Action을 통해 데이터를 변화시키거나, 변화된 데이터에 따른 View로 전파하는 로직으로 표현할 수 있다. 따라서 View 자체끼리는 느슨한 결합이 되고, View는 비즈니스 로직에 의존적이게 되어 변경 로직이나 요구사항에 유연한 대처가 가능하다고 할 수 있다.
19. 프런트엔드 아키텍처를 어떻게 만들까?
정리해 보자. 위에서 우리가 만들어야 할 컴포넌트는 독립성을 유지하고 의존성을 최소화하여 재활용할 수 있어야 한다. 하지만 컴포넌트의 계층구조가 복잡해지고, 데이터를 받는 방식이 복잡해지면서 컴포넌트끼리 데이터를 주고받기 된다. 따라서 컴포넌트 재활용이 어려워지기 시작한다. 이러한 문제를 해결하기 위해 컴포넌트와 데이터를 분리하는 방향으로 단방향 아키텍처가 만들어졌고, 전역 상태 관리가 만들어졌다.
우리는 습관적으로 useState를 사용하여 상태관리를 한다. 그러나 상태 관리를 잘못하면 '유지보수가 어려운 코드'가 된다. 따라서 처음 우리가 생각해야 할 부분은 View 로직과 비즈니스 로직( = 도메인 로직)의 명확한 구분에서 시작된다. 물론, 특정 컴포넌트 영역만 영향을 주는 비즈니스 로직이라면, 특정 컴포넌트 안에서만 만들어줘도 좋다. 작은 컴포넌트 안에서만 책임이 필요하다면, 빠르게 만들 수 있고 구축 비용을 줄일 수 있기 때문에 매우 효율적인 방법이라고 할 수 있다.
반대로 페이지 수준에서 비즈니스 로직을 다룬다면, module 하나로 분리해서 만드는 것도 좋은 방법 중 하나이다. 하지만, 이러한 로직에 상태가 추가된다면 말이 달라진다. 상태 값이 비즈니스 로직의 상태 값인지 화면을 변경시키는 상태 값인지 확인을 해야 한다. 그리고 이에 따라 비즈니스 로직의 상태 값과 화면의 상태 값을 어느 시점에 동기화를 시켜 화면에 표출하는지도 확인이 필요하다.
따라서 변경과 초기화 이슈가 있을 수 있기 때문에, 세션이 유지되는 동안만 비즈니스 로직이 유지되고 화면에 변경이 적용되도록 만들기 위해 노력해야 한다. 그렇다면 내가 작성한 코드가 View 로직과 비즈니스 로직이 잘 분리가 되었는지 어떻게 확인할 수 있을까? 추가 요구사항이 들어왔을 때 쉽게 수정할 수 있는가 없는가로 확인하면 된다. SaaS서비스에서 월별 구독 결제에서 중간 취소 시 1/3만 환불을 할 수 있는 비즈니스 로직을 추가한다고 해보자. 이러한 경우 수정할 부분이 많다면 비즈니스 로직과 View 로직이 적절하게 분리되지 않은 것이다.
20. 좋은 아키택처 코드란 무엇일까?
( 이 부분은 정답이 없기에 관련 부분은 개발을 진행하면서, 계속 추가할 예정입니다.)
보통 우리는 Event 함수 자체에 State를 직관적으로 변경한다. 아래의 예를 보자.
async const onClick = () => {
setModal(false)
setSampleDate([...sampleDate, {id : "hanpy"}])
await fetching({id : "hanpy"})
}
위의 로직은 직관적으로 이해하기가 쉽다. modal을 종료하고, Date를 변경한다. 이러한 로직의 단점은 프로젝트가 복잡해졌을 때, 발생한다. 예를 들어 모달이 닫히는 과정에서 에러가 났다면, 데이터 결과를 하나씩 하나씩 추적해야 한다. 모달을 닫는 setModal()이 여러 로직에서 많이 쓰인다면, 각각의 로직을 하나씩 확인하여야 한다. 또한, View 자체에서 데이터를 직접 수정하게 된다면, Model과 View 사이에 의존성이 생기게 된다. 이러한 문제를 방지하기 위해 View에서는 Intent(의도)만 전달을 하고, Model에서만 데이터를 변환을 할 수 있도록 만들어야 한다. 이는 데이터 변환 로직을 Model 모듈에만 있기 때문에 응집도가 높아지고, View와 비즈니스 로직 사이에 느슨한 결합을 구현할 수 있게 된다. 필요하다면 관련 부분을 검색해 보면 좋을 것 같다.
긴 글을 통해, 다양한 아키텍처들에 대해 알아보았다. 정답이 있다고 말하기는 어렵다. 하지만 좋은 아키텍처를 만드는 이유는, 더 쉽게 코드를 유지보수/재사용하여 product의 에러를 최소화하고 인적 리소스를 절약하는 위함임은 틀림없다고 생각한다. 필자도 오늘도 아키텍처에 대한 고민을 하고 있다. 위의 내용을 파탕으로 주어진 상황에 따라 프로젝트를 성공적으로 이끌 수 있도록 아키텍처를 고민해 보면 좋을 것 같다.
'Web > 프로젝트구현' 카테고리의 다른 글
[React] 컴포넌트 설계 기초 정리 (0) | 2023.08.22 |
---|---|
TypeError: Cannot destructure property 'styles' of 'this.context' as it is null. (0) | 2023.03.12 |
[개발자 도구] TTFB(Time To First Byte) (0) | 2023.02.17 |
[javascript] event.keyCode 기초 정리 (0) | 2023.02.11 |
[UX/UI] web focus 적용하기(tabindex) (0) | 2023.02.08 |
- Total
- Today
- Yesterday
- vuejs
- useState
- Queue
- Python
- react autoFocus
- read_csv
- 자연어처리
- 클라우데라
- login
- logout
- JavaScript
- DFS
- useHistory 안됨
- pandas
- react
- django
- Deque
- error:0308010C:digital envelope routines::unsupported
- UserCreationForm
- NextJS
- nextjs autoFocus
- Vue
- TensorFlow
- next.config.js
- BFS
- nodejs
- 자료구조
- typescript
- mongoDB
- Express
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |