You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
고객의 수요 변화에 따라 요구사항이 바뀌는 것은 소프트웨어 프로젝트에서는 어쩔 수 없는 과제다. (당연함), 제품 요구사항과 컨텍스트는 시간이 지나면 바뀌므로 여러분의 애플리케이션 도한 그에 따라 바뀔 수밖에 없다. 하지만 요구사항이 변화하면 불안정석을 야기하고 개발 일정에 악영향을 준다.
엔지니어링과 관리자들은 애자일(Agile)개발 방법론 같은 반복적인 프로세스를 이용해 요구사항의 변동을 관리한다. 한편 요구사항의 변경에 대응하려면 우리는 진화하는 아키텍처를 만들어야 한다. 진화하는 아키텍처란, 진화에 방해되는 복잡성을 배제하기 위한 것이다.
복잡도를 이해하자
복잡도란, 시스템을 이해하고 수정하는 것을 어렵게 만드는 시스템의 구조와 관련된 모든 것이라고 한다. 복잡한 시스템은 높은 의존성과 모호성이라는 두 가지 특성을 가진다. 여기서 세 번째 특성인 높은 관성을 추가하고자 한다.
의존성이 높은 소프트웨어는 다른 코드의 API나 동작에 의존하게 된다. 의존성이 분명히 불가피한 것으로서, 때로는 필요한 경우도 있지만 반드시 균형을 맞춰야 한다. 새로운 연결과 추정이 많아질수록 코드를 변경하기는 어려워진다. 의존성이 높은 시스템은 강한 결합과 변경의 영향도 확대로 인해 수정이 어렵다.
강한 결합이란, 어떤 모듈이 다른 모듈에 심하게 의존하는 것을 말한다. 그러면 변경의 영향도가 확대되어 하나를 변경하려면 의존성도 변경해야 한다. 그러면 변경의 영향도가 확대되어 하나를 변경하려면 의존성도 변경해야 한다.
모호성이 높으면 프로그래머는 변경의 부작용, 코드의 동작, 변경이 필요한 지점 등을 예측하기가 어려워진다. 모호한 코드는 학습에도 오랜 시간이 걸리며 개발자의 부주의로 문제가 일어날 확률 또한 높아진다. 너무 많은 작업을 담당하는 신 객체(싱글톤), 부작용을 유발하는 전역 상태, 코드를 이해하기 어렵게 만드는 과도한 간접성, 프로그램의 전혀 무관한 부분의 동작에 영향을 주는 원격 작용등 모두 높은 모호성의 증상이다.
관성은 소프트웨어를 계속 사용하려는 성향을 말한다. 간단한 실험에 사용하고 난 뒤 쉽게 없앨 수 있는 코드의 관성은 낮다고 볼 수 있다. 반면 비즈니스에 요긴한 수십 가지 애플리케이션을 실행하는 서비스는 관성이 높다고 할 수 있다. 복잡도의 비용은 시간이 지나면서 누적되므로 관성이 높고 변경이 잦은 시스템은 반드시 간소화해야 하는 반면, 관성이 낮고 변경이 드문 시스템은 복잡한 상태 그대로 남겨둬도 무방하다.
복잡도를 항상 제거할 수 있는 것은 아니지만 적어도 복잡하게 남겨둘 부분을 선택할 수는 있다. 변경사항의 하위 호환성을 고려하면 코드를 사용하기 쉽게 만들 수는 있지만 구현하기는 훨씬 복잡해진다.
진화하는 아키텍처를 위한 설계 원칙
미래에 발생할 요구사항을 알 수는 없으므로 엔지니어는 대체로 두 가지 전략 중 한 가지를 택한다. 나중에 어떤 필요가 발생할지 예측하려 하거나 나중에 좀 더 쉽게 코드를 변경할 수 있는 추상화를 구현하려 한다. 하지만 결국 두 가지 선택 모두 복잡도를 증가시킬 뿐이다. 최대한 간단하게 구현하자. 건결함을 염두에 두고 시스템을 구현할 수 있도록 하자. (Keep things simple, KISS)
코드를 간결하게 유지하는 가장 쉬운 방법은 모든 것을 한꺼번에 작성하지 않는 것이다.
YAGNI원칙: 당장 필요치 않다면 구현하지 말 것
YAGNI란, "당장 필요치 않다면 구현하지 말 것"을 의미한다. 일반적으로 갭라자가 코드에 대한 의욕이 넘치거나 집착하거나 우려가 있는 경우에 이 원칙을 위반하는 일이 생긴다. 이 원칙을 준수하기 위한 간단한 습관은 최소 기능 제품 기능, 불필요하게 유연한 추상화, 너무 이른 최적화 등을 피하면 된다.
개발자들은 대부분 플러그인 아키텍처, 래퍼 인터페이스, 키-값 쌍으로 표현하는 포괄적인 데이터 구조 같은 유연한 추상화에도 끌리는 경향이 있다. 개발자는 추상화를 통해 새로운 요구사항도 쉽게 처리할 수 있을 것이라고 생각하지만 추상화에는 항상 비용이 따른다. 추상화가 상세한 구현을 유연하지 않은 경계 안으로 숨겨버린 탓에 개발자는 이후에 더 많은 노력을 들여 코드를 수정해야 한다.
최소 충격 원칙: 사용자를 놀래키지 말 것
최소 충격 원칙은 매우 명확하다. 사용자를 놀라게 하지 말라는 것이다. 우리가 구현한 기능은 사용자가 처음 예상한 방식대로 동작해야 한다. 학습 곡선이 매우 높아 배우기 어렵거나 이상하게 동작하는 기능은 오히려 사용자를 불안하게 만든다.
도메인 지식은 캡슐화돼야 한다
소프트웨어는 비즈니스 요구사항에 따라 계속 변화한다. 그러므로 비즈니스 도메인을 중심으로 소프트웨어을 그룹화해서 도메인 지식을 캡슐화해야 한다. 비즈니스 도메인에 부합하는 소프트웨어 컴포넌트를 개발하면 코드를 더 집중적이고 깔끔하게 변경할 수 있다.
도메인의 캡슐화는 본질적으로 높은 응집도와 낮은 결합도를 지향하게 된다. 응집도가 높은 소프트웨어의 결합도가 낮아지면 변경사항의 '영향 반경'이 줄어들므로 좀 더 진화하는 코드를 작성할 수 있다.
서로 관련 있는 메소드, 변수, 클래스 등을 가까운 모듈이나 패키지로 모아둘 때 코드의 응집도가 높다고 한다. 결합도가 낮은 코드는 그 자체로 완결성이 높다. 따라서 로직을 변경하더라도 다른 소프트웨어 컴포넌트를 변경할 필요가 없다.
DDD의 필요성
진화하는 API를 위한 설계 원칙
요구사항이 변경되면 코드가 공유하는 인터페이스인 API를 변경해야 한다. API 변경은 쉽지만 올바르게 변경하기는 쉽지 않다. 작고 합리적인 변경사항도 많이 만들다 보면 혼잡해질 수 있다. 더욱이 API의 소소한 변경으로 인해 호환성이 완전히 무너지기도 한다. API를 변경하면서 호환성을 유지하지 않으면 클라이언트에 문제가 생긴다.
API 크기는 작게 유지하자
API를 작게 만들면 이해하고 개선하기 쉽다. API의 크기가 크면 개발자의 인지 부하가 높아지며 문서화, 지원, 디버그, 유지보수할 코드도 늘어난다. 모든 새로운 메소드나 필드는 API를 켜지게 하며 특정 사용 패턴에 묶이게 된다.
따라서 API에도 YAGNI 철학을 적용하자. API메소드나 필드는 당장 필요할 때만 추가하자. API 데이터 모델을 개발할 때는 지금 현 시점에 필요한 메서드만 추가하자.
잘 정의한 서비스 API를 노출하자
API 변경에 호환성을 유지하면 클라이언트 버전과 서버 버전을 독립적으로 관리할 수 있다. 호환성은 상위 호환성과 하위 호환성의 두 가지로 나뉜다. 변경사항이 상위 호환성을 가지면 클라이언트는 새로운 버전의 API를 이용해 이전 버전의 서비스도 호출할 수 있다. 1.0 버전의 API를 실행 중인 웹 서비스가 1.1 버전의 API를 이용하는 클라이언트의 요청을 수신할 수 있다면 상위 호환성을 갖춘 것이다.
변경사항이 하위 호환성을 갖는 것은 그 반대의 경우로 새로운 라이브러리나 서비스를 사용하기 위해 기존의 클라이언트 코드를 변경할 필요가 없다. API 1.0 버전을 이용해 개발된 코드가 1.1 버전의 API를 사용할 때 컴파일 및 실행이 가능하다면 하위 호환성을 갖춘 것이다.
API의 버전을 관리하자
시간이 지나면서 API가 진화하면 여러 버전의 호환성을 처리할 방법을 결정해야 한다. API가 상위 호환성과 하위 호환성을 완전히 제공한다면 기존의 모든 버전은 물론 미래의 API 버전과도 상호운용이 가능하다.
그러다 보면 코드의 유지보수가 어렵고 이제는 지원하지 않는 필드도 처리해야 하는 로직 같은 불편한 상황이 생긴다. 호환성 정책을 완화하면 더욱 급진적인 변화도 포용할 수 있다.
진화하는 데이터를 위한 설계 원칙
API는 영구적인 데이터에 비하면 수명이 짧은 편이다. 클라이언트와 서버 API가 업그레이드되면 업무는 종료된다. 하지만 데이터는 애를리케이션의 변화에 따라 반드시 진화해야 한다.
데이터베이스를 격리하자
공유 데이터베이스는 진화가 어려우며 자울성을 잃는 결과를 야기할 수 잇따. 여기서 자율성이란 개발자나 팀이 독립적으로 시스템을 변경할 수 있는 능력을 말한다. 공유 데이터 베이스는 다른 사람이 데이터베이스를 사용한다는 점을 고려해야 하므로 안전하게 스키마를 변경할 수 없음은 물론 심지어 데이트를 읽거나 쓰는 것조차 못할 수도 있다.
스키마를 사용하자
컬럼과 타입이 엄격하게 정해져 있고 이를 개선하기 위한 프로세스는 어렵다는 사실로 인해 스키마 없는 데이터 관리라는 기법이 나타나 유행하게 됐다. 대부분의 최신 데이터스토어는 미리 정해둔 구조가 없어도 JSON과 같이 객체를 저장하는 기능을 제공한다.
하지만 현실적으로 스키마 없는 방식은 상당한 데이터 무결성 및 복잡도 문제를 지니고 있음이 드러났다. 강려한 타입을 사용하는 스키마 지향 방식은 모호성을 줄여서 애플리케이션의 복잡도를 낮춘다.
느낀점
책 전반적으로 개발자의 삶에서 필요한 영역을 매우 넗게 다루기 때문에 전에 읽었던 책에 비해 내용이 겉핥기 느낌이 있습니다. 그래서 조금 가볍게 읽는 것이 좋겠다는 생각이 드네요
논의사항
개발자들은 대부분 플러그인 아키텍처, 래퍼 인터페이스, 키-값 쌍으로 표현하는 포괄적인 데이터 구조 같은 유연한 추상화에도 끌리는 경향이 있다. 개발자는 추상화를 통해 새로운 요구사항도 쉽게 처리할 수 있을 것이라고 생각하지만 추상화에는 항상 비용이 따른다. 추상화가 상세한 구현을 유연하지 않은 경계 안으로 숨겨버린 탓에 개발자는 이후에 더 많은 노력을 들여 코드를 수정해야 한다.
개발자가 유연한 추상화에 끌리는 이유는 무엇일까요?
The text was updated successfully, but these errors were encountered:
11장 소프트웨어 수명주기 관점의 진화하는 아키첵처 구현
고객의 수요 변화에 따라 요구사항이 바뀌는 것은 소프트웨어 프로젝트에서는 어쩔 수 없는 과제다. (당연함), 제품 요구사항과 컨텍스트는 시간이 지나면 바뀌므로 여러분의 애플리케이션 도한 그에 따라 바뀔 수밖에 없다. 하지만 요구사항이 변화하면 불안정석을 야기하고 개발 일정에 악영향을 준다.
엔지니어링과 관리자들은 애자일(Agile)개발 방법론 같은 반복적인 프로세스를 이용해 요구사항의 변동을 관리한다. 한편 요구사항의 변경에 대응하려면 우리는 진화하는 아키텍처를 만들어야 한다. 진화하는 아키텍처란, 진화에 방해되는 복잡성을 배제하기 위한 것이다.
복잡도를 이해하자
복잡도란, 시스템을 이해하고 수정하는 것을 어렵게 만드는 시스템의 구조와 관련된 모든 것이라고 한다. 복잡한 시스템은 높은 의존성과 모호성이라는 두 가지 특성을 가진다. 여기서 세 번째 특성인 높은 관성을 추가하고자 한다.
의존성이 높은 소프트웨어는 다른 코드의 API나 동작에 의존하게 된다. 의존성이 분명히 불가피한 것으로서, 때로는 필요한 경우도 있지만 반드시 균형을 맞춰야 한다. 새로운 연결과 추정이 많아질수록 코드를 변경하기는 어려워진다. 의존성이 높은 시스템은 강한 결합과 변경의 영향도 확대로 인해 수정이 어렵다.
강한 결합이란, 어떤 모듈이 다른 모듈에 심하게 의존하는 것을 말한다. 그러면 변경의 영향도가 확대되어 하나를 변경하려면 의존성도 변경해야 한다. 그러면 변경의 영향도가 확대되어 하나를 변경하려면 의존성도 변경해야 한다.
모호성이 높으면 프로그래머는 변경의 부작용, 코드의 동작, 변경이 필요한 지점 등을 예측하기가 어려워진다. 모호한 코드는 학습에도 오랜 시간이 걸리며 개발자의 부주의로 문제가 일어날 확률 또한 높아진다. 너무 많은 작업을 담당하는
신 객체
(싱글톤), 부작용을 유발하는 전역 상태, 코드를 이해하기 어렵게 만드는 과도한 간접성, 프로그램의 전혀 무관한 부분의 동작에 영향을 주는 원격 작용등 모두 높은 모호성의 증상이다.관성은 소프트웨어를 계속 사용하려는 성향을 말한다. 간단한 실험에 사용하고 난 뒤 쉽게 없앨 수 있는 코드의 관성은 낮다고 볼 수 있다. 반면 비즈니스에 요긴한 수십 가지 애플리케이션을 실행하는 서비스는 관성이 높다고 할 수 있다. 복잡도의 비용은 시간이 지나면서 누적되므로 관성이 높고 변경이 잦은 시스템은 반드시 간소화해야 하는 반면, 관성이 낮고 변경이 드문 시스템은 복잡한 상태 그대로 남겨둬도 무방하다.
복잡도를 항상 제거할 수 있는 것은 아니지만 적어도 복잡하게 남겨둘 부분을 선택할 수는 있다. 변경사항의 하위 호환성을 고려하면 코드를 사용하기 쉽게 만들 수는 있지만 구현하기는 훨씬 복잡해진다.
진화하는 아키텍처를 위한 설계 원칙
미래에 발생할 요구사항을 알 수는 없으므로 엔지니어는 대체로 두 가지 전략 중 한 가지를 택한다. 나중에 어떤 필요가 발생할지 예측하려 하거나 나중에 좀 더 쉽게 코드를 변경할 수 있는 추상화를 구현하려 한다. 하지만 결국 두 가지 선택 모두 복잡도를 증가시킬 뿐이다. 최대한 간단하게 구현하자. 건결함을 염두에 두고 시스템을 구현할 수 있도록 하자. (Keep things simple, KISS)
코드를 간결하게 유지하는 가장 쉬운 방법은 모든 것을 한꺼번에 작성하지 않는 것이다.
YAGNI원칙: 당장 필요치 않다면 구현하지 말 것
YAGNI란, "당장 필요치 않다면 구현하지 말 것"을 의미한다. 일반적으로 갭라자가 코드에 대한 의욕이 넘치거나 집착하거나 우려가 있는 경우에 이 원칙을 위반하는 일이 생긴다. 이 원칙을 준수하기 위한 간단한 습관은 최소 기능 제품 기능, 불필요하게 유연한 추상화, 너무 이른 최적화 등을 피하면 된다.
개발자들은 대부분 플러그인 아키텍처, 래퍼 인터페이스, 키-값 쌍으로 표현하는 포괄적인 데이터 구조 같은 유연한 추상화에도 끌리는 경향이 있다. 개발자는 추상화를 통해 새로운 요구사항도 쉽게 처리할 수 있을 것이라고 생각하지만 추상화에는 항상 비용이 따른다. 추상화가 상세한 구현을 유연하지 않은 경계 안으로 숨겨버린 탓에 개발자는 이후에 더 많은 노력을 들여 코드를 수정해야 한다.
최소 충격 원칙: 사용자를 놀래키지 말 것
최소 충격 원칙은 매우 명확하다. 사용자를 놀라게 하지 말라는 것이다. 우리가 구현한 기능은 사용자가 처음 예상한 방식대로 동작해야 한다. 학습 곡선이 매우 높아 배우기 어렵거나 이상하게 동작하는 기능은 오히려 사용자를 불안하게 만든다.
도메인 지식은 캡슐화돼야 한다
소프트웨어는 비즈니스 요구사항에 따라 계속 변화한다. 그러므로 비즈니스 도메인을 중심으로 소프트웨어을 그룹화해서 도메인 지식을 캡슐화해야 한다. 비즈니스 도메인에 부합하는 소프트웨어 컴포넌트를 개발하면 코드를 더 집중적이고 깔끔하게 변경할 수 있다.
도메인의 캡슐화는 본질적으로 높은 응집도와 낮은 결합도를 지향하게 된다. 응집도가 높은 소프트웨어의 결합도가 낮아지면 변경사항의 '영향 반경'이 줄어들므로 좀 더 진화하는 코드를 작성할 수 있다.
서로 관련 있는 메소드, 변수, 클래스 등을 가까운 모듈이나 패키지로 모아둘 때 코드의 응집도가 높다고 한다. 결합도가 낮은 코드는 그 자체로 완결성이 높다. 따라서 로직을 변경하더라도 다른 소프트웨어 컴포넌트를 변경할 필요가 없다.
DDD의 필요성
진화하는 API를 위한 설계 원칙
요구사항이 변경되면 코드가 공유하는 인터페이스인 API를 변경해야 한다. API 변경은 쉽지만 올바르게 변경하기는 쉽지 않다. 작고 합리적인 변경사항도 많이 만들다 보면 혼잡해질 수 있다. 더욱이 API의 소소한 변경으로 인해 호환성이 완전히 무너지기도 한다. API를 변경하면서 호환성을 유지하지 않으면 클라이언트에 문제가 생긴다.
API 크기는 작게 유지하자
API를 작게 만들면 이해하고 개선하기 쉽다. API의 크기가 크면 개발자의 인지 부하가 높아지며 문서화, 지원, 디버그, 유지보수할 코드도 늘어난다. 모든 새로운 메소드나 필드는 API를 켜지게 하며 특정 사용 패턴에 묶이게 된다.
따라서 API에도 YAGNI 철학을 적용하자. API메소드나 필드는 당장 필요할 때만 추가하자. API 데이터 모델을 개발할 때는 지금 현 시점에 필요한 메서드만 추가하자.
잘 정의한 서비스 API를 노출하자
API 변경에 호환성을 유지하면 클라이언트 버전과 서버 버전을 독립적으로 관리할 수 있다. 호환성은 상위 호환성과 하위 호환성의 두 가지로 나뉜다. 변경사항이 상위 호환성을 가지면 클라이언트는 새로운 버전의 API를 이용해 이전 버전의 서비스도 호출할 수 있다. 1.0 버전의 API를 실행 중인 웹 서비스가 1.1 버전의 API를 이용하는 클라이언트의 요청을 수신할 수 있다면 상위 호환성을 갖춘 것이다.
변경사항이 하위 호환성을 갖는 것은 그 반대의 경우로 새로운 라이브러리나 서비스를 사용하기 위해 기존의 클라이언트 코드를 변경할 필요가 없다. API 1.0 버전을 이용해 개발된 코드가 1.1 버전의 API를 사용할 때 컴파일 및 실행이 가능하다면 하위 호환성을 갖춘 것이다.
API의 버전을 관리하자
시간이 지나면서 API가 진화하면 여러 버전의 호환성을 처리할 방법을 결정해야 한다. API가 상위 호환성과 하위 호환성을 완전히 제공한다면 기존의 모든 버전은 물론 미래의 API 버전과도 상호운용이 가능하다.
그러다 보면 코드의 유지보수가 어렵고 이제는 지원하지 않는 필드도 처리해야 하는 로직 같은 불편한 상황이 생긴다. 호환성 정책을 완화하면 더욱 급진적인 변화도 포용할 수 있다.
진화하는 데이터를 위한 설계 원칙
API는 영구적인 데이터에 비하면 수명이 짧은 편이다. 클라이언트와 서버 API가 업그레이드되면 업무는 종료된다. 하지만 데이터는 애를리케이션의 변화에 따라 반드시 진화해야 한다.
데이터베이스를 격리하자
공유 데이터베이스는 진화가 어려우며 자울성을 잃는 결과를 야기할 수 잇따. 여기서 자율성이란 개발자나 팀이 독립적으로 시스템을 변경할 수 있는 능력을 말한다. 공유 데이터 베이스는 다른 사람이 데이터베이스를 사용한다는 점을 고려해야 하므로 안전하게 스키마를 변경할 수 없음은 물론 심지어 데이트를 읽거나 쓰는 것조차 못할 수도 있다.
스키마를 사용하자
컬럼과 타입이 엄격하게 정해져 있고 이를 개선하기 위한 프로세스는 어렵다는 사실로 인해 스키마 없는 데이터 관리라는 기법이 나타나 유행하게 됐다. 대부분의 최신 데이터스토어는 미리 정해둔 구조가 없어도 JSON과 같이 객체를 저장하는 기능을 제공한다.
하지만 현실적으로 스키마 없는 방식은 상당한 데이터 무결성 및 복잡도 문제를 지니고 있음이 드러났다. 강려한 타입을 사용하는 스키마 지향 방식은 모호성을 줄여서 애플리케이션의 복잡도를 낮춘다.
느낀점
책 전반적으로 개발자의 삶에서 필요한 영역을 매우 넗게 다루기 때문에 전에 읽었던 책에 비해 내용이 겉핥기 느낌이 있습니다. 그래서 조금 가볍게 읽는 것이 좋겠다는 생각이 드네요
논의사항
The text was updated successfully, but these errors were encountered: