이상적인 앱 구조

Park June Chul·2022년 3월 7일
0

잘 코딩하기

목록 보기
6/6

이 글은 일반적인 이상적인 앱 구조와 코드에 대해 다루는것이 아닌
제가 생각하는 이상향적인 앱 구조에 대해 다룹니다.

쓰다 말음

React는 웹 개발에서 많은 부분을 덜어냈습니다.

DOM조작과 상태 관리, 쿼리 셀렉터 등...
이제 우리는 document API를 아예 몰라도 웹 개발이 가능합니다!

심지어 React는 최근에 Suspense패턴을 이용하여 비동기와 에러 처리에 대한 부분까지 덜어내 버렸습니다.

덜어낸다는 것은 단순히 개발 난이도가 내려감을 의미하지 않습니다.

WIN32API 개발자들이 이상한 API와 씨름할 때, C# 개발자들은 프로덕트 자체에 대해 더 고민할 시간을 벌 수 있었고,

이는 jQuery에서 React로 넘어오는 전환에서도 동일하게 적용됬습니다.

그러니까 앱 스펙과 직접적으로 관련이 있는 코드만 작성하면 나머지 부분들은 차세대 라이브러리/프레임워크들이 대신해준다는 점입니다. 심지어 직접 짜는 것보다 더 효율적으로 동작하죠.

그러니까 더 좋은 앱을 만들고 싶으면 뭔가를 더하는게 아니라 빼야 합니다.

제가 생각하는 이상적인 구조 또한 새로운 기능을 더하지 않습니다.
좀 더 개발자가 비즈니스 로직만 작성하도록 도와주는 역할이라고 볼 수 있겠네요.

제가 매번 예시로 사용하는 UserProfile 컴포넌트를 다시 들고 와 보겠습니다.

제 기준 뺄 수 있는 만큼 다 뺀 UserProfile의 모양은 아래와 같이 생겼습니다.

import {user} from './user';

const UserProfile = () => {
  return (
    <div>
      {user.name};
    </div>
  );
};
  • 상태 관리 혹은, store는 없습니다.
  • 데이터 가져오기 또한 없습니다.
  • 로딩과 에러 처리 이건 React의 천재 개발자들이 이미 빼 주었습니다. 없습니다.

UserProfile 컴포넌트는 그저 화면에 어떻게 보여줄 것인지만을 정의합니다.
여기서 더 필요한건 없습니다.

검색 혹은 다른 방식의 가져오기 예제

앱에 친구 목록 기능이 필요하다고 할 때 아래 친구 검색단일 친구 정보 가져오기 기능이 필요할 수 있습니다.
각각 경우에 어떻게 만들 수 있는지 적어보겠습니다.

검색

return (
  <div>
    {friends.search('검색어').map(x => </Friend />)}
  </div>
);

단일 친구 정보 가져오기

return (
  <div>
    Name: {friends['user_id_1'].name}
  </div>
);

어떻게 가능할까요?

Proxy는 위 코드를 실제로 구현할 수 있게 만들어주는 좋은 접근방법입니다.

let fetched = false;
let data;

export const user = new Proxy({}, {
  get() {
    if (fetched) {
      return data;
    }
    
    const fetchTask = fetch('/user');
    
    fetchTask.then((resp) => {
      data = resp;
    });
    
    throw new fetchTask;
  },
});

대충 수도코드지만 제가 작성한 이상적 코드가 실제로 불가능하지 않음을 보여줍니다.
user 오브젝트에 처음 접근할 때 가져오기를 시작합니다.

만약 relay를 써보신 적이 있다면 아래와 같은 코드를 작성해 더 효율적인 가져오기를 구현할 수 도 있습니다.
(저도 relay의 개념만 간신히 아는 정도이긴 합니다.)

return (
  <div>
    {user.name} 님 안녕하세요
    Lv. {user.level}
    
    친구 목록
    {user.friends.map(friend => (
      <div>
        {friend.name}</div>
    )}
  </div>
);

이 코드가 끝까지 실행되면 우리는 이 컴포넌트가 어떤 프로퍼티들을 필요로 하는지 알 수 있게 되고, 해당 프로퍼티들만 가져오도록 할 수 있습니다.

이는 GraphQL에서 흔하게 사용되는 기법이며, relay또한 이러한 기능을 지원합니다.

두번째 재밌는점은, 내 정보를 가져오는 API와 친구 목록을 가져오는 API는 보통 분리되어 있지만 호출 시점이 동일하다는것을 알기 때문에 서버에게 이 요청을 batch로 묶어서 요청해 볼 수도 있습니다.

이것은 data-loader라는 라이브러리에서 제공하며, dataloader역시 graphql의 기반이 되는 개념입니다.

결론은 글을 작성하듯이 컴포넌트를 작성하면

데이터는 물 흐르듯 따라 들어오는 형태입니다.

  • 비동기 처리는 없습니다. 그냥 접근하는 순간 요청합니다.
  • 데이터가 정말 필요한 시점에만 가져오기를 시작합니다.
    • 선언형으로 작성하는 React특성 상, 쓰지도 않을 데이터를 미리 깔아두고 시작하는 경우가 종종 있습니다.
    • 이러한 구조에서는 이런 가능성이 원천적으로 차단됩니다.
  • 모든 값 변경은 자동으로 반영됩니다.

Disclaimer

  • 이 글의 내용 그리고 코드는 부분적으로 구현해본 적은 있지만, 전체 스펙을 구현해본적은 없습니다. 말 그대로 제가 생각하는 이상적인 앱 코드입니다.
  • 위의 항목을 해본 적 없으니, 당연히 규모가 큰 앱에서 시도해본적도 없습니다. 규모가 커지면 더 복잡한 문제들이 생기고 위 해결방법이 답이 아닐 수 있습니다.
profile
다른 곳에서 볼 수 없는 이상한 주제를 다룹니다. https://pjc0247.github.io/new-home

1개의 댓글

comment-user-thumbnail
2022년 6월 28일

카카오 웹툰 클론코딩을 시작으로 재밌어서 상태관리를 쭉 보다가 결국
여태껏 글 써주신것 전부 다 봤는데 깃허브까지 들어가봐서 인상깊게 잘 봤습니다.
깃허브도 대충 꾸며놓고 공부할때 대충 넘어간 것들이 많았는데 깨달은 것들과 자극받는 것들이 많네요.
글 써주신것들 감사하고 화이팅 해주세요. 감사합니다.

답글 달기