본문 바로가기
BackEnd

API Architecture에 대해

by SoriKim 2023. 11. 12.
반응형

1. 코드 구조의 중요성

하나의 파일에 모든 코드를 구현하는 방법의 장점은 간단하다는 것입니다. 한 파일에서 확인할 수 있으므로 신경 써야 할 파일 개수가 줄어들며, 개발이 전체적으로 더욱 간단해집니다. 하지만 한 파일에 코드의 양이 조금만 많아져도 이런 간단함의 장점은 잃어버리고 코드의 유지 보수가 어려워집니다. 실제 기업 시스템에서 하나의 파일에 모든 코드를 넣은 경우는 거의 없습니다. 실제로 논리적으로 또는 기능적으로 영역을 구분하여 개별 코드를 관리하는 것이 좋습니다. 

이런 코드의 구조를 더 체계적으로 그리고 효율적으로 구현해 놓은 것을 코드의 아키텍쳐(architecture)라고 합니다. 

이제 어떤 코드를 어떤 기준으로 나누어 구조화해야 하는지 알아봅시다. 

 

1️⃣ 확장성

모든 코드는 처음 조금한 규모에서 시작합니다. 간단한 시스템이라도 서비스가 발전할수록 시스템도 커져갈 수밖에 없습니다. 따라서 시스템을 구현할 때는 확장성이 중요합니다. 확장성을 고려하지 않고 구현한 코드들은 시스템의 규모가 커질수록 문제가 많이 생길 확률이 높아집니다. 그러므로 확장성이 높은 구조로 코드를 구현하는 것이 중요합니다. 

 

2️⃣ 재사용성

한 번 작성한 코드를 필요에 따라 다른 여러 곳에 사용할 수 있는 특징을 말합니다. 재사용성이 높아야 코드의 양이 적어지고 개발의 속도도 높아지며, 코드 또한 더 안전하고 견고한 코드를 구현하기 쉽니다. 코드 구조상 재사용성은 일반 코드 레벨의 재상용성, 즉 함수나 클래스를 재사용하는 수준의 재사용성보다는 구조적 재사용성을 이야기합니다. 

 

3️⃣ 유지 보수 가능성

코드는 한 번 작성된다고 끝나는 것이 아닌 여러 개발자, 여러 팀이 수정하고 유지보수하게 됩니다. 유지보스는 소프트웨어 지속 가능과 연결된 중요한 요소입니다. 유지 보수가 쉬운 코드를 구현하기 위해 구조적으로 로직이 잘 정리가 되고 나뉘어 있어야 합니다. 반대로 여러 로직이 함께 뒤엉켜 있는 코드일수록 유지보수가 힘들며 이런 코드를 스파게티 코드(spaghetti code)라고 합니다. 스파게티처럼 뒤엉켜 있는 코드라는 뜻입니다. 그러므로 함수나 클래스 등을 사용해 코드를 추상화(abstraction)하고 서로 독립적인 로직을 분리해 필요한 곳에 적절하게 사용되도록 하는 코드를 구현해 유지 보수를 더 쉽게 할 수 있도록 해야 합니다. 

 

4️⃣ 가독성

코드 가독성이란 다른 개발자들이 코드를 읽었을 때 얼마나 이해하기 쉬운가를 나타내는 특징입니다. 어려운 로직일수록 더욱 가독성이 높게 구현해야 합니다. 

 

5️⃣ 테스트 가능성

코드는 작성된 이후로, 제대로 동작하는지 테스트가 이루어지게 됩니다. 로직이 간결할 수록 테스트를 진행하기도 수월합니다. 테스트가 잘 구현된 코드는 추상화가 잘 되어있고, 한 가지 역할만 하는 코드입니다. 코드의 구조도 마찬가지로 추상화가 잘 구현되어 있고 담당하는 역할이 잘 나뉘어 있는 구조가 테스트하기 쉬운 구조가 됩니다. 

 

 

2. 관심사 분리(Separation Of Concerns) 

🔵 역할이 분리되어 있지 않다는 것은

API 서버를 커피숍에 비유해보면, 고객이 음료를 주문(request)하면, 직원(Server)은 냉장고(Database)에서 재료(Data)를 준비하고, 제조해 고객에게 제공(response)합니다. 

여기서 직원의 역할은 고객 맞이, 주문받기, 메뉴 질문, 주문 확인, 재료 가공, 제조, 제공까지 많은 역할을 수행하게 됩니다. 규모가 작을 경우 혼자 이 모든 업무를 담당하는 것이 편할 수 있습니다. 왜냐하면 의사결정 속도가 빠르고, 일 처리가 간결하게 지기 때문입니다. 하지만 규모가 커지고, 고객이 많아진 상황에 한 사람이 하는 역할이 많고 복잡해진다면 다음과 같은 문제가 발생할 가능성이 생깁니다. 

- 직원의 역할이 명확하지 않아 실수할 확률이 높다. 

- 실수의 원인을 파악하기 어렵다. 

- 하고 있는 일이 많아 직원에게 문제가 발생해도 대체할 수 있는 자원을 찾기 어렵다. 

 

이렇듯 효율적인 업무 처리를 위해 분업이 필요합니다. 고객을 응대하는 서버 직원, 음료를 제조하는 제조 직원, 직원끼리 소통을 책임지고 매니징을 하는 매니저 직원까지. 업무가 효율적으로 그리고 혼선 없이 진행되기 위한 역할 분리가 이루어져야 합니다. 

 

🟡 직원1 역할: 고객 맞이, 주문받기, 메뉴질문, 제공

🟡 직원2 역할: 주문확인 

🟡 직원3 역할: 재료 가공, 음료 제조, 재료 준비, 재료 가져오기

 

위와 같이 직원들의 역할을 분리하면 아래와 같은 이점을 얻을 수 있습니다. 

1️⃣ 확장성

각 직원이 맡은 역할에 집중하여, 카페가 더욱 확장된 업무의 혼선이 적다. 

[직원 1은 고객 요청사항에 집중, 직원 2는 직원 의사소통에 집중하고 식당 내부 과정 파악, 직원 3은 냉장고 상황 및 제조에 집중] 

 

2️⃣ 재사용성

기존 주문만 받던 카페에 배달의 민족으로 주문 할 수 있도록 새로운 기능을 추가한다면 배달의 민족 주문만 확인해 제조직원에게 전달만 해주면 됩니다. 때문에 사람을 새롭게 채용할 필요 없이 기존 주문을 확인하던 직원 2가 역할을 동일하게 수행할 수 있습니다. 

 

3️⃣ 유지 보수 가능성 

외부 문제 상황 발생 시(고객의 잘못된 주문, 제조 음료 재료의 부족) 문제 파익이 원활하고, 대응 속도가 빨라집니다. 

 

4️⃣ 가독성

어떤 직원이 어떤 역할을 수행하고 있는지 파악이 수월하다. 

 

5️⃣ 테스트 가능성 

각 역할의 수행 정도를 가늠하기 편리하다. 

 

이렇게, 역할이 제대로 분리되어 있지 않다는 것은 하나의 시스템을 체계적으로 관리하기 어렵다는 것을 의미합니다. 따라서 역할에 따른 분리로 더 나은 시스템을 만들어갈 수 있습니다. 서버 코드 또한 역할에 따라 파일을 분리하여 보다 구조화(모듈화)된 시스템을 만들 수 있습니다. 

 

🔵  역할에 따른 코드 분리 

역할에 따라 코드를 분리해 구조화를 진행합니다. 여기서 '구조'란 파일을 꼭 파일을 분리하는 것은 아닐 수 있습니다. 프로그램 자체의 구조를 뜻하기도 하며 편의상 파일로 분리하는 과정을 진행하고 점진적으로 소프트웨어 아키텍처 자체를 이해하는 것으로 폭 넓혀가는 것이 좋습니다. 

 

HTTP 통신 처리하는 서버의 상황도 이와 크게 다르지 않습니다. 고객의 요청(주문)이 들어오면 서버는 데이터(재료)를 가공해 요청에 알맞은 응답(음료제조)을 반환합니다. 

 

 

서버가 하는 역할을 자세히 뜯어보면 굉장히 다양한 기능이 혼재되어 있습니다. 

예를 들어 회원가입을 하는 로직을 생각해보면 

  • 클라이언트로부터 요청 받기 
  • Request에 누락된 Key가 없는지 확인해 Key Error를 캐치
  • 비밀번호 길이를 확인해 유저의 존재 유무를 확인
  • DB에 Insert Into 문을 전송해 데이터를 저장
  • 제대로 데이터가 저장됨을 응답으로 전송

이런 많은 기능이 app.js 파일 하나에 일어나고 있을 것입니다. 

이런 코드는 스파게티 코드로, 하나의 기능을 수정하거나 교체하려고 하면 파일 내부 모든 다른 코드들이 지장 받을 가능성이 높습니다. 그리고 특정 파일에서 오류가 발생하면 해당 파일 내부에 있는 다른 코드들 또한 오류에 영향을 받을 수 있습니다. 코드가 조금만 많아져도 파일이 복잡해 가독성이 떨어지는 문제도 발생됩니다. 

 

따라서 코드의 역할에 따라 파일을 분리해야 하며, 크게 다음과 같은 기준으로 분리합니다. 

  • [파일 1] HTTP Request/Response 처리 
  • [파일 2] Business Logic 처리 
  • [파일 3] Database 통신 처리 

여기서 파일 1은 Client로부터 받은 요청 자체에 관련된 일만 처리합니다. 

[ 예를 들어 Requset body에서 데이터를 꺼내며 Json Response로 제품 정보를 전달 ]

 

파일 2는 우리 서비스가 결정한 규칙에 따른 일들만 처리합니다. 

[ 예를 들어 비밀번호의 길이는 8자리 이상으로 규정하며, 이미 가입한 이메일로는 중복 가입을 허용하지 않으며, 비밀번호는 암호화해 저장 ]

 

파일 3은 데이터베이스와의 통신만 처리합니다. 

[ 예를 들어 데이터를 Insert Into로 저장하며, Select로 데이터를 가져옴]

 

이렇게 분리된 구조로 코드를 구현하면 코드의 확장성이 높아집니다. 각 파일에 포함되어 있는 코드의 목적이 명확하고 범위도 확실하기 때문에 코드의 구조를 파악하기도 쉽습니다. 또한, 각 파일이 서로 독립적이고 역할이 분명하여 서로에게 끼치는 여향을 최소화하며 확장하거나 수정이 가능합니다. 

 

주된 역할과 집중해야 할 기능을 분리해 서로 다른 기능을 하는 파일은 신경을 쓰지 않도록 하는 것을 'Seperation Of Concern, 관심사의 분리'라고 합니다. 

반응형

댓글