Post

MovieCommunitySite - CRUD 기능


Movie Community - CRUD 기능에 대하여

CRUD 기능은 데이터의 기본적인 관리 기능을 나타내는 약어로서,
Create (생성), Read (읽기), Update (갱신), Delete (삭제)의 4가지 기능을 말한다.
각 기능들에 대해 알아보자.

  • Create (생성)
    • 새로운 데이터 생성, 기존 데이터 복제하여 새로운 항목을 만드는 작업
    • 데이터베이스에서는 INSERT 문을 사용하여 새로운 레코드를 추가
  • Read (읽기)
    • 데이터 조회, 데이터 읽기
    • 데이터베이스에서는 SELECT 문을 사용하여 데이터를 검색
  • Update (갱신)
    • 기존 데이터 수정, 업데이트
    • 데이터베이스에서는 UPDATE 문을 사용하여 기존 레코드를 수정
  • Delete (삭제)
    • 데이터 삭제
    • 데이터베이스에서는 DELETE 문을 사용하여 레코드를 삭제

Movie Community 프로젝트

프로젝트를 진행하면서 회원가입, 마이페이지, 회원수정, 회원탈퇴, 게시글 조회를 하는 CRUD 기능 구현을 했다.
처음 만들어보는 프로젝트라 그런지 많이 어색했고 기능 하나를 구현 하는데 시간소모가 컸다.
각 기능을 구현 할 때 고민했던 점, 왜 그렇게 구현을 했는지, 어떤 점이 어려웠는지 등에 대해 말하고자 한다.

Create (생성), 회원가입 기능 개선

회원가입의 필수요소인 유효성 검사를 구현 할 때 고민을 많이 했다.
처음 ID 중복체크를 할 때 중복확인 이라는 버튼을 클릭해 유효성 검사를 하도록 했다.
하지만 ID를 입력할 때 실시간으로 유효성 검사를 하는 것이 사용자에게 더 효과적이라는 생각이 들었다.
그리고 버튼 클릭을 하는 것 자체가 불편하고 비효율적이라 생각했고, 옛날 회원가입 방식처럼 보였다.
그래서 찾아보니 화면 부분에서 키가 떼어질 때 마다 실행하는 keyup 이라는 함수를 알게되었다.
버튼 방식으로 구현 했을 때는 ID 전체를 한 번에 서버로 보내 확인했고,
keyup 함수로 구현 했을 때는 글자를 입력할 때 마다 서버로 보내 실시간으로 확인하는 방법이었다.
사용자는 실시간으로 확인하는 것이 편리할 것이고, 서버를 생각하면 버튼 방식이 효율적이었다.
하지만 커뮤니티 사이트라는 특성을 생각 했을 때, 사용자가 편리해야 사이트를 이용할 것이라는 확신이 들었다.
그래서 keyup 함수로 유효성 검사를 구현 했고, 정규 표현식을 이용해 ID 양식 제한을 두었다.
프로젝트를 진행할 당시에 keyup을 바로바로 확인하는 것이 비효율적이라는 생각을 하지 못했다.
다시 코드를 보니 keyup을 바로바로 확인하는 것이 아니라, 시간차를 주면 효율적이지 않을까 생각했다.
사용자 대다수가 ID 입력을 할 때, 1초 혹은 2초안에 작성하는 것에 초점을 두었다.
사용자가 키보드에서 손을 떼고 일정 시간이 지나고 검사를 하게 만들면 될 것 같았다.
그래서 방법을 찾아보게 되었고 디바운싱(Debouncing)에 대해 알게되었다.

디바운싱(Debouncing)이란 ?

일정 시간 동안 이벤트 반복 호출을 제어, 불필요한 연산이나 서버 요청을 방지하여 효율적인 동작을 할 수 있게 한다.
필자가 찾던 기능이 디바운싱이었고, 불필요한 서버 부하를 제거하는 효율적인 방법이라 코드에 적용해 보았다.
setTimeout, clearTimeout 함수를 사용하여 디바운싱 효과를 주었다.

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
31
32
33
34
35
36
37
function join() {
    let timeoutId;

    $('#userId').keyup(function() {
        let userId = /^[a-z0-9]{4,10}$/;

        if (!(userId.test($('#userId').val()))) {
            $('#idErrMsg').css('color', 'red').text('영문, 숫자 4자 이상 10자 이하로 입력하세요.');
        } else {
            // 이전에 예약된 중복 체크 작업이 있다면 취소
            clearTimeout(timeoutId);

            // 새로운 중복 체크 작업 예약
            timeoutId = setTimeout(function() {
                $.ajax({
                    url: 'checkUserId',
                    method: 'post',
                    contentType: 'application/json',
                    data: JSON.stringify({
                        userId: $('#userId').val()
                    }),
                    success: function(result) {
                        if (result == 1) {
                            $('#idErrMsg').css('color', 'red').text('이미 존재하는 아이디 입니다.');
                            $('#userId').focus();
                        } else {
                            $('#idErrMsg').css('color', 'blue').text('사용 가능한 아이디 입니다.');
                            $('#userId').blur(function() {
                                $('#idErrMsg').text('');
                            });
                        }
                    }
                });
            }, 1000); // 1000ms 디바운싱 지연 시간
        }
    });
}

디바운싱을 사용하지 않았을 때는 작성한 후 키가 떼어질 때 마다 유효성 검사를 하다보니,
보기에도 좋지 않았고 너무 비효율적으로 보였지만 디바운싱을 사용하니,
달라진 것이 확실하게 눈에 보이기 시작했다.
결과가 확연하게 차이가 나니 개선하길 잘했다는 생각과 하나 해냈다는 작은 성취감이 생겼다.
기능을 구현하면서 이 부분은 백엔드 보단 프론트의 업무에 더 맞다고 생각이 들었다.
하지만 이에 대해 알고 있으면 프론트 엔지니어와 원할한 협업이 진행 될 수 있다고 생각한다.
앞으로도 코드를 발전시킬 수 있는 방법을 생각해보고 적용해보는 습관을 길러야겠다. 이렇게 또 하나 배웠다.

계층화 아키텍처 또는 MVC 아키텍처란?

수업을 들을 때, 프론트 데이터를 컨트롤러에서 받아 컨트롤러에서 모든 로직을 처리한 후,
서비스로 넘기는 방법으로 배웠다. 그래서 프로젝트를 진행할 때도 이 방식을 사용해 구현을 했다.
하지만 프로젝트가 끝나고 코드를 다시 보는데 아무리 생각해도 컨트롤러에서 모든 로직을 처리한다면,
그냥 바로 DAO로 넘겨주면 되는 것이 아닌가? 서비스가 왜 필요하지 라는 의문이 들었다.
그래서 컨트롤러, 서비스, DAO에 대해 찾아보게 되었다.

  • 컨트롤러(Controller)
    • 역할과 책임
      • 사용자의 입력을 처리하고 요청을 수신하는 주체로써, 클라이언트와 서버 간의 인터페이스 역할을 한다.
      • 모델(Model)과 뷰(View) 간의 상호 작용을 조정하여 애플리케이션의 흐름을 제어한다.
      • HTTP 요청을 받아들이고, 요청에서 필요한 데이터를 추출
      • 비즈니스 로직을 호출하기 위해 해당 데이터를 서비스에 전달
      • 서비스로부터 받은 결과를 가공하여 적절한 응답을 생성하고 클라이언트에게 반환
      • 예외 처리 및 오류 핸들링을 수행하여 사용자에게 적절한 메시지를 제공
  • 서비스 (Service)
    • 역할과 책임
      • 비즈니스 로직을 포함하고, 컨트롤러로부터 받은 요청을 처리한다.
      • 데이터베이스 액세스, 외부 API 호출 등과 같은 영속성 계층과의 상호 작용을 처리한다.
      • 트랜잭션 관리, 데이터의 가공 및 검증 등을 수행한다.
      • 독립적으로 테스트 가능한 단위로 비즈니스 로직을 구현한다.
  • DAO (Data Access Object)
    • 역할과 책임
      • 데이터베이스와의 상호 작용을 처리하고 데이터 액세스를 추상화한다.
      • 데이터베이스 연결, 쿼리 실행, 결과 매핑 등을 수행한다.
      • 서비스나 컨트롤러에서 필요한 데이터를 데이터베이스에서 가져오거나 데이터를 저장한다.

컨트롤러와 서비스에 대해 찾아보니 배웠던 부분도 있고 몰랐던 부분들이 있었다.
컨트롤러에서 비지니스 로직 구현을 권장하지 않는다고 한다. 하지만 간단하고 빠르게 처리 하는 작업에서,
사용할 수 있다고 한다. 수업 때는 간단한 작업이라 컨트롤러에서 전부 비지니스 로직을 구현한 것 같다.
이런 부분들에 대해 수업을 할 때 설명을 해줬으면 좋았을 것이라는 생각이 들지만,
의문이 생겨서 찾아본 결과 더 많이 알게된 점도 있다. 혹시 이렇게 직접 찾아보라고 그렇게 알려줬던 것일까..?
시간이 지나 그 점에 대해서는 알 수 없지만 직접 찾아봐야 한다라고 생각하기로 했다.
직접 찾아본 후 내가 내린 결론은 아래와 같다.

  • Q1: 비즈니스 로직을 어디에 구현하는 것이 좋은가?
    • 비즈니스 로직은 주로 서비스(Service) 계층에 구현하는 것이 좋다.
    • 서비스 계층은 비즈니스 로직을 처리하고 관리하기 위한 역할을 수행한다.
    • 비즈니스 로직을 배치함으로써 여러 컨트롤러에서 동일한 비즈니스 로직을 공유하고 재사용할 수 있다.
  • Q2: 컨트롤러에서 간단한 작업을 처리, 복잡한 비즈니스 로직을 처리하는 것 간의 구분을 어떻게 할 수 있을까?
    • 컨트롤러(Controller)
      • 사용자 입력 검증, 요청의 전처리, 응답의 후처리와 같은 간단한 작업을 수행
      • 프레젠테이션 로직에 집중하며, 주로 데이터의 유효성 검사와 전달을 처리
      • 복잡한 비즈니스 로직이 필요한 경우 해당 로직을 서비스에 위임
    • 서비스(Service)
      • 복잡한 비즈니스 로직, 트랜잭션 관리, 데이터 액세스 등 기술적인 부분을 담당
      • 여러 컨트롤러에서 공통으로 사용되는 로직이나 데이터 액세스 작업은 서비스에서 중앙화하여 구현
      • 컨트롤러에 비해 높은 수준의 추상화와 비즈니스 도메인에 대한 이해가 필요한 부분을 처리

비지니스 로직이란?

컨트롤러와 서비스의 로직에 대해 고민을 하던 중, 비지니스 로직이라는 것을 알게되었다.
필자가 구현한 컨트롤러에서 처리하고 있던 코드가 비지니스 로직이라고 한다.
비지니스 로직이란 특정 업무나 도메인에 관련된 핵심적인 규칙, 계산, 처리, 결정 등을 수행하는 코드다.
크게 다음과 같은 종류로 나눌 수 있다.

  • 입력 유효성 검사 (Validation)
    • 사용자로부터 입력받은 데이터의 유효성을 검사하는 로직
    • 양식에 입력된 값이 필요 조건을 충족하는지 검사하는 것
  • 업무 규칙 (Business Rules)
    • 특정 업무 도메인에서 정의된 규칙을 구현하는 로직
    • 주문이나 결제 시 특정 조건을 만족하는지 검사하고 처리하는 것
  • 계산 및 처리 (Calculation and Processing)
    • 특정 값을 계산하거나 다양한 처리를 수행하는 로직
    • 세금 계산, 할인 적용, 주문 처리 등
  • 상태 관리 (State Management)
    • 시스템이나 애플리케이션의 상태를 관리하는 로직
    • 상태에 따라 다르게 처리되어야 하는 경우
  • 예외 처리 (Exception Handling)
    • 예외 상황을 감지하고 처리하는 로직
    • 비정상적인 상황에 대한 적절한 조치를 취하는 것
  • 흐름 제어 (Flow Control)
    • 비지니스 프로세스의 흐름을 제어하는 로직
    • 조건에 따라 다른 경로를 따르거나 반복적인 작업을 처리하는 부분이 해당

비지니스 로직에 대한 개념을 알게되고 서비스 레이어와 연관지어 생각해보니 확실히,
서비스에서 로직을 구현 하는 것이, 컨트롤러에서 클라이언트와의 상호작용에 집중할 수 있게 만든다고 느꼈다.
이렇게 수업을 들을 때 몰랐던 부분을 알아가며 직접 구현해보니 기억에 오래 남고,
내 지식으로 만드는 과정이라 생각하니 뿌듯하고 계속 하고 싶다는 생각이 마구마구 들었다.
앞으로도 멈추지 않고 필요한 부분에 대해 찾아가며 직접 구현해보는 습관을 만들어야겠다고 다짐했다.

DTO(Data Transfer Object)란?

회원가입, 마이페이지, 회원수정, 회원탈퇴 등을 구현 할 때 도메인의 객체를 사용하여 구현했다.
하지만 기능 구현 후 테스트를 할 때 데이터에 사용하지 않는 데이터까지 포함이 되는 상황을 경험했다.
회원 수정에서 로그인 할 때 사용하는 ID를 수정하지 않는다. 하지만 회원수정 할 때 계속해서,
ID의 데이터까지 넘겨주는 것이 비효율적이라 생각했다. 하지만 도메인 객체에는 ID가 없으면,
안되는 상황이라 이것을 해결할 방법을 찾다보니 DTO(Data Transfer Object)에 대해 알게되었다.

  • DTO(Data Transfer Object)
    • 데이터 전송을 위해 사용되는 객체
    • 데이터의 특정 부분이나 전체를 캡슐화하여 전달하고자 하는 목적에 맞게 설계된 객체

필요한 부분만 DTO로 만들어 사용하면 효율적으로 데이터 전송이 가능할 것 같았다.
DTO로 구현을 해보니 불필요한 데이터 없이 필요한 데이터만 사용하니 효율적이라는 생각이 들었다.
프로젝트를 만드는 것도 재밌고 모르는 부분을 알게되어 그 부분을 프로젝트에 적용할 때 더욱 재밌다.
앞으로도 이런 초심을 잃지않고 좋은 개발자가 되도록 공부를 해야겠다.