디자인 시스템 네이밍 서포트 툴 개발기 - FE편

예리에르·2023년 8월 29일
2

Frontend

목록 보기
8/10
post-thumbnail

전에 작성했던 BE편은 모두 읽고오셨나요? ㅎㅎ 그 후편 FE개발 후기 입니다. 익숙하지 않았던 BE는 개발 시작부터 세세하게 개발기를 남겼지만 FE 개발자로 이번 글은 해맸던 부분을 해결한 내용 위주로 작성하겠습니다.

개발

비동기처리

❌ 문제점

요청으로 받아온 데이터를 다 풀지 못해서 .split(’’)에서 문제가 생김

export function requestAllHideNaming (response:(rs:any)=> void,complete:()=>void) {
    Http.Get('all/hide').call(response,complete)
};

...

runInAction(() =>{
            const {namingInfo} = this.props;
            this.features = namingInfo.map(naming => naming.feature);

            requestAllHideNaming(action((res)=>{
                this.features.map((feature)=> {
                    const hide = res.filter(r=> r.feature === feature)[0].hide;

                    const info = hide.reduce((acc:any,curr:any)=>{
                        const {attribute,feature_hide,attribute_hide} = curr;
                        const featureHideArray = feature_hide.split(",");
                        const attributeHideArray = attribute_hide.split(",");
                        acc.push({feature,attribute,
                            feature_hide:featureHideArray,
                            attribute_hide:attributeHideArray});
                        return acc;
                    },[]);
                    this.hideNaming = [...this.hideNaming,...info];
                });
            }),()=>console.log("done"));
        });
...

fetch를 통해 api를 호출하고 fetching한 결과를 callback 형태로 데이터 처리 하는 코드입니다.
여기서 겪었던 문제점은 10개의 Object 리스트가 this.feaures에 들어오는데 10개를 모두 처리한 데이가 나오는 것이 아닌 2개~3개 정도의 리스트 요소를 처리하면서 error가 발생하는 것이었습니다.

filter를 통해 hide 라는 리스트를 만들고 난뒤, reduce를 사용해 데이터를 처리하는 로직입니다. 비동기 콜백 함수 내부에 데이터를 처리하면서 여러 비동기 작업이 동시에 실행되어 데이터의 일관성과 정확성을 유지가 어려웠습니다.

즉, 비동기 작업이 순차적으로 실행되도록 보장되지 않았습니다.

⭕ 해결방법


runInAction(async () => {
            const {namingInfo} = this.props;
            runInAction(() => {
                this.features = namingInfo.map(naming => naming.feature);
            });

            const hideList = await requestAllHideNaming();

            // 개별 hide 항목을 처리하는 기능 정의
            const processHideEntry = (feature) => (curr) => {
                const { attribute, feature_hide, attribute_hide } = curr;
                const featureHideArray = feature_hide.split(",");
                const attributeHideArray = attribute_hide.split(",");
                return {
                    feature: feature,
                    attribute: attribute,
                    feature_hide: featureHideArray,
                    attribute_hide: attributeHideArray
                };
            };

            // 각 feature에 대한 hide 항목 처리

            const allHideData = await Promise.all(
                this.features.map(async (feature) => {
                    const hide = hideList.find((r) => r.feature === feature)?.hide || [];
                    const processedHideData = hide.map(processHideEntry(feature));
                    return processedHideData;
                })
            );

            // flat를 사용해 배열을 생성하고 staet 업데이트
            const flattenedHideData = allHideData.flat();
            runInAction(() => {
                this.hideNaming = flattenedHideData;
            });
        });

그래서 Promise.all을 활용하여 하나의 Promise로 만들어줬습니다. async를 사용해서 map 요소들을 각 Promise로 바꿔줬습니다. 그럼 Promise.all은 map 안의 요소들을 병렬로 수행하게 되고 완료될 때 완료 Promise를 반환해줍니다.

모든 요소들을 async/await를 통해 처리하는 것보다 소요시간이 줄어들었습니다.

여기서 주의해야 하는 사항은 병렬로 처리하기 때문에 순서가 중요한 경우라면 Promise.all로 관리하면 안됩니다.

암기로 async와 await 를 같이 사용해야 한다고 생각했지만 아니었습다. 용도에 따라 다르게 사용할 수 있다는 것을 알게되었습니다. async는 promise가 아닌걸 promise로 간편하게 바꿔줄수 있었다. new Promise를 사용했더라면 resolev,reject 를 추가해야했을텐데 좀더 코드를 간결하게 해결 할 수 있었습니다.!! ❤️‍🔥❤️‍🔥

배포

docker network 사용

백앤드와 프론트 엔드를 모두 구성하고 배포하는 경험은 처음이었습니다. 실제 서비스에서 개발을 진행하더라도 주어진 페이지 및 컴포넌트를 개발하였고 CI/CD를 구성할 기회는 거의 없었습니다.

서비스 분석을 통해 nginx를 통해 서버와 통신하는 방법을 개념적으로 알고 있었지만 실제로 적용해본 적이 없었는데 이번 프로젝트로 실제 nginx로 서버와 통신하는 CI/CD를 구성해보았습니다.

https://blog.wonizz.tk/2019/07/27/docker-network/
도커 네트워크를 사용하게 되면 외부에서 요청을 들어왔을 때 내부 컨테이너의 내부 IP가 만들어집니다.

도커 내부 포트 3000번으로 띄어진 n개의 컨테이너가 있더라도 컨테이너IP를 통해 구분해서 연결이 가능합니다.

deploy_desing_naming으로 구성된 네트워크가 있습니다. 외부에서 7070포트를 이용하여 서비스에 접근합니다. 그럼 컨테이너의 80포트에 접근하게 됩니다.

$ sudo docker run -it -d -p 7070:80 --network=deploy_design_naming design-naming/front

왜냐하면 7070포트는 컨테이너 80으로 연결되어 있기 때문입니다. nginx는 80 포트를 듣고 있다가 / , /api를 구분하여 연결을 구분합니다.

server {
    ...
            location ^~ /api/ {
            proxy_pass http://design-naming-was:3000/;
            proxy_set_header Cookie $http_cookie;
            proxy_set_header Origin $http_origin;
            proxy_pass_request_headers on;
            proxy_http_version 1.1;
        }

        location ~* \.(?:html?)$ {
            expires -1;
        }
    ...
}

was와 front는 이미 같은 네트워크에 있기 때문에 container 끼리는 name을 hostname 처럼 사용할 수 있습니다.

docker를 실행할 떄 --network 옵션이 들어간 이유?

현재 구성된 시스템은 백엔드를 배포할 때 docker-compose를 통해 deploy_design_naming이라는 네트워크가 생성되어 있습니다. 이미 존재한 네트워크에 프론트엔드 contiaer를 추가하기 때문에 해당 옵션이 추가 들어가 있는 것입니다! ㅎㅎ

마무리

프론트 엔드는 간단한 CRUD 화면으로 구성된 간단한 UI구성이었습니다. 하지만 요청하고 얻은 응답으로 데이터를 처리하는 과정이 복잡한 쉽지 않은 과정이었습니다.
이를 통해 통신에 대한 이해와 Promise에 대한 이해를 높일 수 있었습니다. 단순히 요청할때만 사용하는 것이 아니라 용도에 따라 일반 로직처리에도 사용할 수 있다는 사실을 알 수 있었습니다.

또한 직접 백엔드와 프론트엔드를 모두 배포하고 네트워크로 묶어보면서 인프라적인 지식도 높일 수 있었습니다. 여기서 나아가 docker-compose, docker-compose 끼리 네트워크를 형상하는 방법도 있는데 그건 추후에 포스팅 하도록 하겠습니다.😆💖😆💖

참고

profile
비전공 프론트엔드 개발자의 개발일기😈 ✍️

2개의 댓글

comment-user-thumbnail
2024년 4월 8일

안녕하세요! WONIZZ Blog 운영자입니다. 글을 참고해주셔서 감사합니다.

DNS가 변경되어 참고해서 링크 걸어주시면 감사하겠습니다.

https://blog.wonizz.tk -> https://blog.wonizz.com

1개의 답글