[안드로이드스튜디오_문화][복잡성제거]

기말 지하기포·2024년 1월 13일
0

클린 아키텍처

1.만드려고 하는 앱이 해결하고자 하는 문제에 잘 어울리는 설계가 좋은 설계구조이다.

-예를 들어 코드구조가 시스템이 어떻게 동작할 수 있는지를 잘 이해 할 수 있는지 보여줘야 한다.

2.작업이 편리해야 한다.

-2.1 : 이해하기 쉽고
-2.2 : 왜 코드를 이렇게 작성했는지 알아야하고
-2.3 : 코드 유지 및 보수에 용이해야 하며
-2.4 : 테스트 코드 작성이 쉬워야한다.

3.변화에 민감해야 한다.

-왜냐하면 비즈니스 니즈라는 것은 항상 변화하기 때문에 그에 따라서 프로그램도 계속해서 진화해 나가야 되고 설계도 동시에 진화해 나가야 한다.

4.성능 개선 작업을 유연하게 해줘야 한다.

클린 아키텍처의 방해물 : 복잡성

1.복잡성

-복잡성이란 시스템을 이해하기 어렵고 수정하기 어렵게 만드는 소프트웨어 구조에 관한 모든 것이 복잡성이라고 한다.

-그러나 복잡성이 코드의 줄 수 를 의미하는 것은 아니다. 코드의 줄수가 어마어마하게 길다고 하여도 복잡성이 낮을 수 있고 , 코드의 줄수가 짧다고 하여도 복잡성이 높을 수 있다.

2.복잡성 판단 기준 세가지

-변경 증폭(Change Amplification) : 작은 변경이 발생했는데 여러 군데를 편집해야 된다고 하면, 복잡성이 높은 것이다.

-인지적 부하(Cognitive Load) : 작은 변경을 하기 위해서 많은 부분을 알아야 한다면, 복잡성이 높은 것이다.

-알 수 없는 무지(Unknown unKnowons) : 작은 변경이 일어났을 때 예측하지 못한 결과가 나왔는데 왜 그렇게 됐는지도 알 수 없는 경우, 복잡성이 높은 것이다.

3.복잡성을 조장하는 세가지 요인

-의존성(Dependencies) : 코드가 독립적으로 이해되고 수정 될 수 없을 때 복잡성이 생긴다. 하지만 코드라고 하는 것은 유기적이기 때문에 서로가 서로의 영향을 받기 때문에 의존성을 완전히 제거하는 불가능하므로 최소한의 의존성만 가지도록 코드를 작성하여야 한다. // 어떠한 특정 코드 , 특정 메서드 , 특정 클래스 등이 독립적으로 이해되고 수정 될 수 없다는 것은 이것이 어딘가에 의존되어 있다는 것이고 이러한 의존성이 복잡성을 높이는 요인이 된다.

-불명확함(Obscurity) : 중요한 정보가 불명확 할 때 복잡성이 생긴다. // 특정 메서드가 있을 때 이 메서드에 무엇이 입력돼서 어떤 결과가 나오는지가 명확하지 않은 경우가 의외로 많은 경우가 있다. 이와 정반대로 결과와 마지막이 있는데 중간에 어떤 일이 일어난 것인지 이해하지 못한다면 결과도 이해할 수 없는 그런 경우가 생길 수 도 있다. 이것도 다른 의미의 불명확함이라고 볼 수 있다.

-전술적 프로그래밍(Tactical Programming) : 지금 있는 문제만 일단 해결하자고 할 때 복잡성이 생긴다. 이런 경우 같은 경우는 지금은 여러 가지 고려를 하지 않고 지금 문제만 해결하기 때문에 지금은 10% ~ 20%의 정도의 비용을 적게 쓸 수 있을지는 모르지만 이 비용이 이자가 되서 영원히 남을 수 있다. 이것을 기술부채라고 부른다. <-> 전략적 프로그래밍 : 임의의 무엇가로 인해서 어떤 임팩트가 있겠고 어떤 영향이 다른 곳에 갈 수 있다고 하는 것을 판단하고 제대로 완성하기를 의미한다. 이런 경우에는 시간을 더 투자해야 한다. 하지만 기술부채를 남기지 않는다.

4.복잡성을 낮추는 방법 다섯가지 방법

-불필요한 정보를 감춘다(추상화) : 추상화라는것은 확실한 것을 애매모호하게 바꾼다고 하는 것을 의미하는 것이 아니라 중요한 정보가 안에 있다고 했을 때 그 정보의 시놉시스 같은 것들만 알면 되는 것을 추상화라고 할 수 있다.

  • 4-1) 모듈을 깊이 만들 필요가 있다.
  • 4-2) 인터페이스는 범용으로 넓게 만들어야 된다.
  • 4-3) 정보의 은닉(information hiding) : 안에서 어떤일이 일어난지는 은닉되어야 되고 그래서 알 필요도 없고 알 수 도 없게 만들어야 된다.

-깔끔한 추상화

  • 4-4) 특정 복잡성이 있다고 하면 이것들을 최대한 하위레벨로 끌어내릴 필요가 있다.
  • 4-5) 추상화 사이의 경계 찾기

4-1 모듈을 깊게 만들어야 한다. (모듈 : 기능을 가진 코드 묶음)

-모듈에서 얘기하는 "인터페이스"=="노출되는 것"을 의미한다. 외부에 노출되는 것은 클래스 그 자체가 있을 것이고 , 해당 클래스의 public method가 있을 것이다. 이렇게 두가지가 외부에 노출된다. "노출된다"=="사용된다"

-추상화 : 중요하지 않은 세부사항을 감춰주는 간소화된 뷰

-깊은 모듈 Vs 얕은 모듈 : 깊은 모듈의 깊이가 의미하는 것은 작업의 깊이를 의미한다. 작업에서는 많은 일들이 일어나겠지만 위에서 보는 짧은 면(해당 모듈을 호출하기 위한 인터페이스)이 있다. 인터페이스는 한정되어 있고 나머지 모듈에서 일어난 대부분의 일들은 수면 밑에 있어서 실제로 사용자 입장에서는 모듈의 위에있는 인터페이스만 알면 되는 것을 깊은 모듈이라고 한다. 따라서 이 깊은 모듈을 가장 좋은 모듈이라고 볼 수 있다. 예를 들어 사용자가 몇개의 인터페이스만 알고 있으면 모듈 전체의 기능을 사용 할 수 있는 것을 의미하는데 , 이러한 모듈은 내부적으로는 복잡할 수 있으나 이 복잡성은 사용자가 몰라도 된다.// 얕은 모듈이란 어떤 클래스가 있다고 했을 때 public method가 너무 많거나 하나의 메소드가 있을 때 하나의 메소드로 완결이 안 돼서 특정 작업을 위해서 여러 개의 메서드를 계속해서 불러야 된다든가 하는 경우는 얕은 모듈이라고 할 수 있다. 여러개의 메서드를 계속 불러야 되는 경우라고 하면 깊이가 옆으로 더 넓어지면서 깊이가 낮아지는데 , 여기서 깊이가 낮아진다는것은 위에서 사용하는 사람들의 입장에서 계속해서 그 모듈에 있는 부분들을 이해하고 계속해서 인터페이스를 통해서 그 지식을 기반으로 호출해준다는 그런 문제를 갖게된다. 예를 들면 사용자가 모듈의 기능을 완전하게 활요하기 위해 많은 다른 메서드를 알고 있어야 하는 경우이다.

4-2 인터페이스는 범용으로 만들어야 한다.

-인터페이스("노출 되는 것")은 범용 인터페이스(general purpose) 그리고 specific purpose가 있다.

-범용 인터페이스("노출 되는 것")은 여기저기서 사용 될 수 있는 재사용 가능한 것이라고 생각하면 된다. 범용이라고 하는 것은 지금 비용이 많이 든다. 예를 들면 모듈을 범용으로 만든다고 하면 인터페이스 자체는 범용으로 여기저기서 사용 될 수 있는 그런 것들이고 , 구현 자체는 지금 현재 필요한 요구사항에 대해서만 한다. 그리고 이것을 다른 용도로 사용하기 위해서 public API를 따로 내서 그걸 이용해서 쓸 수 있도록 한 번 더 설계를 한 것을 말한다.

-특정 인터페이스("노출 되는 것")은 특별한 문제 해결이나 특정한 기능 제공을 목적으로 하여 노출 될 수 있는 경우가 제한 되는것 , 즉 , 재사용성이 극히 낮은 것이라고 생각하면 된다. 특정 인터페이스는 비용이 나중에 든다.

-내가 만든 인터페이스가 범용인가 를 판단할 수 있는 기준들

  • 현재의 요구사항을 모두 만족하는 것 중에 제일 심플한(낮은 복잡성)가?
  • public method가 많은 상황에 적용 될 수 있는가?
  • public API가 현재의 문제를 해결하는 데에만 적요되는 것이 아니라 실제로 다른 상황에서 사용하기 편한가?

4-3 정보의 은닉(information hiding)

-정보의 은닉을 이루기 위해서는 일반적인 케이스들을 최대한 심플(낮은 복잡성)하게 만들어야 된다. 즉, 불필요한 정보를 감춰야 될 필요가 있어서 , 여기서 사용되지 않는 것들은 최대한 감춰야 된다. 예를들면 어떤 변수들이 클래스 안에 존재하고 있는데 모두 다 public으로 되어 있거나 , set 없이 다 노출되어 있다면 , 이런 것들은 정보의 유출로 판단된다. 즉, 감출 수 있는 것들은 클래스안에 가둬야 한다는 것이다. 왜냐하면 대부분의 경우 특정 클래스 내부에서 사용되는 데이터라고 하는 것들은 외부에서 볼 필요가 없어야 하는 것들이 대부분 정상이기 때문이다. 만약 해당 클래스에서만 사용되어야 하는 지식들이 다른 곳에 누출된다면 복잡성이 높아지고 필요한 지식이 한 군데에 집중되지 않아서 특정 로직의 수정 같은 것들이 여러 클래스에 영향을 미칠 수 있는 문제점이 있기 때문에 정보의 은닉을 이루어야 한다. 또한, 정보의 은닉이 이루어지지 않아서 over explosure가 발생한다면 사용자가 일반적인 작업들을 위해서 별의별 학습을 진행하게 될 수 도 있다.

4-4 특정 복잡성이 있다고 하면 이것들을 최대한 하위레벨로 끌어내릴 필요가 있다.

-심플(낮은 복잡성)한 인터페이스("노출 되는 것")는 심플(낮은 복잡성)한 구현보다 낫다. 따라서 가급적이면 구현 자체를 아래로 감추어서 코드가 실제로 어떻게 구현되는지는 사용자가 몰라도 되게 한 후 사용자가 인터페이스를 사용할 때 간단하게 사용 할 수 있도록 만들어야 한다.

-그렇다고 해서 복잡성을 무작정 아래로 끌어내리고 인터페이스를 위로 끌어올린다면 , 다른 의미의 정보 유출로 이루어질 수 도 있다. 따라서 복잡성을 아래로 끌어내리는 경우에는 3가지의 원칙이 있다.

  • 기존에 잇는 기능화 밀접하게 연관되어 있다면
  • 앱의 여러 부분들을 특정 정보들을 감춤으로 인해서 다른 부분들이 더 단수한게 만들어 줄 수 있다면
  • 클래스의 인터페이스를 단순하게 만들어 줄 수 있다면
  • 예를들면 만약에 / 읽어 / 3보다 커? / 출력해 /이것을 3가지로 나누면 사용자가 사용할 때 3가지의 기능을 따다닥 연속으로 구현해야 되는데 읽고 / 3보다 커? / 이것들을 private로 바꾸어서 / 출력해 /에 넣어주는 형태가 좋다. cf. 재사용되지 않으면 굳이 나누지 않아도 된다고 오해하지 말기

4-5 추상화 사이의 경계 찾기

-클래스를 나누는 경계라고 보면 된다.

-클래스를 합치는 경우

  • 같은 정보가 공유되는 경우
  • 합께 있는 것이 인터페이스를 단순하게 만들어 주는 경우
  • 코드 중복을 없애 주는 경우

-클래스를 분리하는 경우

  • 특정 목적의 API가 범용 클래스 내부에 있을 때
  • 다른 종류의 범용 매커니즘이 함께 있을 때
profile
포기하지 말기

0개의 댓글