철벽 API 디자인을 위한 18가지 필수 규칙

철벽 API 디자인: 18가지 규칙

1. 서명 (Signature)

API 인터페이스(interface)를 통해 주고받는 데이터가 중간에 변조되는 것을 방지하기 위해, API 인터페이스(interface)에 서명(signature)을 구현하는 것이 종종 필요합니다.

API 요청자는 요청 파라미터(parameter), 타임스탬프(timestamp), 그리고 비밀 키(secret key)를 하나의 문자열로 합칩니다.

그런 다음 MD5나 다른 해시 알고리즘(hash algorithm)을 사용하여 서명(sign) 값을 생성합니다.

이 서명(sign) 값은 요청 파라미터(parameter)나 헤더(header)에 포함되어 API 서버로 전송됩니다.

API 게이트웨이(gateway) 서비스 측에서는, 게이트웨이(gateway)가 전달받은 서명(sign) 값을 가져옵니다.

그런 다음 동일한 요청 파라미터(parameter), 타임스탬프(timestamp), 그리고 비밀 키(secret key)를 사용하여 동일한 MD5 알고리즘(algorithm)으로 또 다른 서명(sign) 값을 생성합니다.

그리고 이 두 개의 서명(sign) 값을 비교합니다.

만약 두 서명(sign) 값이 일치하면, 해당 요청은 유효한 것으로 간주되고 API 게이트웨이(gateway) 서비스는 요청을 적절한 비즈니스 시스템으로 전달합니다.


만약 두 서명(sign) 값이 일치하지 않으면, API 게이트웨이(gateway) 서비스는 서명 오류(signature error)를 반환합니다.

왜 서명에 타임스탬프(timestamp)를 포함해야 할까요?

보안을 강화하고 동일한 요청이 반복적으로 사용되는 것(재전송 공격)을 방지하기 위해, 서명에 타임스탬프(timestamp)를 포함합니다.

이는 또한 비밀 키(secret key)가 해독될 가능성을 줄여줍니다.

각 요청은 합리적인 유효 시간(예: 15분)을 가져야 합니다.

따라서, 요청은 15분 동안 유효합니다.

만약 15분을 초과하면, API 게이트웨이(gateway) 서비스는 요청이 만료되었다는 오류를 반환합니다.

현재 서명에 사용되는 비밀 키(secret key)를 생성하는 방법은 두 가지가 있습니다.

  • 고정된 개인 키(Fixed Private Key, privateKey): 양측이 고정된 값을 비밀 키(secret key)로 사용하기로 합의합니다.

  • AK/SK 키 쌍(AK/SK Key Pair): API 제공자가 AK/SK 쌍을 할당합니다.

    SK는 서명 시 비밀 키(secret key)로 사용되고, AK는 accessKey라는 이름으로 요청 헤더(header)에 전송됩니다.

    API 제공자는 전달받은 AK를 사용하여 SK를 조회하고, 새로운 서명(sign) 값을 생성하여 검증합니다.

2. 암호화 (Encryption)

어떤 경우에는 API 인터페이스(interface)가 사용자 로그인 비밀번호, 은행 카드 번호, 이체 금액 등 매우 민감한 데이터를 전송합니다.

이러한 파라미터(parameter)들을 평문(plaintext)으로 공용 인터넷 망을 통해 노출하는 것은 극도로 위험합니다.

이러한 위험을 완화하기 위해, 암호화(encryption)를 반드시 구현해야 합니다.

예를 들어, 사용자 등록 인터페이스(interface)에서 사용자가 사용자 이름과 비밀번호를 입력한 후, 비밀번호는 암호화되어야 합니다.

일반적인 접근 방식은 AES 대칭 암호화(symmetric encryption)를 사용하는 것입니다.

  • 프론트엔드(front-end)에서는 사용자의 비밀번호를 공개 키(public key)로 암호화합니다.

    (비대칭 암호화 또는 하이브리드 방식일 수 있습니다.

    )
  • 등록 API는 이후 비밀 키(secret key)로 비밀번호를 복호화하고, 필요한 비즈니스 유효성 검사를 수행한 다음, 다른 암호화 방식(예: 해싱)을 사용하여 데이터베이스(database)에 저장하기 전에 다시 암호화(또는 해싱)합니다.

3. IP 화이트리스팅 (IP Whitelisting)

API 보안을 더욱 강화하기 위해, IP 화이트리스팅(whitelisting)을 구현할 수 있습니다.

설령 서명(signature)이나 암호화(encryption) 메커니즘(mechanism)이 뚫리더라도, 공격자는 여전히 승인된 IP 주소에서 API를 요청해야만 합니다.

해결책은 IP 주소를 기반으로 API 요청을 제한하여, 화이트리스트(whitelist)에 등록된 IP로부터의 요청만 허용하는 것입니다.

  • API 요청이 화이트리스트(whitelist)에 등록된 IP에서 온 경우, 정상적으로 처리됩니다.

  • 요청이 화이트리스트(whitelist)에 없는 IP에서 온 경우, 즉시 접근이 거부됩니다.

IP 화이트리스팅(whitelisting)은 API 게이트웨이(gateway) 수준에서 강제될 수 있습니다.

하지만, 회사 내부의 애플리케이션(application) 서버가 침해당하여 공격자가 내부 네트워크에서 API 요청을 보낼 수도 있습니다.

이에 대응하기 위해, 모드시큐리티(ModSecurity)와 같은 웹 방화벽(web firewall)을 배포하여 추가적인 보호 계층을 마련해야 합니다.

4. 속도 제한 (Rate Limiting)

제3자 플랫폼(third-party platform)이 여러분의 API를 호출할 때, 그 요청 빈도는 통제 불가능할 수 있습니다.

만약 제3자가 갑자기 대량의 요청을 동시에 보낸다면, 여러분의 API 서비스는 과부하되어 다운될 수 있습니다.

따라서, 속도 제한(rate limiting)을 반드시 구현해야 합니다.

일반적인 속도 제한 전략 세 가지는 다음과 같습니다.

  • IP당 요청 제한: 예: 단일 IP는 분당 최대 10,000건의 요청만 할 수 있습니다.

  • API 엔드포인트(endpoint)당 요청 제한: 예: 단일 IP는 특정 API 엔드포인트(endpoint)에 대해 분당 최대 2,000건의 요청만 할 수 있습니다.

  • 사용자(AK/SK)당 요청 제한: 예: 단일 AK/SK 사용자는 분당 최대 10,000건의 API 요청만 할 수 있습니다.

실제 애플리케이션(application)에서는 엔진엑스(Nginx), 레디스(Redis), 또는 API 게이트웨이(gateway)를 사용하여 속도 제한(rate limiting)을 구현할 수 있습니다.

5. 파라미터 검증 (Parameter Validation)

API 인터페이스(interface)는 파라미터(parameter) 유효성 검증을 반드시 강제해야 합니다.

예를 들면 다음과 같습니다.

  • 필수 필드(field)가 비어 있는지 확인합니다.

  • 필드(field) 타입을 확인합니다.

  • 필드(field) 길이를 검증합니다.

  • 열거형(enumerated) 값이 올바른지 확인합니다.

이는 유효하지 않은 요청을 처리 과정 초기에 걸러내어 불필요한 처리를 방지하는 데 도움이 됩니다.

예를 들어, 만약 어떤 요청이 허용된 최대 길이를 초과하는 필드(field) 값으로 데이터를 삽입하려고 시도하면, 데이터베이스(database)에서 오류가 발생할 것입니다.

하지만 이러한 검증은 데이터베이스(database) 작업 전에 처리되어 시스템 자원을 절약해야 합니다.

검증 실패 시 발생할 수 있는 문제 예시:

  • 잘못된 금액 값: 양수만 저장해야 하는 필드(field)에 음수 값이 허용된다면 예상치 못한 손실을 야기할 수 있습니다.

  • 유효하지 않은 상태 값: 시스템이 상태 필드(field)를 검증하지 않고 알 수 없는 값이 수신되면, 데이터베이스(database)를 손상시킬 수 있습니다.

일반적인 검증 프레임워크(framework)

자바(Java)에서는 가장 널리 사용되는 검증 프레임워크(framework)는 하이버네이트 밸리데이터(Hibernate Validator)이며, 다음과 같은 어노테이션(annotation)들을 포함합니다.

  • @Null
  • @NotEmpty
  • @Size
  • @Max
  • @Min

이러한 어노테이션(annotation)들은 데이터 유효성 검증을 간단하게 만들어줍니다.

날짜 필드(field)나 열거형(enum) 필드(field)의 경우, 검증을 위해 사용자 정의 어노테이션(annotation)이 필요할 수 있습니다.

6. 통일된 응답 형식 (Unified Response Format)

저는 서로 다른 응답들이 일관성 없는 JSON 형식을 가지는 API들을 마주친 적이 있습니다.

예를 들면 다음과 같습니다.

정상 응답:

{
  "code": 0,
  "message": null,
  "data": [{ "id": 123, "name": "abc" }]
}

 
서명 오류 응답:

{
  "code": 1001,
  "message": "Signature error",
  "data": null
}

 
권한 없음 응답:

{
  "rt": 10,
  "errorMgt": "No permission",
  "result": null
}

 

이것이 왜 문제일까요?

API가 서로 다른 형식으로 응답을 반환하면, API를 연동하는 개발자들에게 불필요한 혼란을 야기합니다.

이 문제는 종종 다음과 같은 경우에 발생합니다.

  • API 게이트웨이(gateway)는 하나의 응답 형식을 가집니다.

  • 비즈니스 시스템은 다른 응답 형식을 가집니다.

  • API 게이트웨이(gateway) 오류가 발생하면 한 가지 형식이 반환됩니다.

  • 비즈니스 시스템 오류가 발생하면 다른 형식이 반환됩니다.

해결책: 응답 구조 표준화

API 게이트웨이(gateway)는 통일된 응답 형식을 강제해야 합니다.

만약 비즈니스 시스템이 오류 메시지를 포함하는 RuntimeException을 발생시킨다면, API 게이트웨이(gateway)는 이 예외(exception)를 잡아 표준화된 형식으로 반환해야 합니다.

7. 통일된 예외 처리 (Unified Exception Handling)

API 인터페이스(interface)는 일관된 예외(exception) 처리를 구현해야 합니다.

데이터베이스(database) 문제(예: 테이블 누락 또는 SQL 문법 오류)로 인해 API 요청이 실패하고, 응답이 가공되지 않은 SQL 오류를 직접 반환하는 상황을 겪어본 적 있으신가요.

일부 잘못 설계된 API는 예외(exception) 스택 트레이스(stack trace), 데이터베이스(database) 세부 정보, 오류 코드, 심지어 코드 라인 번호까지 응답에 노출시킬 수 있습니다.

이는 심각한 보안 위험입니다.

악의적인 행위자는 이 정보를 악용하여 SQL 인젝션(SQL injection) 공격을 수행하거나 데이터베이스(database)를 직접 탈취하여 시스템 침해로 이어질 수 있습니다.

해결책: 민감한 오류 정보 가리기

가공되지 않은 오류 메시지를 노출하는 대신, 모든 API 예외(exception)는 다음과 같은 표준 오류 응답으로 변환되어야 합니다.

{
  "code": 500,
  "message": "Internal Server Error",
  "data": null
}

 

  • code 필드(field)는 500 (서버 오류에 대한 표준 HTTP 오류 코드)입니다.

  • message 필드(field)는 내부 시스템 세부 정보를 노출하지 않는 일반적인 오류 메시지입니다.

디버깅을 위한 내부 로깅

문제를 디버깅(debug)하기 위해, 내부 로그(log)에는 여전히 다음 정보들이 기록되어야 합니다.

  • 전체 예외(exception) 스택 트레이스(stack trace)
  • 데이터베이스(database) 오류 세부 정보
  • 정확한 오류 라인 번호

이는 내부 팀이 외부 사용자에게 민감한 데이터를 노출하지 않으면서 문제를 진단하는 데 필요한 정보를 확보하도록 보장합니다.

게이트웨이 수준 예외 가로채기

예외(exception) 처리는 API 게이트웨이(gateway) 수준에서 강제될 수 있으며, 모든 오류 응답이 일관되고 정제된 형식을 따르도록 보장합니다.

8. 요청 로깅 (Request Logging)

요청 로그(log)는 API 호출, 특히 제3자 플랫폼(third-party platform)과의 연동 문제를 진단할 때 매우 중요합니다.

추적 가능성을 보장하기 위해, 다음 API 요청 세부 정보를 로그(log)로 남겨야 합니다.

  • 요청 URL
  • 요청 파라미터(parameter)
  • 요청 헤더(header)
  • HTTP 메서드(method)
  • 응답 데이터
  • 응답 시간

요청 추적을 위한 traceId 사용

로그(log)에는 traceId가 포함되어야 하며, 이를 통해 특정 요청과 관련된 모든 로그(log)를 함께 연결할 수 있습니다.

이는 문제 해결 시 관련 없는 로그(log)를 걸러내는 데 도움이 됩니다.

제3자가 로그에 접근할 수 있도록 만들기

경우에 따라 제3자 플랫폼(third-party platform)도 요청 로그(log)에 접근해야 할 필요가 있을 수 있습니다.

이를 용이하게 하려면:

  • 몽고DB(MongoDB)나 엘라스틱서치(Elasticsearch)와 같은 데이터베이스(database)에 로그(log)를 저장합니다.

  • 제3자 사용자가 로그(log)를 검색하고 볼 수 있는 UI 대시보드(dashboard)를 개발합니다.

이는 셀프 서비스(self-service) 디버깅(debugging)을 가능하게 하여, 외부 사용자가 사소한 문제로 지원팀에 연락해야 하는 필요성을 줄여줍니다.

9. 멱등성 설계 (Idempotency Design)

제3자 플랫폼(third-party platform)은 매우 짧은 시간 내에 중복된 API 요청을 보낼 수 있으며, 이는 종종 다음과 같은 이유 때문입니다.

  • 그들의 시스템 버그(bug)로 인한 반복 호출

  • API 응답이 지연되거나 실패했을 때의 재시도 메커니즘(mechanism)

만약 API가 멱등성(idempotency, 여러 번 요청해도 결과가 동일한 성질)을 처리하지 않으면, 중복 요청은 중복된 레코드(record)를 생성하여 데이터 불일치를 야기할 수 있습니다.

해결책: 중복 요청이 중복 레코드를 생성하지 않도록 보장

만약 동일한 API 요청이 짧은 시간 내에 여러 번 수신된다면:

  • 첫 번째 요청은 정상적으로 처리되고 데이터를 삽입합니다.

  • 이후의 동일한 요청들은 새로운 데이터를 삽입하지 않지만, 여전히 성공 응답을 반환합니다.

구현 접근 방식

데이터베이스의 유니크 제약조건(Unique constraints) 활용

요청 파라미터(parameter)에 대한 유니크 인덱스(unique index)를 사용하여 중복 항목 생성을 방지합니다.

레디스(Redis)를 사용한 중복 제거

요청 파라미터(parameter)와 함께 requestId를 레디스(Redis)에 저장합니다.


만약 동일한 requestId가 다시 수신되면, 요청을 거부합니다.

10. 배치 API의 레코드 수 제한 (Limiting Record Count in Batch APIs)

배치(batch) 처리 API의 경우, 요청당 레코드(record) 수를 제한하는 것이 중요합니다.

왜 제한해야 할까요?

  • 요청당 너무 많은 레코드(record)를 허용하면 API 타임아웃(timeout) 및 불안정성을 유발할 수 있습니다.

  • 큰 페이로드(payload)는 서버 부하를 증가시키고 전반적인 API 성능을 저하시킵니다.

권장 제한

  • 단일 API 요청은 최대 500개의 레코드(record)만 허용해야 합니다.

  • 만약 500개 이상의 레코드(record)가 전송되면, API는 오류를 반환해야 합니다.

이 제한은 설정 가능해야 하며, API를 공개하기 전에 제3자 사용자와 합의되어야 합니다.

대규모 쿼리를 위한 페이지네이션(Pagination)

만약 API가 대규모 데이터셋(dataset)을 반환해야 한다면, 모든 데이터를 한 번의 요청으로 반환하는 대신 페이지네이션(pagination)을 구현해야 합니다.

11. 부하 테스트 (Load Testing)

API를 출시하기 전에, 해당 API의 QPS(초당 쿼리 수, queries per second) 한계를 이해하기 위해 부하 테스트(load testing)가 필수적입니다.

속도 제한(rate limiting)이 설정되어 있더라도, API가 실제로 예상되는 부하를 처리할 수 있는지 검증해야 합니다.

예시 시나리오

  • API 속도 제한(rate limit)은 초당 50개 요청으로 설정되어 있습니다.

  • 하지만 실제 서버 용량은 초당 30개 요청만 처리할 수 있습니다.

이는 속도 제한(rate limiting)이 있더라도 API가 여전히 다운될 수 있음을 의미합니다.

부하 테스트 도구

  • 제이미터(JMeter)
  • 아파치 벤치(Apache Bench, ab)

스트레스 테스트(stress test)를 실행하여, 안정적인 성능을 유지하기 위해 몇 개의 서버 노드(node)가 필요한지 결정할 수 있습니다.

12. 비동기 처리 (Asynchronous Processing)

대부분의 API는 동기식(synchronous)으로, 요청이 즉시 처리되고 응답이 실시간으로 반환됩니다.

하지만 일부 복잡한 작업, 특히 배치(batch) 처리는 실행하는 데 너무 오래 걸릴 수 있습니다.

해결책: 오래 걸리는 작업을 비동기 처리로 전환

MQ(메시지 큐) 메시지 전송

  • API는 작업을 큐(queue)에 넣은 후 즉시 성공 응답을 반환합니다.

  • 별도의 메시지 컨슈머(message consumer)가 작업을 비동기적으로 처리합니다.

제3자가 처리 결과를 확인하도록 허용

  • 콜백(Callback) 방식: 처리가 완료되면 제3자 API에 알림을 보냅니다 (결제 API에서 흔히 사용됨).

  • 폴링(Polling) 방식: 제3자가 상태 확인 API를 반복적으로 호출하여 진행 상황을 추적합니다.

13. 데이터 마스킹 (Data Masking / Data Redaction)

일부 API 응답에는 다음과 같은 민감한 사용자 데이터가 포함될 수 있습니다.

  • 전화번호
  • 은행 카드 번호

만약 이 정보가 마스킹(masking) 없이 노출되면, 데이터 유출 위험이 증가합니다.

해결책: 데이터 마스킹 적용

예를 들어, 은행 카드 번호를 마스킹(masking)합니다.

  • 원본: 5196123456781234
  • 마스킹됨: 5196****1234

설령 데이터가 유출되더라도 부분적으로 보호되어 보안 위험을 줄여줍니다.

14. 포괄적인 API 문서화 (Comprehensive API Documentation)

잘 문서화된 API는 연동 노력을 줄이고 오해를 최소화합니다.

API 문서에는 다음 내용이 포함되어야 합니다.

  • API URL
  • HTTP 메서드(method) (예: GET, POST)
  • 요청 파라미터(parameter) 및 필드(field) 설명
  • 응답 형식 및 필드(field) 설명
  • 오류 코드 및 메시지
  • 암호화(encryption) 및 서명(signature) 예시
  • 요청 예시
  • 추가 요구사항 (예: IP 화이트리스팅)

네이밍 컨벤션 표준화

일관성을 유지하기 위해:

  • 필드(field) 이름에는 카멜 케이스(camelCase)를 사용합니다.

  • 필드(field) 타입 및 길이를 표준화합니다 (예: id는 Long, status는 int).

  • 통일된 시간 형식을 정의합니다 (예: yyyy-MM-dd HH:mm:ss).

문서에는 AK/SK 키 사용법과 API 도메인(domain) 이름도 명시해야 합니다.

15. 요청 메서드 (Request Methods)

API는 다음과 같은 다양한 요청 메서드(method)를 지원합니다.

  • GET
  • POST
  • PUT
  • DELETE

올바른 메서드 선택

  • GET: 읽기 전용 요청에 적합합니다 (파라미터 전송이 필요 없을 때).

  • POST: 파라미터(parameter)가 필요할 때 권장됩니다 (문제 발생 소지가 적음).

왜 GET보다 POST를 사용할까요?

  • POST는 파라미터 확장이 더 쉽습니다.

    페인(Feign) API 호출 등에서 새로운 파라미터(parameter)를 추가할 때 기존 코드를 수정할 필요가 없습니다.

  • GET은 URL 길이 제한이 있습니다.

    최대 5000자 정도지만, POST는 제한이 없습니다.

16. 요청 헤더 (Request Headers)

인증 토큰(token)이나 traceId와 같은 특정 파라미터(parameter)들은 쿼리 파라미터(query parameter) 대신 요청 헤더(request header)를 통해 전송되어야 합니다.

예를 들면:

  • 모든 API 요청에 traceId를 URL 파라미터(parameter)로 추가하는 대신,

  • 클라이언트(client)는 요청 헤더(header)에 traceId를 보내야 합니다.

  • 서버는 인터셉터(interceptor)를 사용하여 traceId를 추출할 수 있습니다.

17. 배치 처리 (Batch Processing)

API를 설계할 때, 데이터 조회, 추가, 수정, 삭제 등 어떤 작업이든 항상 배치(batch) 처리를 고려해야 합니다.

왜 배치 처리가 중요할까요?

  • 많은 시나리오에서 한 번에 여러 레코드(record)를 조회해야 합니다.

  • 예를 들어, 주문 상세 정보를 검색하는 경우:

    • 만약 API가 한 번에 하나의 주문만 가져올 수 있다면, 각 주문마다 별도의 API 호출이 필요합니다.

    • 만약 API가 배치(batch) 조회를 지원한다면, 단일 요청으로 여러 주문을 검색하여 효율성을 향상시킬 수 있습니다.

  • 데이터를 추가할 때도 마찬가지입니다.

    • 만약 API가 요청당 하나의 레코드(record)만 추가할 수 있고, 배치(batch) 작업으로 1,000개의 레코드(record)를 삽입해야 한다면, 이는 1,000번의 개별 API 호출을 필요로 합니다.

    • 대신, 배치(batch) 삽입 API를 사용하면 1,000개의 레코드(record)를 모두 하나의 요청으로 제출하여 오버헤드(overhead)를 줄일 수 있습니다.

설계 권장 사항:

가능하다면, API는 단일 레코드(record)만 처리하는 대신 배치(batch) 작업을 지원해야 합니다.


이는 API를 다양한 비즈니스 요구에 더 일반적이고 확장 가능하게 만듭니다.

18. 단일 책임 원칙 (Single Responsibility Principle)

어떤 API 디자인은 너무 복잡하여 단일 요청에서 수많은 조건을 지원합니다.


그 결과:

  • 서비스 계층(Service 클래스)에 과도한 if...else 문이 포함됩니다.

  • 응답 모델(model)에 가능한 모든 필드(field)가 포함되어 너무 많은 속성(property)을 갖게 됩니다.

지나치게 복잡한 API의 문제점:

  • 유지보수가 어렵습니다: 1년이 지나면 원래 개발자조차 특정 시나리오에 어떤 필드(field)가 필요한지 기억하기 어려울 수 있습니다.

  • 예상치 못한 변경 위험이 높습니다: 시나리오 A를 위한 로직 수정이 의도치 않게 시나리오 B에 영향을 미칠 수 있습니다.

해결책: 단일 책임 원칙 준수

하나의 API가 모든 것을 처리하도록 하는 대신, API를 더 작고 시나리오별 특정 엔드포인트(endpoint)로 분리합니다.

예시:

주문 생성 API에 대해 웹(Web)과 모바일(Mobile) 두 플랫폼(platform)과 표준(Standard) 및 빠른 주문(Fast) 두 가지 주문 방식이 있다고 가정해 봅시다.

모든 것을 처리하는 하나의 API를 설계하는 대신, 다음과 같이 분리합니다.

  • 웹 플랫폼 API
    • /web/v1/order/create
    • /web/v1/order/fastCreate
  • 모바일 플랫폼 API
    • /mobile/v1/order/create
    • /mobile/v1/order/fastCreate

이렇게 하면 각각 특정 사용 사례에 전념하는 네 개의 개별 API가 됩니다.

이점:

  • 비즈니스 로직이 명확하게 유지됩니다.

  • API 유지보수가 더 쉬워집니다.

  • 변경 시 의도하지 않은 부작용의 위험이 줄어듭니다.

결론

이러한 모범 사례들을 따르면, API 인터페이스(interface)는 더욱 안전하고, 확장 가능하며, 유지보수하기 쉬워집니다.

이러한 원칙들은 다음을 돕습니다.

  • 보안 취약점 예방 (예: 무단 접근, SQL 인젝션)

  • 성능 최적화 (예: 속도 제한, 배치 처리)

  • 개발자 경험 향상 (예: 표준화된 응답, 명확한 API 문서)

내부 시스템용 API를 설계하든, 제3자 연동용 API를 설계하든, 이러한 모범 사례들을 채택하면 더욱 견고하고 미래 지향적인 아키텍처(architecture)를 보장할 수 있습니다.