(장준영)Vanilla JavaScript로 SPA 구현하기 [2일차] - 식당/카페 여석 확인 어플리케이션

2024. 4. 10. 11:45프로젝트

1일차에 나는 어떻게 클라이언트쪽으로 json 데이터를 보내는 api의 내부를 디자인해야

CSR SPA의 장점인 서버와 디비 비용의 최소화에 적합할까? 에 대해 고민했었고

 

이미 작성된 SPA 의 서버쪽 api 코드들과 뤼튼한테 물어보는걸 통해 영감을 좀 얻으려했다

뤼튼한테 먼저 물어봤다

장인의마음으로

HTML CSS Javascript Node.js Express MongoDB 를 이용해서 SPA를 만들고있는데 서버에서 어떤 방식으로 json 데이터를 디자인해야 CSR의 목적인 서버와 DB 비용 절감에 적합하게 api를 만들 수 있을까?

뤼튼
AI 검색
 

답변 진행 과정

 
 
 

SPA를 위한 서버 및 DB 비용 절감을 위한 JSON 데이터 디자인 방법

SPA(Single Page Application) 개발에 있어서 클라이언트 사이드 렌더링(CSR)의 목적은 서버와 데이터베이스(DB) 비용을 절감하면서 사용자에게 빠른 반응 속도를 제공하는 것입니다. 이를 위해 서버에서 JSON 데이터를 효율적으로 디자인하는 것이 중요합니다. 아래는 서버에서 JSON 데이터를 디자인할 때 고려해야 할 몇 가지 방법입니다. 🙂


RESTful API와 JSON 데이터 구조

  • RESTful API 디자인: RESTful API는 웹 표준을 따르며, 자원(Resource)의 상태 정보를 JSON 형태로 전달합니다. 이를 통해 클라이언트와 서버 간의 통신을 효율적으로 할 수 있습니다. 1
  • JSON 데이터 최적화: 필요한 정보만을 최소한으로 포함하여 JSON 데이터의 크기를 줄이는 것이 중요합니다. 이는 네트워크 대역폭 사용을 줄이고, 클라이언트의 처리 속도를 높이는 데 도움이 됩니다.

데이터 캐싱과 비동기 처리

  • 데이터 캐싱: 자주 사용되는 데이터는 클라이언트 측에서 캐싱하여 서버 요청을 줄일 수 있습니다. 이는 서버 부하를 줄이고, 사용자 경험을 향상시킵니다.
  • 비동기 처리: 클라이언트에서 서버로의 요청은 비동기적으로 처리하여, 사용자의 인터랙션에 대한 응답성을 높이는 것이 좋습니다. 이를 위해 JavaScript의 fetch API나 XMLHttpRequest를 사용할 수 있습니다.

데이터 페이징과 지연 로딩

  • 데이터 페이징: 대량의 데이터를 한 번에 로드하는 대신, 필요할 때마다 작은 단위로 데이터를 요청하는 페이징 처리를 고려해야 합니다. 이는 초기 로딩 시간을 단축시키고, 서버 부하를 분산시킵니다.
  • 지연 로딩(Lazy Loading): 화면에 바로 보이지 않는 콘텐츠는 지연 로딩을 적용하여, 필요할 때만 데이터를 로드하도록 합니다. 이는 리소스 사용을 최적화하고, 사용자 경험을 개선합니다.

위의 방법들을 통해 서버와 DB 비용을 절감하면서도, 사용자에게 빠르고 부드러운 웹 애플리케이션 경험을 제공할 수 있습니다. SPA 개발에 있어서 이러한 접근 방법들은 매우 중요하니, 참고하시어 효율적인 애플리케이션을 만드시길 바랍니다! 🚀

그렇다고 한다..

RESTful API 디자인 > 잘 모르겠다 REST API 라고 해도 과연 그게 서버랑 디비비용 절감의 목적에 적합할까? 

JSON 데이터 최적화 > 필요한 정보만을 최소한 포함.. 간단하면서도 깊게 생각해보면 간단하지 않은 것 같다

데이터 캐싱 > 변동성이 없고 동시에 자주 값을 가져와야하는 데이터의 경우 모두 클라이언트 단에 로컬스토리지 같은곳에 데이터를 넣어두고 거기서 가져다가 사용하면 서버와 디비의 비용을 절감할 수 있다 

비동기 처리 > 싱글 스레드에서 비동기를 어케하노?? ????? 

https://gruuuuu.github.io/javascript/async-js/

 

Javascript 비동기 함수의 동작원리 (feat. EventLoop)

Overview 이번 포스팅에서는 최근 Javascript관련 포스팅 3개를 작성하면서 개인적으로 궁금했던 내용을 다뤄보려고 합니다. (1) 호다닥 톺아보는 Callback 함수 (2) 호다닥 톺아보는 Promise (3) 호다닥 톺

gruuuuu.github.io

설마 설마 하니까 무거운것들 큐로 보내고 스택에서 가벼운것들 다 실행 끝내고 스택 다 비면 큐에꺼 꺼내서 실행해주는 자바스크립트 로직을 그냥 비동기? 라고 치고 표현하는 것 같다.. 그냥 ajax 쓰라는것 같은데?? 뭐라는 말인지 솔직히 모르겠다 

데이터 페이징 > 이거 그냥 데이터바인딩으로 CSR 해주는거 말하는 거 같다

지연 로딩(Lazy Loading)> 뭔말인지 모르겠다

그냥 화면에 바로 보이는 것들이랑 바로 안 보이는것들을 렌더링할때 필요한 데이터들을 가져오는걸 구분해서

화면에 바로 보이는것들을 먼져 가져와서 데이터바인딩 시켜주고 그 다음에 안 보이는 것들, 인터렉팅을 해야 보이는것들에 필요한 데이터들을 가져와줌으로써 CSR의 단점인 첫 페이지 로딩이 긴 부분을 보완해라? 라는 말 같은데... 뭐 일단 알겠다

 

근데 클라이언트 

데이터 캐싱, 데이터페이징, 지연 로딩 이런거 다 클라이언트 단에서 처리해줄 일이고 지금 생각하고있는 서버단에서 필요한 정보는 JSON 데이터 최적화 뿐이다, 일단 제이슨 최적화 라는 당연한 소리만 건졌다 ^^ 

 

이렇게 된거

SPA 만들떄 서버쪽 json api 코드를 찾아서 한번 보자...

아 아니다 귀찮다

아직은 JSON 데이터 뭐 가져올지도 기능설계도 안 됐는데.. 일단 회원가입 로그인 기능이나 구현해놓고 와야겠다

 

에잇! 모르겠다! 일단 회원가입을 만들고 기능을 생각해야겠당 ^^

SSR로 만들었다면 회원가입 a테그로 get 요청 보내면 서버에서 받아서 회원가입창 렌더링해서 클라이언트쪽으로 보냈을건데

SSR이 아니라 CSR이니 회원가입 화면도 get 요청이 아닌 이벤트리스너로 클릭 받아서 회원가입 창 만들어주면 된다

<script>
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////아래부터 화면 빌드를 위한 코드들이 모이는공간 /////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        //첫화면 셋팅 함수
        function 첫화면만들기(){
            $('.app__container').append(`
        <div class="home__container">
            <div class="home__filter"></div>
            <div class="home__content">
                <p class="home__text">매이플에서도 자리싸움 하는데! 카페에서는 <span style="font-size: 50px;">왜???</span></p>
                <p class="home__subtitle">자리싸움이 필요할때❤️</p>
                <h1 class="home__title">거기. 내 자리</h1>
            </div>
            <div class="home__box">
                <form>
                    <input type="text" style="display: block; margin-left: auto; margin-top: 40px; margin-right: auto; width: 90%; height: 40px; font-size: 40px;" placeholder="아이디를 입력해라">
                    <input type="text" style="display: block; margin-left: auto; margin-top: 20px; margin-right: auto; width: 90%; height: 40px; font-size: 40px;" placeholder="비밀번호도 쫌 입력하고">
                    <button type="submit" style="display: block; margin-left: 50px; margin-top: 20px; font-size: 20px;">로그인</button>
                </form>
                <p style="display: block; margin-left: 50px; margin-top: 40px;"><button href="#/" class="register" onclick="회원가입버튼클릭()">회원가입</button> <button href="">아이디/비밀번호 찾기</button></p>
            </div>
        </div>
        `)
        }
        //회원가입 버튼 누르면 
        function 회원가입버튼클릭(){
            $('.app__container').append(`
            <div class="register__container">
                <div class="register__filter"></div>
                <div class="register__box">
                    <h1 class="register__subtitle">자리싸움이 그마이 하고싶나..?<br>그래..<br>하고싶다 카는데 우야겠노..</h1>
                    <h1 class="register__title">해삐라</h1>
                    <input class="input_for_username" type="text" name="username" placeholder="가입할 닉네임 입력해라" style=" margin-left: auto; margin-top: 20px; margin-right: auto; display: block; width: 90%; height: 30px; font-size: 30px;">
                    <input class="input_for_password" type="password" name="password" placeholder="가입할 비번 입력해라" style=" margin-left: auto; margin-top: 20px; margin-right: auto; display: block; width: 90%; height: 30px; font-size: 30px;">
                    <button class="register_to_server_post" type="submit" style="display: block; margin-left: auto; margin-top: 30px; margin-right: auto; width: 200px; height: 30px; font-size: 20px;">회원가입</button>
                    <button class="register_to_home" style="display: block; margin-left: auto; margin-top: 10px; margin-right: auto; width: 200px; height: 30px; font-size: 20px;">돌아가기</button>
                </div>
            </div>
            `)
            $('.register_to_server_post').click(function(){
                $.post('/register', {
                    //username 중복검사 코드 클라이언트쪽에 써줘야함 써버낭비 ㄴㄴㄴ
                    username : $('.input_for_username').val(),
                    password : $('.input_for_password').val()
                })
            })    
            $('.register_to_home').click(function(){
                $('.app__container').empty()
                첫화면만들기()
            })    
        }
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////위에까지 화면 빌드를 위한 코드들이 모이는공간 /////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        

        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////아래부터 화면 빌드를 하는 코드들이 모이는공간 /////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        첫화면만들기()
    </script>

 

어펜드를 엄청많이 써야해서 모든 어펜드들을 함수화 시켜줄 생각으로 코드를 작성했다, 그리고 거기 안에 들어가는

이벤트 코드들은 쌩으로 어펜드 밑에다 만들어줄 생각이다 

SSR로 만들땐 프론트? 라는 개념이 없지만 있다면 진짜 화면싸게에 불과한데

CSR로 만들떈 빽엔드쪽은 api싸개가 되버리는 것 같다, 프론트가 정말 바쁘다 ㅠ

 

이벤트 주고 뭐 하고 할때

식별자는 클래스로 지정할거다

클래스 이름을 지정하는 규칙을 한번 정하고 시작할거다

 

class="register_to_home"

레지스트 페이지 에서 홈 페이지 로 페이지를 전환하는 연출을 하는 역할

class="register_to_server_post"

레지스터 페이지에서 서버로 포스트 요청을 날리는 역할

 

이런식으로 페이지와 페이지 사이의 나타나고 사라지고 등의 연출을 하는 기능의 클래스를

페이지명_to_페이지명 으로 지정할거고

페이지에서 서버로 요청을 날리는 기능의 클래스를

페이지명_to_server_요청종류 으로 지정할거다

 

아이디 중복 검사는 클라이언트단에서 1차적으로 검사 돌려줄거고

비번 해싱은 서버쪽에서 담당할거다 

 

아이디 중복 검사 전에 정규식 써서 비번 형식에 맞게 입력 잘 했는지 먼저 검사 해줄거다

 

근데 갑자기 드는 생각인데 비번 정규식으로 검사하는 코드 짜버리면 테스트할때 너무 불편하고 짜증나잖아?

응~~~ 그래서 안 할꺼야~~~ 귀찮아

 

아이디 중복 검사를 돌려줘야하니까 

서버에서 유저id 정보를 다 받아와야한다

자 이제 뇌라는걸 써야할때가 왔다 

>>> 

데이터를 가져오는 형태가  2가지가 될 수 있음

1. 모든 유저의 이름만 다 가져온다 > 당장 회원가입 시 이름 비교를 위해 사용되니까

2. 모든 유저의 민감한 정보를 제외한 모든 데이터를 다 가져온다 > 당장은 필요없어도 일단 다 필요하긴 하니까

 

처음 페이지 로딩에 필요한 데이터인가?? = ㄴㄴㄴㄴ

자주 사용하는 데이터인가?? = 유저간 자리 싸움하는 어플리케이션 특성상, 유저 데이터에 접근 할 가능성이 높음

자주 사용되는 코드인가?? = 처음 회원가입할때만 필요함, 하지만 사용자 수가 올라갈수록 사용빈도도 따라서 증가

이 코드를 위해서 안 가져와도, 레이지 로딩때 가져올 데이터인가?? = 

 

>>>

다시 생각해보니 유저ID 자체가 민감한 데이터라 처음 한번에 다 받아와서 캐싱해줬다 치자 

이제 앙김옥찌 라는 아이디로 회원 가입을 할건데, 갑자기 그순간 다른사람이 앙김옥찌 라는 아이디로 회원가입을 해버려서 디비에 앙김옥찌라는 아이디가 들어갔다면?, 서버단에서 최종적인 방어를 해주긴 하겠지만, 어차피 서버단에서 방어할거니 클라이언트 단에서 방어를 딱히? 해줄 일은 없을것 같다, 클라이언트 단에서 유저 데이터를 요청할때마다 받아서

클라이언트 단에 아이디 중복 검사 처리를 하게 하더라도 어차피 서버단에서 다시 제대로 검사를 해 줘야만 한다

왜?? 클라이언트 단에 최신 유저 데이터를 요청했다고 해도, 클라이언트 단에 도착한 이상 결국 그 데이터는 더이상 최신 데이터가 아니게 된다, 그래서 클라이언트 단에서 아이디 중복 검사를 해주는거 자체가 프론트쪽 낭비라고 생각이 든다 

그러니 클라이언트 단에서 아이디 중복 검사를 하지 말고 아이디 중복 검사하는 일은 서버쪽으로  넘겨야하는게 효율적으로 맞다 

>>>> 뭔가 얻은 것 같은 교훈??

= 중요한 데이터들, 다시말해 프론트쪽에서 아무리 검사를 했다고 한들 어차피 서버쪽에서 교차검증을 해줘야한다

그러니, 프론트쪽에서 이뤄지는 검사는 뺵에서 검사하는걸 약간? 쓰잘떼기 없는것들? 정도만 검사를 해서 도와주면

그게 최선인거같다, 데이터 정확도에 대한 책임은 서버쪽에서 담당을 하는게 맞는거 같고, 프론트쪽에서는

그냥 굳이 서버에서 안 해도 될일을 하는게 맞는 것 같다, 프론트입장에서 욕심내서 생각을 하면 안 되고, 서버쪽 입장에서 생각을 하고 프론트는 그냥 서버의 불편함을 살짝 덜어주는거로 만족을 해야할 것 같다, 

결국 서버에서 보는 디비 데이터와, 클라이언트에서 보는 디비 데이터중 서버에서 보는 디비 데이터가 더 최신일 수 밖에

없는 문제로 인해, 결국 프론는 짐을 더는 것 에서 만족할 수 밖에 없는 것 같다..

>>>

>>> 결론 :

아이디 중복 검사는 프론트에서 담당하지 않는다, 서버에서 온전히 담당할것이고, 그로 인해 프론트쪽에 유저id 데이터를 가져오는 일은 낭비이다, 프론트쪽에서 아이디 중복검사를 위해...... 아..씹.. 잠만..

>>> 갑자기 드는 생각 :

위와같은 동시에 같은 아이디로 회원가입 요청같은 특이 케이스를 제외한다면, 이미 있는 아이디를 중복검사 하는 케이스까지 생각을 해준다면 서버에서 하는 일을 덜어주는... 아니 새끼야 어차피 서버에서 교차검증 할꺼라니까???

어차피 할껀데 뭘 계속 프론트에서 낭비질이냐, 그거 프론트에서 해도 어차피 서버에서 할꺼라고 2중으로 서버 낭비시키는꼴이라니까??? 

>>> 결론 :

아이디 중복 검사는 프론트에서 담당하지 않는다, 서버에서 온전히 담당할것이고, 그로 인해 프론트쪽에 유저id 데이터를 가져오는 일은 낭비이다, 프론트쪽에서 아이디 중복검사를 위해 유저에대한 데이터를 받아오는 일은 없을것이다

>>> 잠깐만??! :

아니 맞잖아! 

프론트쪽에서 이미 있는 이름으로 중복검사 해서 중복검사 통과 못 하면 아얘 서버로 요청도 못 가게 만들면

서버쪽 일을 프론트쪽에서 덜어내는게 맞잖아! 아무리 교차검증은 할거라고 해도, 이이름 있는지 저이름 있는지 찔러보는거에대해서는 프론트에서 담당을 해주겠다는 이야기잖아!! 

그리고 중복검사를 할때마다 서버에서 유저정보 받아오는게 아니라, 회원가입 버튼 눌렀을떄 딱 한번만 이미 가입된 회원정보 받아오면 댐, 그래서 클라이언트에서 비교해줄거고 최종적으로 서버에서 비교를 해줄거임 이후 통과 했을 경우에

디비에 인서트해줄꺼고 ㅇㅋ??? 

>>> 결론 : 

회원가입 버튼 클릭할때 딱 1번만 유저 이름정보 가져와줄거다 

클라이언트 쪽에서 이미 가입된 이름과 새로 가입하려는 이름이 일치하는게 없는지 중복검사를 때려줘서 서버의 일을 덜어줄거고

클라이언트 쪽에서 이름 중복검사를 통과하면 서버쪽으로 post 요청이 갈꺼다

서버쪽에서 이름 중복검사를 2차적으로 하고 디비에 동일한 이름이 없을 경우 디비에 회원정보를 인서트하게 될거다

>>>> 인사이트 : 

클라이언트 쪽에서 서버쪽의 일을 덜어주려면, 최대한 클라이언트쪽에서 많은 의견을 제시하며 나대야한다

이렇게 저렇게 우리가 도와줄게!! 하면서 찔러보고 동시에 면밀하게 서버의 업무를 분석하면서 효율적인 방법을

최대한 찾아나가야한다.. 이렇게 하다보면 어느정도 정답? 이라 부를만한것들이 만들어질 것 같다 

 

암튼 다음시간에 회원기능 만들거임