왜 시스템 디자인을 배워야하는가?

왜 내 프로젝트는 면접에서 통하지 않을까?
개발자는 문제를 해결하는 사람이다라고 하는데 프로젝트에서 차별성을 보여주기가 쉽지 않다.
보통 시작은 간단한 프로젝트로 많이 한다.
API 서버를 만들어보고 DB를 붙여보고 프론트랑 통신을 해보고 이런 프로젝트들을 많이 한다.
이것만으로는 면접에서 깊이 있는 기술적 고민을 보여주기가 쉽지 않다.

위 그림에 나오는 문제들은 벡앤드 개발을 시작하면 한 번쯤 겪는 것들이고 구글링이나 블로그 글 등을 통해 해결가능하다.
그래서 이런 단순한 기술 구현 경험만으로는 나만의 차별성을 보여주기 어렵다.
단순 구현에서 벗어나 문제 상황에서 어떤 기술을 선택하고, 왜 그렇게 선택했는지를 설명할 수 있는 프로젝트를 의도적으로 해야된다.
여기서 시스템 디자인이라는 키워드가 등장한다.
시스템 디자인은 시스템 아키텍처 설계라고도 한다.
하나의 소프트웨어 시스템이 어떻게 구성되고 작동할지를 설계하는 과정이다.
- 어떤 기능을 어떻게 구현할 지 설계
- 어떤 기술을 사용할 지 결정
- 각 구성 요소를 어떻게 연결하지 고민
어떤 컴포넌트를 어디에 배치할지 데이터는 어떻게 저장하고 처리할지 사용자가 많아졌을 때는 어떻게 확장을 할 수 있는지 등..


시스템 디자인은 의사결정의 연속이다.
프로젝트를 위한 아키텍처를 그릴 때도 단순하게 사용한 기술을 나열하는 게 아니라,
예를 들어 왜 이 자리에는 Redis를 사용했는지 유도하고 설명할 수 있어야한다.
항상 필요한 것은 내 서비스가 이루려고 하는 목표가 뭔지를 명확하게 정의를 하고,
서비스 중심적인 사고를 가지는 것이 중요하다.
내가 무엇을 만들었는지를 잊지 않고, 그 서비스의 목표에 맞게 기술적인 의사결정을 해야한다.
그래서 서비스마다 어떤 목표를 달성해야 되는지가 다르다.
예를 들어,
결제 서비스라면 돈과 연관되어 있으니 신뢰성과 보안이 중요하다.
메신저 서비스라면 많은 사용자가 들어와도 빠르게 동작을 해야 되니깐 실시간성과 확장성이 중요하다.
온라인 쇼핑 서비스라면 하루 24시간 잘 동작하는 것이 중요하니 가용성과 사용자가 들어왔을 때 잘 버틸 수 있는 확장성이 중요하다.
서비스를 만들 때 가장 중요한 4가지 핵심 목표
- 신뢰성 : 시스템이 사용자의 예상대로 항상 정확하고 일관되게 동작하는지에 대한 목표
- 성능 : 시스템이 빠르고 안정적으로 반응을 하는지에 대한 목표
- 가용성 : 시스템이 언제든지 접근 가능한 상태인지에 대한 목표
- 확장성 : 트래픽이나 데이터가 늘어나도 시스템의 성능이 잘 유지가 되는지에 대한 지표
(신뢰성을 시작으로 성능, 가용성, 확장성에 대해 차차 포스팅할 예정이다.)
신뢰성
단순하게 사용자가 얼마나 이 서비스를 믿고 사용할 수 있는가
즉, 시스템이 사용자의 예상대로 매번 정확하고 일관되게 동작하는 특성
신뢰성을 높이는 방법
- 사용자가 예상한대로 기능을 수행한다.
- 무언가 잘못되어도 정확하고 일관되게 동작한다.

첫번째로는 기능이 잘 동작하려면 개발하려는 것이 무엇인지 알아야한다.
그래서 사전에 명확한 요구사항 정의를 해주는 것이 중요하다.
API 형태로 데이터를 주고 받는 경우가 많은데, 이런 경우에는 사용하는 응답하고 에러코드의 일관성이 있게 사용하는 것이 중요하다.
그리고 또 적절한 테스트를 짜줘야 된다. 테스트에는 단위 테스트와 통합 테스트가 있다.
- 단위 테스트 : 클래스 단위로 코드를 짜는데 그 클래스의 작은 기능 하나하나를 테스트 하는 것
- 통합 테스트 : 더 큰 범위에서 다른 DB나 외부 의존성까지 함께 검사를 하는 것
테스트는 실 서비스를 한다고 하면 예상한 기능을 잘 수행하는지 확인하는데 정말 중요한 역할을 한다.
코드가 더 추가되고 수정되고 할 때 이전에 만든 기능들이 잘 동작하는지 보장을 하는데도 중요한 역할을 한다.
RDB를 쓸 때 주로 사용하는 트랜잭션을 활용해서 데이터의 정합성을 유지할 수 있다.
예를 들어 5만원을 송금할 때, 내 계좌에서는 5만원이 빠지고 상대 계좌에서는 5만원이 추가되는 이 한 번에 일어나야 되는 데이터의 변경이 하나의 트랜잭션으로 묶이면 데이터의 정합성이 지켜질 수 있다.
그리고 우리가 사용하는 데이터 저장소가 여러 개인 경우, 데이터 상태의 일관성을 관리해야한다.
예를 들어 DB를 쓰고 있고, 캐시를 같이 쓰고 있다고 했을 때, 이 캐시에 있는 데이터와 DB에 있는 데이터가 일치하도록 관리해야한다.
여러 데이터 베이스 복제본이 있을 때, 복제본 사이에 데이터가 일치하도록 신경 써야 한다.
또 데이터를 안전하게 보관하기 위해서 DB 복제나 데이터 백업을 해야 신뢰성을 높일 수 있다.

두 번째로는 이제 어떻게 하면 무엇이 잘못됐을 때도 잘 동작하도록 보장할지에 대해서 생각을 해볼 수 있다.
내결함성(falut tolerance) 이라는 용어로 불린다.
사용자가 아예 요청을 잘못 보냈거나 아니면 컴포넌트 중에 하나가 장애가 났다거나 이럴 때도 일관된 동작을 해야지 신뢰성 있다고 볼 수 있다.


장애가 항상 존재하는 상황에서 어떻게 신뢰성을 보장해 줄 수 있을까?
일단 입력이 잘못된 상태나 예측할 수 있는 비즈니스 로직적인 예외 케이스에 대해서는 최대한 서버 코드단에서 처리를 해주는 것이 좋다.
입력값 검증이나 예외처리를 해 줄 수 있다.
또 문제 상황에는 같은 요청이 여러번 갈 수 있으니까 요청이 여러번 처리돼도 결과가 변하지 않도록 멱등성 있는 API를 만드는 것이 하나의 방법이다.
문제 상황이 발생했을 때 전체 트랜잭션이 롤백되도록 해야 일관된 동작을 보장할 수 있다.
만약, 그냥 단일 DB만 쓰는 경우 말고 여러 서비스에서 각각의 DB를 쓰고 있고, 서비스 간의 트랜잭션을 보장해야 되는 경우가 있다.
이를 분산 트랜잭션 처리라고 하는데, 이런 경우에는 이 모든 작업이 한 번에 성공하거나 한 번에 실패하도록 만들어야 되니까 단일 DB에서 트랜잭션을 다룰 떄 조금 더 복잡한 설계를 해야 신뢰성을 높일 수 있다.
특정 요청이 실패했을 때, 재시도 처리를 하면 신뢰성을 높일 수 있다. 이 재시도를 몇 번 할지, 얼마 주기로 재시도할지 이런 전략들을 정해야 한다.
다른 서버로 요청을 보내야 될 때, 이 보냈을 때 실패 비율이 얼마 이상 되면 해당 서버는 문제가 있는 걸로 보고 더 이상 요청을 보내지 않아서장래를 우리 서버까지 전파시키지 않는 Circuit Breaker라는 게 있는데 이런 설정을 해주어 신뢰성을 높일 수 있다.
마지막으로 장애 상황을 고려한 설계를 할 수 있다. 이것은 시스템이 일부 장애를 겪더라도 서비스 전체가 중단되는 게 아니라 일부 기능만 제한적으로 제공을 하거나 아니면 필요하면 자동으로 복구되도록 하는 구조로 만들 수 있다.
신뢰성 있는 시스템을 만들었다는 것을 어필해야될 때 수치적으로 증명하는 것이 가장 설득력 있다.
그러면 수치상으로 지표를 측정하기 위해서 먼저 어떤 기능에서 신뢰성이 보장되는 것이 가장 중요한 지
주요 기능을 추려내는 것이 우선 되어야 된다. 그리고 그 기능에 대해서 측정할 수 있는 지표를 하나씩 측정해야된다.
신뢰성 지표




신뢰성을 측정하는데 사용할 수 있는 지표
- MTBF : 실패하는 시간 사이의 간격
- 얼마나 오랫동안 문제 없이 동작하는 가를 측정할 수 있는데 서버 실패 로그 사이에 시간을 확인할 수 있다.
- MTTR : 문제가 생겼을 때 얼마나 빨리 복구를 했는가 하는 수치
- 에러율 : 에러율을 측정해서 해당 기능의 전체 요청 중 에러의 비율을 측정할 수 있다.
- 특히 성공 케이스인 200번대나 사용자 오류인 400번대를 제외해서 500번대 응답이 얼마나 되는 가를 측정할 수 있다.
- 데이터 무결성 검사
- 하나의 수치로 나타내기 어렵지만 저장하는 데이터의 정합성에는 문제가 없는지 확인해볼 수 있다.
실제로 프로젝트를 했을 때, 어떻게 신뢰성에 대한 설득을 할 수 있는 지에 대한 예시

예시를 통해 신뢰성 있는 시스템을 구축했다라고 증명하기 위해 생각해볼만한 것
- 얼마나 오랫동안 오류 없이 운영이 됐는지
- 혹시 오류가 났다고 하면 오류가 왜 났고, 이거를 어떻게 개선했는지
- 장애가 발생하면 오류를 얼마만에 자동 복구했는지
- 개발자가 장애를 인지하기 위해서 알림 시스템을 구축했는지
- 주요 API에 대한 에러율을 측정할 수 있는지
- 매일 잔여 포인트가 차감된 포인트랑 일치하는지 확인하는 일 배치(batch)가 만들어져 있는지
- 동일한 요청이 여러번 들어와도 적립 차감이 한 번만 되도록 하는 멱등성 있는 설계를 했는지
위와 같은 예시사항들을 고려해서 설계를 했다라고 설명하면 좋은 어필이 될 것이다.
다음 포스팅은 성능, 가용성, 확장성에 대해 더 공부하고 정리할 예정이다.
Reference
이 글은 인프런 '시스템 디자인 첫 걸음: 면접에서 돋보이는 백엔드 아키텍처 설계하기' 강의를 보고 정리하였습니다.
시스템 디자인 첫걸음: 면접에서 돋보이는 백엔드 아키텍처 설계하기| 성장랜턴 - 인프런 강의
현재 평점 4.9점 수강생 402명인 강의를 만나보세요. API 설계, CRUD 구현, JWT 인증 같은 기초를 넘어 백엔드 아키텍처 설계까지! 면접에서 설계 경험을 자신 있게 말할 수 있는 ‘나만의 백엔드 아키
www.inflearn.com
'프로젝트 > 블로그 3기' 카테고리의 다른 글
| HTTP vs HTTPS 환경에서의 쿠키 보안 설정 (0) | 2026.02.19 |
|---|---|
| [Keepit] Spring Security OAuth2 소셜 로그인에서 JSESSIONID가 생성되는 문제 해결하기 (1) | 2026.02.08 |
| [네트워크] 쿠키, 세션, JWT, 인증 그리고 웹 보안 등 (0) | 2026.01.25 |
| 시스템 디자인의 핵심 목표 4가지 (2) - 성능, 가용성, 확장성 (0) | 2026.01.05 |
| 블로그 적금 3기 시작 (1) | 2025.12.19 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!