나는 설계가 좋아서

Broccolism·2023년 12월 10일
8
post-thumbnail

서론

그동안 이런 책을 읽었다.

지금은 이런 책을 읽고 있다.

그러면서 깨달은건 내가 소프트웨어 설계 분야를 좋아하고 실무에서도 비즈니스 요구사항에 맞춰 프로그램 구조를 만드는 작업을 가장 재밌어 한다는 점이다. (다이어그램 그리는 프로그램인 draw.io 만 켜면 가슴이 두근거리는 병이 있다.😇) 이 글에서는 소프트웨어 설계 분야에서 어떤 내용을 다루는지, 대체 어떤 매력이 있는지 간략하게 정리해보려 한다.

본론

소프트웨어 아키텍처?

소프트웨어 설계라는 단어를 들으면 가장 먼저 무엇이 떠오르는지 생각해보자. 개인적으로는 가장 먼저 사각형과 화살표로 이루어진 그림이 떠오른다.

그러니까 이런.. 그림들.

  • 서비스가 어떤 요소로 구성되고
  • 각 요소가 다른 요소와 어떻게 관련되어 있으며
  • 사용자 데이터는 어떤 흐름으로 흘러가는지

… 등을 나타내는 그림 말이다.

‘소프트웨어 아키텍처101’ 에서는 소프트웨어 설계에 대해 말할 때 다음 4가지 항목을 다뤄야 한다고 설명한다: 아키텍처 특성, 아키텍처 결정, 설계 원칙, 시스템의 구조. (1장. 서론) 각 단어의 뜻을 하나씩 파헤치기엔 갈 길이 멀기 때문에 한마디로 요약하자면

아키텍처는 중요한 것들에 관한 것이다. 그게 무엇이든 말이다. - 랄프 존슨 Ralph Johnson

…이 아저씨(?)로 말할 것 같으면 ‘GoF 디자인 패턴’을 만든 GoF 중 한 사람이다. 마틴 파울러 Martin Fowler 는 자신의 책에서 이 말을 인용하면서 소프트웨어 아키텍처에 대한 명확한 정의를 내리려는 시도조차 하지 않았다고 한다.

그렇다면 우리는 소프트웨어 아키텍처에 대한 한 줄짜리 정의를 만드려고 노력하는 것보다 랄프 존슨 아저씨가 말한 ‘중요한 것들’이 대체 무엇인지 알아보는게 빠를 것이다. (적어도 실무를 해본 지 2년쯤 되어가는 주니어 입장에서는 그렇다.)

변화가 중요하다

여기 2가지 프로그램이 있다. 하나는 한번 만든 뒤 다시는 추가 요구사항이나 버그가 생기지 않아서 코드를 수정할 일이 없는 프로그램, 다른 하나는 새로운 기능을 붙이거나 기존 기능을 수정해야 하는 일이 빈번한 프로그램이다. 둘 중 어떤걸 만들 때 더 신경쓰게 될까? 당연히 후자다. 코드 중복을 줄이고, 가독성에 신경쓰고, 예상되는 변화가 있을 때 어떻게 확장하면 좋을지에 대해 고민하면서 미래의 우리가 수정하기 쉬운 코드를 쓰기 위해 고민하는 지점이 전자보다 많을 것이다. 코드를 작성하면서 어떤 부분이 변할 수 있고 어떤 부분이 변하지 않는 부분인지를 잘 구분해야 한다.

코드를 변경하는 이유는 프로그램 요구사항이 변하기 때문이다. 문제는 이 변화를 우리가 예측하기 쉽지 않다는 점에 있다. 요구사항이 단순히 기능만을 일컫는 것은 아니다. 사용자가 점점 늘어나서 더 많은 트래픽을 감당해야 하는 것도 프로그램에 주어지는 요구사항 중 하나다. 그리고 이 트래픽이라는 요구사항 때문에 전체 아키텍처를 다시 짜야하는 경우도 있다. 물리적인 컴퓨팅 파워를 업그레이드하는 방법도 있지만 언제나 비용의 문제가 있기 때문이다. 우리는 항상 어떻게하면 자원을 효율적으로 쓸 수 있을지 고민해야 한다.

트레이드 오프가 중요하다

인생은 선택의 연속.(!) 개발도 선택의 연속이다. 무언가 선택했다는 건 다른걸 포기했다는 의미다.

분산 시스템 설계 필드에는 CAP 정리라는 것이 있다. Consistency 일관성, Availability 가용성, Partition tolerance 파티션 감내성 3가지를 동시에 만족하는 분산 시스템을 설계하는 것은 불가능하다는 정리다.

각각을 좀 더 살펴보기 위해 은행 애플리케이션을 예시로 들어보겠다. 분산 DB에 연결된 서버는 2개이고, 고객 A는 B에게 차례로 1000원, 2000원을을 송금했다.

  • Consistency 일관성: A가 애플리케이션을 열었을 때 A의 잔고에서 정확히 3000원이 빠져나갔음을 조회할 수 있어야 한다. 1000원만 빠져나갔다고 할 바엔 애플리케이션 오류를 표시해야 한다.
  • Availability 가용성: A는 24시간 언제든 애플리케이션에 들어가서 잔고를 확인하거나 송금하는 등 은행 업무를 볼 수 있어야 한다. 예를 들어, 서버 1이 죽더라도 서버 2는 멀쩡해야 한다.
  • Partition tolerance 파티션 감내성: 서버 1이 DB에 연결하면서 타임아웃이 발생하는 등 네트워크 통신이 실패하더라도 애플리케이션은 정상 동작해야 한다.
    • 여기서 말하는 파티션 은 네트워크 파티션이다. 네트워크 장애가 발생하여 특정 서버가 다른 서버들과 통신할 수 없는 상태로 고립되었다면 네트워크 파티션이 생겼다고 말할 수 있다.

CAP 정리에서는 CA 시스템은 현실적으로 존재할 수 없다고 설명한다. CA 시스템은 파티션 감내성을 지원하지 않는다. 즉, 네트워크 장애에 대한 내성을 갖지 않는다. 하지만 통상적인 네트워크 장애는 우리가 피한다고 피해지는 문제가 아니다. 하다못해 상어가 해저 케이블을 뜯어먹을 수도 있는 일이다. 그렇다면 실세계에서 우리가 만들어내는 시스템은 CP 혹은 AP, 혹은 그 중간 어딘가에 있는 시스템이 된다.

분산 시스템 설계에서뿐만 아니라 일반 애플리케이션 설계를 할 때에도 다양한 트레이드 오프 상황에 맞닥뜨리게 된다. 그럴 때마다 대체 어떤 기준으로 선택을 해야 할까?

상황이 중요하다

대답은 ‘아무도 모른다’ 이다. 얼마나 모를 정도냐면, 구글도 모른다. 상황에 따라 다르기 때문이다. 무엇이 좋은 설계인지에 대한 기준을 모든 경우에 적용할 수 없다. 다만 내가 정한 기준은 이정도뿐이다.

  • 설계에서 달성하려는 목표가 명확하고
  • 그 목표를 위해 전체 컴포넌트가 적절하게 구성된 것

여기서 말하는 ‘목표’는 이런 단어로 표현될 수 있다.

  • 성능: 빨라야 한다. 내가 쓴 스킬이 무려 1초 뒤에 상대방에게 도달하고, 그 사이에 상대방이 피해버리는 PvP 게임은 참을 수 없다.
  • 신뢰성: 믿을 수 있어야 한다. 주식 거래 애플리케이션에서 매도 버튼을 눌렀을 때 매수가 된다거나 갑자기 앱이 종료된다거나 하면 난리가 날 것이다.
  • 확장성: 트래픽을 감당할 수 있어야 한다. 쇼핑 애플리케이션이 무료 쿠폰을 뿌리는 11시 정각마다 터져버린다면 답답한 마음에 삭제해버리고 다른 앱으로 갈아타버릴지도 모른다.
  • 유지보수성: 새로운 요구사항이 들어오거나 기존 기능을 수정해야 할 때 쉽게 변경할 수 있어야 한다. 공통 함수를 따로 분리하지 않고 복사-붙여넣기로만 만들어낸 코드를 수정해야 하는 상황은 개발자의 몸과 마음을 지치게 한다.

이외에도 어떤 시스템이 달성해야하는 성질을 나타내는 다양한 용어가 있다. 너무 많아서 이 글에 같이 담기는 커녕 포스팅 하나로 끝낼 수 없을 정도다.

중요한 건 이런 성질 중 무엇이 가장 중요한지가 항상 다르다는 것이다. 주식 거래 앱에서는 초기 진입 시간을 포기하더라도 보안이나 신뢰성을 지키는 것이 중요할 수 있고, 쇼핑 앱에서는 선착순 쿠폰 발급 시 약간의 오류는 있을 수 있더라도 접속 자체가 안되는 상황을 방지하는게 더 중요할 수도 있다. 모든 것은 상황에 따라 다르다.

결론

정말 머리아프네요. 이런걸 왜 합니까?

주어진 정답이 없기 때문이다.

‘소프트웨어 아키텍처 101’ 에서는 이런 구절도 나온다.

최고의 아키텍처를 고집하지 말고 나쁜 것 중에서 제일 나은 아키텍처를 선택하세요. - 4장. 아키텍처 특성 정의

정답이 없는 문제를 다룰 때 좋은 점은 내가 답을 만들어낼 수 있다는 점이다. 그게 정답인지 오답인지는 미래의 우리가 판단할 일이다. 단지 현재 상황에서 최선의 답이라고 생각하는걸 고를 뿐이다.

한때 컴퓨터 프로그래밍이 수학과 참 닮았다는 생각을 한 적이 있다. 문제가 주어지면 항상 ‘정석적으로 해답에 접근하는 방법’이 있을 것으로 생각했다. 대학교 과제를 하거나 알고리즘 문제를 풀 때는 이 말이 꽤 잘 들어맞았다. 깔끔하고 이해하기 쉬운 코드로 주어진 문제를 해결하는 코드. 친구들과 비교해보면 보통 비슷하게 생긴 코드들이 나왔다.

하지만 요구사항이 복잡해지고 프로그램을 둘러싼 상황도 복잡해지면 아주 다양한 경우의 수가 나올 수 있다. 그 경우의 수를 비교해가면서 어떤 것이 가장 효율적이면서도 적합한 방법일지 판단하고 논의하는 과정이 정말 재밌다. 그리고 과거의 내가 한 (물론 당시에는 최선의 답이었을) 선택을 보면서 ‘대체 왜 이렇게 했담 ㅋ’ 하면서 개선해나가는 작업도 재밌다.

뭔가 만들어내고 뜯어고치는 걸 좋아하다보니 이런쪽에 관심이 가는 것 같다. 특히 다양한 상황에서 어떤 기준을 두고 판단하는지 즉, 어떤 사고방식을 갖고 어떤 측면에서 문제를 바라봐야 하는지에 대해 배우는 과정이 즐겁다.

마지막으로

하지만 설계의 함정에는 빠지지 말자.

설계쪽 책을 읽으면서 나도 모르게 갖게 된 생각은 ‘음, 단순히 코드를 짜는 일보다 설계를 하는 작업이 더 고난이도이고 더 높은 수준의 작업이지. 큰 그림을 그리는거잖아.’ 였다. 하지만 ‘오브젝트’를 읽으면서 완전히 생각이 바뀌었다.

어떤 사람들은 설계가 코드를 작성하는 것보다는 높은 차원의 창조적인 행위라고 생각하는 것 같다. 하지만 설계를 구현과 떨어트려서 이야기하는 것은 불가능하다. 설계는 코드 작성의 일부이며 코드를 작성하지 않고서는 검증할 수 없다. - 오브젝트 01. 객체, 설계

그러니까 설계를 한다는 건, 특정 동작을 하는 코드를 어디에다가 둘 지를 고민하는 것과 마찬가지인 것이다.

소프트웨어 개발에서 실무가 이론보다 앞서 있는 대표적인 분야로 ‘소프트웨어 설계’와 ‘소프트웨어 유지보수’를 들 수 있다. - 오브젝트 01. 객체, 설계

이 말에 공감이 간 이유는 대학교 강의 중에 소프트웨어 설계를 다루는 강의는 본 적이 없기 때문이었다. 오히려 실무를 하면서 여러 경험을 해 보는게 우선이라는 생각이 든다. 어느정도 경험이 쌓인 다음에야 그동안의 짬밥(!)을 일반화 해서 이론으로 풀어낼 수 있지 않을까 싶다.

profile
설계를 좋아합니다. 코드도 적고 그림도 그리고 글도 씁니다. 넓고 얕은 경험을 쌓고 있습니다.

2개의 댓글

comment-user-thumbnail
2023년 12월 11일

드디어 오브젝트~

1개의 답글