뭐든 만들어 볼까?

작심하고 배웠으면, 뭐든 만들어야 세상이 알아주지.

시작하면 어렵지 않아요.
어렵게 배우면 어렵게 만들어야해요.
핵심을 쉽게 배워야 쉽게 만들 수 있어요.

기술 스택 별 이야기/ReactNative

ReactNative 전역 데이터 관리

imaustin 2025. 2. 19. 01:27
반응형
왜 앱에서 전역 데이터 관리가
중요하고 골치 아픈지...
하지만 바닥부터 잘 쌓으면 쉬워요~

 

웹이든 네이티브든 전역 데이터 관리는 빠질 수 없는 이슈이고 또 솔루션입니다. 뜨거운 감자처럼 이야기 되는 이 전역 데이터는 왜 프런트 개발자들에게 골치아픈 존재로 이야기 되곤 할까요?

 

1. 배보다 배꼽이 더 큰 전역 데이터 관리

일단 왜 전역 데이터가 필요한 지에 대해서 먼저 이야기를 해야겠죠? 사실 전역 데이터든 특정 컴포넌트나 렉시컬 환경에 갇힌 데이터이든 변수를 이용해서 값을 운용한다는 것에는 변함이 없습니다. 이 이슈는 특정 변수를 누군가에게 전달하는 과정에서 발생합니다. 사용하는 방법 때문에 발생하는 거죠.

우리가 만드는 웹이든 앱이든 현대 프런트엔드 개발에서 구축하는 앱은 하나의 큰 몸체 안에 들어가 있는 구조체들입니다. 이런 모양을 웹에서는 SPA(Single Page Application)이라고 부르죠? 웹이라는 특성에서 이름을 붙인거긴 한데, 이 용어가 복잡한 여러 개념을 좀 쉽게 설명해 줍니다. 하나의 페이지(몸체) 안에 만들어 놓은 프로그램이라는 뜻입니다.

모두가 아시고 계시는 것 처럼, 애플리케이션은 여러 개의 컴포넌트라는 단위의 객체로 만듭니다. 복잡성을 만들지 않기 위해서 관심사항 또는 책임에 따라서 분리하는 거죠. 문제는 이 분리된 컴포넌트들은 구조상 서로 격리되어 있다는 겁니다. 하지만 이 격리되어 있는 컴포넌트들은 플랫폼에 따라서 하나의 페이지나 또는 스크린 안에서 레고블럭처럼 합쳐집니다.

이 과정에서 각 컴포넌트로 전달해야 하는 정보들이 외부에서 주입됩니다. 음... 여기! 이 부분을 집중해서 생각해야 합니다. 주입할 수 있다는 것은 소프트웨어 공학적인 차원에서 본다면 하나의 솔루션이고 좋은 방법이지만, 내장될 수 있는 구조를 가지고 있는 컴포넌트의 차원에서 보면 중첩된 구조 안으로 반복해서 값을 전달해 주라고 부모 컴포넌트가 계속 귀찮은 일을 시킵니다. 그런데 얘는 너무 착해서 그냥 시키는 대로 하죠. 그러다가.. 사춘기가 오고 삐딱선을 타기 시작하면... 음... 이건 아래에서 이야기 하죠. 저도 부모라... ㅎㅎ

예를 들어서 A⊃B⊃C⊃D 라는 구조로 되어 있는 각각의 컴포넌트를 생각해 볼까요? D라는 컴포넌트에 외부에서 주입되는 value가 있다고 생각해 보죠. 이 값이 만약 A에서 생성되는 값이라면 이렇게 전달이 되어야 할 겁니다.

A → B → C → D

이런 방식을 속성값을 통해서 컴포넌트들의 계층을 뚫고 값을 주입한다고 해서 Props Drilling이라고 부릅니다. 하지만 이 방법에는 문제가 좀 있습니다. 문제라기 보다는 비효율성이라고 해야하는게 더 맞을 것 같은데요... 만약 B, C에서 이 value를 사용하지 않는다면 B, C는 자신이 사용하지도 않을 value를 다음 계층으로 넘겨주기 위해서 값을 받아야 합니다.

이 부분에서 소프트웨어 공학적인 문제 하나가 발생합니다. 자신의 책임이 아닌 일을 하고 있게 되는 상황이 발생하는 거죠. 쓰지도 않고, 자신의 책임도 아닌 일을 B, C가 하게 되는 겁니다. 그리고 이러한 과정으로 인해 이상한 데이터의 흐름이 생겨버립니다. 쉽게 이야기해서 옆 방에 전원을 공급하기 위해서 내 방에 수십 수백가닥의 전기선이 방바닦으로 지나가고 있는 것 같은 상황이 생겨버리는 거죠. 아우... 짜증나겠죠?

위에서 SPA라는 표현을 썼었죠? 맞습니다. 애플리케이션을 살아있는 사람으로 비유해 보면, 하나의 큰 몸체 안에서 머리부터 손가락 끝까지 이어지는 혈관 같은 것들이 하나씩 둘씩 생기기 시작하는 겁니다. 나중에는 수십 수백개의 혈관이 만들어 지겠죠? 데이터의 크기와 비중이 다르니까 그 혈관의 두께도 천차 만별일 겁니다. 어떤 건 굵은 혈관이고, 또 어떤건 매우 가는 모세혈관 같은 것들도 만들어 질 겁니다. 그런데 이 혈관이 관리되지 않으면 어떻게 될까요? 생각만 해도 끔찍하죠?

그래서 이런 생각을 해 냅니다. 저렇게 전달하지 말고 그냥 어디서든 쓸 수 있는 곳에다가 변수를 만들어 놓고 그걸 쓰면 안돼? 라고 말입니다. 아이디어는 정말 심플하고 훌륭했는데, 이걸 구현하기 위해서는 해결해야 할 문제들이 점점 많아지게 됩니다.

그래서 엔지니어들이 표준화 된 방식으로 처리하기 위해서 여러가지 기술들을 만들어 냅니다. 그런데 이 개념들이 반영된 기술을 익히는 것이 쉽지 않았습니다. 여기에 사용되거나 거론된 디자인 패턴 상의 개념들과 체계들이 개념 상으로는 쉽고 정리된 구조를 표방했지만, 정작 배우는 데에 가파른 학습 곡선을 요구하게 되었죠(사실... 디자인 패턴이나 구조화에 대한 학습을 일반 기술 사용자인 개발자들이 잘 하지 않으니까요...).

또 각각 사용하는 방법과 용어, 위치도 조금씩 달랐습니다. 높은 학습 곡선, 숙련도에 따라 일관되지 않게 사용된 결과로 인한 코드 산출물들...  결국 시간이 갈 수록 배보다 배꼽이 더 큰 비용을 지불하기 시작 합니다. 나는 그냥 변수 하나 만 Props Drilling을 안하려고 시작했는데 말이죠.

 

2. 쉬운 방법을 따라가자

전역 데이터를 관리하는 데에는 여러가지 방법이 존재합니다. 기본 React에서 제공해 주는 Context API에서 부터, Redux, MobX, Recoil 등등 많은 방법들이 있습니다. 하지만 각각 다른 개념과 사용법으로 인해 잘못 도입할 경우 프로젝트의 복잡성을 가중시킬 수 있어서 가능하면 하나의 방법을 체계적으로 도입해야 합니다.

저는 이 글에서 가장 쉽고 간단하게 사용할 수 있는 솔루션을 하나 사용할 계획입니다. 바로 Zustand 입니다.

Zustand는 리액트에서 사용하는 전역관리 솔루션입니다. 과거에는 ReactNative에서 사용하려면 몇가지 제약이 있었던 기억이 있는데, 지금은 거의 완벽하게 전역관리를 지원합니다. 뿐만 아니라 AsyncStorage와 연동해서 Persistent Data도 사용할 수 있습니다.

새로운 기술에 대한 보수적인 시니어 분들이나 또는 Redux를 사용하시던 분들이 프로젝트 조직에 있다면, 도입에 허들이 있을 수도 있습니다. '무슨 소리야?! 리액트의 전역 관리는 Redux지!'하는 의견에 부딛힐 수도 있습니다. 음... 시니어인 저도 저런 라떼엔 조금... 거부감이 있습니다. ㅎㅎ 하지만 기술의 사변적인 변화는 항상 필요를 해결하기 위해서 나왔고 Zustand도 예외는 아닙니다. 한번 써 보면 다시는 Redux로 돌아가기 싫으실 지도 모릅니다. 꽤 매력적이거든요.

출처: Zustand 공식 사이트

귀엽죠? 공식 사이트에 가시면 아래와 같은 소개의 글과 함께 많은 내용을 보실 수 있습니다.

https://zustand.docs.pmnd.rs/getting-started/introduction

A small, fast, and scalable bearbones state management solution. Zustand has a comfy API based on hooks. It isn't boilerplatey or opinionated, but has enough convention to be explicit and flux-like.

Don't disregard it because it's cute, it has claws! Lots of time was spent to deal with common pitfalls, like the dreaded zombie child problem, React concurrency, and context loss between mixed renderers. It may be the one state manager in the React space that gets all of these right.

 

3. Zustand 설치

먼저 설치해야 겠죠? 공식사이트에 가시면 설치방법이 나와 있습니다. 일단 아래와 같이 의존성을 설치해 주세요.

# NPM 사용
npm install zustand

# YARN 사용
yarn add zustand

그리고 ios를 위해서 pod install을 해 줍니다.

cd ios
pod install

이렇게 하면 준비가 끝납니다. 이제 사용해 볼까요?

 

4. Zustand 사용 - 전역으로 사용할 상태값 생성

전역으로 사용하는 값들은 대부분 상태값일 겁니다. 그렇다면 다음의 2가지가 있어야 합니다.

  • 수정자

네, 맞습니다. useState로 사용하던 것과 비슷하게 접근하면 됩니다. 조금 차이가 있을 수 있지만, 컴포넌트 내에서 사용하는 값들을 컴포넌트 밖으로 빼냈다고 생각하면 좀 쉽습니다.

그렇다면 가장 쉬운 예제로 카운터를 증감 시키는 경우를 예로 전역 데이터를 운용하는 예제를 시작해 보겠습니다.

4-1. 전역 값 생성

먼저 프로젝트의 적절한 위치에 counter-state.ts 라는 파일을 하나 만들고 아래와 같이 작성합니다.

import { create } from 'zustand';

interface CounterState {
  count: number;
  increment: () => void;
  decrement: () => void;
}

export const useCounterStore = create<CounterState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

어렵지 않죠? 

우리가 운영할 값은 'count' 변수 하나에 담겨있습니다. 이 값을 전역으로 사용할 계획입니다. 그리고 이 변수를 업데이트 하는 방법으로 '증가(increment)'와 '감소(decrement)' 라는 함수를 만들 계획입니다. 각각의 함수에서는 'count' 변수를 목적에 맞게 1 만큼 증가 시키고 감소시키는 비즈니스 로직을 담을 계획입니다.

먼저 타입을 선언했습니다. 하나의 타입에 값과 함수(메서드)를 담았습니다.

interface CounterState {
  count: number;
  increment: () => void;
  decrement: () => void;
}

그리고 저 타입의 값을 생성해서 전역에 넣는 작업을 합니다.

import { create } from 'zustand';

export const useCounterStore = create<CounterState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

이제 본체입니다. 이렇게 작성하면 Zustand가 count라는 값과 count 값을 변경하는 2개의 함수를 생성해서 전역에 등록해 줍니다. 끝입니다. 그냥 쓰면 됩니다. 이름에서 알 수 있듯이 훅처럼 쓸 수 있게 됩니다. 정말 간단하죠? 진짜냐구요? 그럼 이제 이 전역 값을 써서 카운터 애플리케이션을 만들겠습니다.

4-2. 전역 값을 사용해서 애플리케이션 만들기

우리가 만들 애플리케이션은 전역값을 사용하고 있다는 사실을 체감하기 위해서 2개의 컴포넌트로 구분할 계획입니다.

1) 값을 출력하는 컴포넌트: 

import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
import {useCounterStore} from '../context/CounterState.ts';

const CurrentCount = () => {
    const {count} = useCounterStore();
    return (
        <View style={styles.block}>
            <Text style={styles.count}>{count}</Text>
        </View>
    );
};

const styles = StyleSheet.create({
    block: {
        alignItems: 'center',
    },
    count: {
        fontSize: 160,
        fontWeight: 'bold',
    },
});

export default CurrentCount;

위의 컴포넌트는 전역 데이터 값을 나타내는 컴포넌트입니다. 우리가 작성했던 Zustand 상태값이죠. 다른 기능은 없고, 전역 상태의 값만 가져옵니다. 주목할 사항은 이 값을 어디선가 전역에 등록된 increment나 decrement로 수정을 하면 컴포넌트가 다시 그려지면서 count 라는 변수의 값이 업데이트 된다는 사실입니다.

2) 값을 변경하는 컴포넌트: 

import React from 'react';
import {Pressable, StyleSheet, Text, View} from 'react-native';
import {useCounterStore} from '../context/CounterState.ts';

const CountControl = () => {
    const {increment, decrement} = useCounterStore();
    return (
        <View style={styles.block}>
            <Pressable onPress={increment}>
                <Text style={styles.btn}>Increment</Text>
            </Pressable>
            <Pressable onPress={decrement}>
                <Text style={styles.btn}>Decrement</Text>
            </Pressable>
        </View>
    );
};

const styles = StyleSheet.create({
    block: {
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        paddingVertical: 16,
        gap: 16,
    },
    btn: {
        fontSize: 26,
    },
});

export default CountControl;

위의 컴포넌트는 전역에 등록되어 있는 함수를 가져와서 사용합니다. 위에서 이야기 한 것처럼, 해당 함수에는 전역에 등록된 값을 1씩 증가시키거나 또는 감소시키는 비즈니스 로직이 구현되어 있습니다.

예상하셨겠지만, 위의 컴포넌트를 호출하면 연결되어 있는 전역값이 바뀝니다. 그리고 어디선가 그 값을 쓰고 있다면 값을 쓰고 있는 해당 컴포넌트가 다시 그려지면서 값이 실시간으로 업데이트 됩니다.

이제 이 컴포넌트들을 모아서 애플리케이션을 만들어 볼까요?

3) 컴포넌트들을 모아서 애플리케이션으로:

import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import CurrentCount from './src/components/CurrentCount.tsx';
import CountControl from './src/components/CountControl.tsx';

const App = () => {
    return (
        <SafeAreaView style={styles.container}>
            <CurrentCount />
            <CountControl />
        </SafeAreaView>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
});

export default App;

위의 코드는 먼저 만든 2개의 코드를 하나의 소스코드에 조합해서 완성된 애플리케이션을 만든 메인 애플리케이션 파일입니다. 여기서 주목해서 봐야 할 부분은 분리된 2개의 컴포넌트, 즉 CurrentCount 컴포넌트와 CountControl입니다. 

이 두 컴포넌트에는 외부에서 주입해 주는 속성이 하나도 없습니다. 보통 컴포넌트들은 상태값을 외부에서 주입하는데, 이 컴포넌트들은 외부에서 어떤 값도 주입되지 않고있죠? 그런데 CountControl에서 값을 수정하면 CurrentCount에 그 결과가 실시간으로 반영됩니다.

사실 이런 현상을 위해서 전역값을 사용합니다. 어딘가에 값과 수정을 하는 연관된 함수들을 하나의 객체로 등록해 두고, 애플리케이션의 어디서든지 가져와서 사용하기 위해서 전역값을 사용합니다.

위의 애플리케이션을 실행하면 아래와 같이 나옵니다.

어때요? 실제로 작동하죠?

매우 간단한 사용법으로 기존의 Redux나 MobX와는 비교도 안될 정도로 쉽게 전역값을 생성하고 사용할 수 있습니다(물론 이 글에서는 Redux나 MobX 사용을 설명하지는 않았습니다. 나중에 기회가 될 때에 한번 비교하는 글을 쓸까 고민중입니다.). 

그렇다면 왜 이렇게 전역값을 사용하는지 감이 오시나요?

위에서 이야기 했던 SPA, 즉 하나의 단위로 구성된 애플리케이션의 경우 특정 기능이나 역할 단위로 코드를 분할해서 작성합니다. 이름이 Single라고 해서 하나의 파일에 모두 작성할 수는 없잖아요? 컴포넌트가 이런 목적에서 만들어진 겁니다. 그리고 이렇게 나누어서 담고, 특정 위치에 보관하도록 규칙을 정하는 작업을 설계라고 하죠.

설계가 반영된 애플리케이션들은 점점 증가하는 요구사항이나 기능을 효율적으로 반영하고 확장하기 위해서 서로 다른 방향과 시점으로 컴포넌트의 수가 늘어나게 됩니다. 유지보수가 이루어지고 운영 시간이 증가할 수록 컴포넌트의 수는 점점 더 많아지겠죠? 의존 관계나 또는 설계, 즉 나누는 방식이나 나누어서 담아두는 장소와 장소 간 관계성도 점점 복잡해 질 겁니다. 이렇게 되면 각 컴포넌트가 사용하는 데이터도 점점 더 복잡해지겠죠?

프로젝트가 조금만 커지기 시작해도 컴포넌트 간 유지해야 하는 데이터 간의 관계는 거미줄 처럼 복잡해 지고 예민해 집니다. 하나 만 수정해도 그 수정의 파급은 애플리케이션 전반으로 흘러들어 갈 겁니다.

만약 잘 만들어진 설계와 체계가 사라진다면 각 컴포넌트가 변하는 시기와 방향에 관계없이 데이터의 구조도 일정한 패턴이나 기준 없이 영향을 받게 됩니다. 한마디로 정리되지 않은 공사판, 막장이 되는 거죠. 석탄 갱도의 가장 깊은 곳처럼 깜깜해 지고 예상하지 못하는 환경의 지배를 받게 되는 겁니다.

간단한 변수 이야기로 시작했는데, 점점 이야기가 무거워 지죠?

 

5. 배보다 배꼽이 커지는 걸 막자!

애플리케이션을 만들 때에는 코드나 비즈니스 로직을 구현하는 과정이 중요하지만, 실제로 운영이 이루어지는 런타임에서는 무엇보다 '데이터'가 가장 영향력이 크고 관심의 대상이 되는 존재가 됩니다. 여기서 배와 배꼽의 관계가 역전되죠. 애플리케이션의 로직이나 코드는 배포 이후에 고정되어서 작동하지만, 데이터는 계~속 만들어지고 흐르기 때문에 잘 설계된 설계와 비즈니스 로직으로 그 흐름을 제어하지 못하면 애플리케이션을 지배하는 것이 데이터가 되는 상황이 발생하게 됩니다.

세상에 누구도 배보다 더 큰 배꼽을 달고 다니고 싶어하는 사람은 없겠죠? 애플리케이션도 마찬가지 입니다. 배보다 배꼽이 더 커지면 운영에 들어가는 비용이 기하급수적으로 늘어납니다. 그래서 웹이든 앱이든 애플리케이션을 구축할 때에 가장 신경쓰는 것이 전역 데이터의 관리입니다. 이 녀석, 즉 전역 데이터를 관리하는 것이 배꼽이거든요. 데이터는 배가 되겠죠?

그래서 가능하면 배꼽을 키우지 않기 위해서 간단하고 쉽고, 명확한 데이터 관리 방법이 필요한 겁니다.

 

6. Zustand는 Persistent 계층도 커버해 준다?!

그런데 앱을 운영하다보면 전역 값을 Persistent 계층에 보관하는 경우가 필요해 집니다. 이게 무슨 말이냐하면, 앱이 설치된 장치에 저장해야 하는 경우가 필요하다는 뜻입니다. 웹으로 치면 브라우저의 데이터 저장소에 저장하는 것과 같은 니즈라고 생각하면 됩니다.

앱을 사용하다가 종료하겠죠? 그런데 다시 앱을 실행 시켰을 때에 이전에 사용하던 데이터가 사라진다면 그 앱은 일회용 앱이 되고 말 겁니다. 그런 앱을 쓰는 사용자는 없겠죠? 그런데 이 Persistent 계층의 데이터를 관리하려면 별도로 AsyncStorage라는 녀석을 통해서 저장을 해야 합니다. 이 작업도 만만치 않게 귀찮은 녀석입니다. 잘못 관리하면 이녀석도 배보다 더 큰 배곱이 될 수 있습니다.

다행스럽게도 Zustand는 Persistent 계층의 데이터로도 저장할 수 있습니다. 별도로 이 기능을 위해서 다른 컴포넌트나 코드를 작성해서 이중으로 관리하지 않아도 된다는 뜻이죠.

방법도 매우 심플합니다. 아래와 같이 이전에 작성해 둔 전역 값 설정에 전역 값을 Persistent 계층에도 저장한다는 것만 알려주고, 저장하고 가져오고 지우는 방법에 AsyncStorage를 사용해서 작성만 해 주면 됩니다.

import {create} from 'zustand';
import {persist} from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';

interface CounterState {
    count: number;
    increment: () => void;
    decrement: () => void;
}

export const useCounterStore = create<CounterState>()(
    persist(
        set => ({
            count: 0,
            increment: () => set(state => ({count: state.count + 1})),
            decrement: () => set(state => ({count: state.count - 1})),
        }),
        {
            name: 'counter', // 저장될 key 값
            storage: {
                getItem: async name => {
                    const value = await AsyncStorage.getItem(name);
                    return value ? JSON.parse(value) : null;
                },
                setItem: async (name, value) => {
                    await AsyncStorage.setItem(name, JSON.stringify(value));
                },
                removeItem: async name => {
                    await AsyncStorage.removeItem(name);
                },
            },
        },
    ),
);

위의 코드는 이전에 작성했던 코드와 같은 파일입니다. 그런데 몇 가지가 추가되어 있습니다.

create를 사용할 때에 persist라는 함수에 이전에 사용했던 구현 내용을 넣어주고, 뒤에 Persistent와 관련된 설정을 추가만 해 주면 됩니다. 잘 보시면 값을 넣고, 가져오고, 그리고 삭제할 때에 AsyncStorage를 사용해서 값을 CRUD하고 있죠? 이렇게 만 해 주면 다른 것들은 바꿀 필요가 없습니다. 그냥 동일한 방식으로 사용만 하면 됩니다.

 

7. 결론

어때요? ReactNative 전역 데이터 관리... 이렇게 하니까 쉽고 명료하지 않나요?

사실 이 방법을 이해하고 사용할 수 있게되면 앱을 제작할 때에 컴포넌트가 매우 자유로워지고, 확장할 수 있는 가능성이 기하급수적으로 늘어납니다. 명확한 경계만큼 유지보수에도 엄청난 생산성이 만들어 집니다.

이전엔 이 모든 것들을 Redux를 사용해서 했습니다. Redux도 매우 훌륭한 라이브러리 입니다. 확장성도 매우 높아서 어디서든 전역 데이터를 사용하는 곳이라면 거의 만능처럼 여겨졌습니다. 하지만 높은 학습곡선과 보일러 플레이팅 같은 중복된 작업 때문에 개발자들의 불평이 점점 늘어갔죠. 누군가 처음에 기준을 잘못 잡아두면 이후에 작업하는 사람들이 애를 많이 먹었습니다. 그리고 불편하니까 각기 다른 방식으로 작업하기 시작하면 결국 그 애플리케이션은 금새 이 전역 데이터 때문에 레거시화 되어 갑니다.

React에서 직접 만든 Recoil도 매우 훌륭하고 천재적인 전역 라이브러리입니다. 하지만 저의 개인적인 생각으로는 Zustand 만큼의 명확성이나 편의성을 제공하는 데에는 조금 부족한 면이 있는 것 같다는 느낌을 받았습니다.

사실 Redux도 Recoil도 쓰는 사람이 숙련되어 있다면 어떤 것을 써도 괜찮습니다. 하지만 기억해야 하는 사실 하나는 '내가 작성하는 코드를 더 많이 보는 사람은 내가 아니다' 라는 겁니다. 내가 어려운 기술을 익혀서 무엇인가를 만들었는데, 그걸 누군가 보고서 유지보수를 해야 하는 상황이 더 많다는 거죠. 그래서 쉽게, 더 쉽게... 그리고 간단하고 명료하게, 더 간단하게 작성하는 것이 좋습니다.

프로젝트를 진행하다보면 가끔 '굳이' 저렇게 어렵게 만들지 않아도 되는데, 마치 '자기 역량을 반영하기 위한 것처럼' 과하다 싶을 정도로 복잡하게 작성된 코드들을 봅니다. 동료들은 죽을 맛이겠죠? 코드를 작성할 때에는 멋있어 보이고 스스로 칭찬할 만큼 복잡하고 어려운 기술을 잘 반영해서 돌아가는 것처럼 보이겠지만, 문제는 그 코드를 더 많이 봐야하는 사람은 다른 사람일 가능성이 높다는 겁니다. 네, 맞습니다. 프로젝트는 나 혼자 하는게 아닙니다.

반드시 그 기술로 만 문제를 해결할 수 있다면 꼭 그 기술을 사용해야 만 합니다. 그리고 그 기술이 학습곡선이 높다면 그 프로젝트가 관리비용이 높아서 유지보수 하는 시점에 높은 코스트의 기술 비용을 지불해야 한다는 사실을 인지하고 가능한 쉽게 설계를 해서 사용하고, 해당 내용은 모두 소스코드에 반드시 주석으로 꼼꼼하게 설명을 해 두어야 합니다.

잠시 꼰데가 되겠습니다. 요즘 소위 '클린코드'라는 유행을 타고 소스코드에 주석을 달면 '실력 없는' 개발자라는 낙인이 찍힌다는 이야기를 들었던 기억이 있습니다. 정말 주석이 없는 코드가 '클린'한 코드일까요? 너무 교조적인 풍조에 휩쓸려 잘못된 길로 가고 있는 것은 아닌가하는 염려가 조금 있습니다. 

다시 원점으로 돌아가서, 위에서 지금까지 이야기 해 온 내용의 핵심이 뭘까요? 바로 '쉽게' 입니다. 모든 문제는 복잡해져 가는 상황에서 발생합니다. 그리고 우리 개발자들은 숙명과도 같이 그 복잡성을 쉽게 풀어내어야 하는 사람들입니다. 우리 스스로가 기술에 매몰되어서 복잡한 요구사항에 기술적인 옷을 입혀서 더 전문적으로 '어려운'이라는 환경을 추가해서는 안됩니다. 그래서 '전역 데이터 관리'라는 조금은 불편한 작업에 대한 이야기를 시작했고, Zustand라는 라이브러리를 통해서 쉽게 '전역 데이터 관리'를 하는 방법을 소개해 드렸습니다.

전역 데이터 관리... 어때요? 쉽죠? 그럼 이제 여러분이 더 쉽게 만들어 보세요.

반응형