'좋은 코드/나쁜 코드 학습 디자인 입문'읽고 신경 쓴 일 노트

개시하다


화제가 된'좋은 코드/나쁜 코드로 학습한 디자인 입문-지속적인 성장을 유지하기 쉬운 코드의 쓰기'출판사 페이지를 읽었다.
총체적으로 말하자면, 대부분의 경우 '응, 그래' 에 동의할 수 있다.
물론 처음 보는 생각과 생각, 기교도 있다.
한편, 신경 쓰이는 일과 조금 걸리는 일도 있으니 미리 적어두자.
필기일 뿐이라고 결론이 나지 않는다.

p.55: HitPoint.isZero

HitPoint류는 isZero방법이 있다.
"적중점이 0이면 진짜"라는 구체적인 실시는 다음과 같다.
목록 4.25
  private static final int MIN = 0;
목록 4.25
  boolean isZero() {
    return amount == MIN;
  }
나는 왜 '0' 을 나타내는 필드의 이름이 ZERO 이 아니라 MIN 인지 매우 궁금하다.
값이 0이 아니어도 상관없지만 규격상'안전타점이 0'이라고 표시하면MINZERO이 좋다.
'규격상 인기점은 제로, amount장의 값은 MIN반과 같다'HitPoint반의 디자인은 isZero방법 이외의 코드에서는 볼 수 없다.

p.90: 초기return


나도 초기 리턴의 목적과 장점을 이해할 생각이다.
그런데 리스트 6.9의 코드가 좀 끊겼어요.
목록 6.9
if (hitPointRate == 0) return HealthCondition.dead;
if (hitPointRate < 0.3) return HealthCondition.danger;
if (hitPointRate < 0.5) return HealthCondition.caution;

return HealthCondition.fine;
변경 전 코드(리스트 6.7 또는 리스트 6.8) 중else가 사라지면 조건이 보기 어려워진다.
예를 들어 세 번째 줄if (hitPointRate < 0.5) ....
생명상태는'주의(caution)'란 hitPointRate가 0.30.5 범위에 있는 경우를 뜻하지만'0.3이상'은 앞줄을 보지 않으면 모른다.
또 앞으로'위험'과'주의(caution)'사이에 또 하나의 생명상태가 추가되는 상황에서 그것을 판단하는if문은 반드시 2행과 3행 사이에 틀리지 않게 추가되어야 한다.else가 사라진 후 편의가 개선되었지만 코드를 읽을 때else와 같은 선행if문이 있는 조건도 보이지 않는다. 그러면 else 한 쪽과 앞쪽이 연결되는 것이 더욱 명확하고 이해하기 쉽지 않겠는가. 이것이 바로 이런 상황을 일으키는 원인이다.
글쎄, 내가 쓰기에 익숙하지 않고 읽기에 익숙하지 않은 이유도 있을 거야.
목록 6.4의 초기 리턴과 목록 3.4의 보호 섹션은 전혀 이의가 없다.

이세계의 컬렉션


나는 수치의 대상을 이세계로 설정하는 생각도 알고 그 장점도 이해하려고 했다.
다만, 지금까지 그 소장품들까지 음소거판으로 바꿔야 하는 것은 익숙하지 않아 좀 놀랐다.

원본(Java Edition)


우선 전제다.Party종류Member대상의 소장.
목록 7.11
class Party {
  private final List<Member> members;

  Party() {
    members = new ArrayList<Member>();
  }
}
그리고 Party류 실례에 Member대상add을 추가한다.
이때 Party류가 정음편이라는 것을 유지하기 위해add방법은 새로운Party류의 실례를 생성하고 되돌아오고 있다.
목록 7.13
class Party {
  // 中略
  Party add(final Member newMember) {
    List<Member> adding = new ArrayList<>(members);
    adding.add(newMember);
    return new Party(adding);
  }
또한 다음 구조기가 추가되었습니다.
목록 7.14
  private Party(List<Member> members) {
    this.members = members;
  }

C++ 버전


이 글을 읽고 생각난 건'C++면 어떻게 이루어질까'였어요.
C++의 경우 대상은 인용된 의미뿐만 아니라 값의 의미로도 처리할 수 있다.
도대체 Party 대상이 가지고 있는 Member 대상의 디자인이 적합한지 아직 잘 모르겠어요. 일단 이렇게 정할게요.
목록 7.11과 같은 Party 클래스를 C++로 써 보면 이렇게 될까요?std::vector 유형의 데이터 구성원을const로 설정하는 데 익숙하지 않아 신선합니다.
class Party {
 public:
  Party() = default;

 private:
  const std::vector<Member> members_;
};
다음에 우리는 std::vector<Member> 유형의 수용 가능한 대상의 구조기와 add 구성원 함수를 추가하려고 시도할 것이다.
class Party {
 public:
  Party() = default;

  Party add(const Member &newMember) {
    std::vector<Member> adding{std::move(members_)};
    adding.push_back(newMember);
    return Party{std::move(adding)};
  }

 private:
  const std::vector<Member> members_;

  explicit Party(std::vector<Member> &&members)
      : members_{std::move(members)} {
  }
};
완료.
원래의 자바 버전과 달리 add 구성원 함수에서 Member 유형의 대상이 복제되었는데 이것은 부득이한 것이다.
rvalue reference를 매개 변수로 하는 구성원 함수 add(Member &&member) 를 불러오면 사용할 쪽을 선택할 수 있습니다.
그럼 이Party급을 사용하는 쪽의 인코딩은 이렇습니다.
  auto newParty = currentParty.add(newMember);
의 문제는 add 구성원 함수에서 자신의 members_ 데이터 구성원을 이동한 것이다.
멤버 추가 후 추가 전 대상currentParty도 방문할 수 있어 위험하다[1].
이를 막기 위해 이동하지 않고 복제할 수 있지만, 새로운 Member 대상을 추가할 때마다 기존의 Member 대상은 모두 복제돼 실행 시간이나 메모리 사용량에 상관없이 받아들여지기 어렵다.
다만, add라는 구성원 함수에서 이동되는 것은 놀라운 최소 원칙에 어긋나 좋지 않다.
문장 첫머리에 방치된 이 과제의 해결은 분야를 잘 분석하고 모델링한 뒤다.
도대체 Party 대상이 가지고 있는 Member 대상의 디자인이 적합한지 아직 잘 모르겠어요. 일단 이렇게 정할게요.
이 상황에서 나 자신이라면 지침이 아닐까 싶어요.
저자 미노 드라이버() 씨가 Rust로 다시 쓴다고 해서 조금 신경이 쓰인다.

p.139: Member.id

id 나는 필드가 원시 유형인 것을 매우 의식한다int.
제3장(학급설계)의 방침에 따르면 이것도 전용 학급이어야 한다고 생각합니다.
나는 이 책을 읽기 전부터 원시형(C++에서fundamental types)을 많이 쓰는 스타일에 위화감을 느꼈고, 주변에서도 "인터페이스에 bool형을 제외하고fundamental types를 사용하지 말아야 한다"고 주장했다.
또 "bool형 이외"라는 점은 타협의 결과였지만, 아래 기사를 읽으면서 생각이 바뀌었다.
https://zenn.dev/reputeless/articles/cpp-article-yesno

p.295: isDisabled

CustomerComic 등류isEnabled 방법이 있다.
보호절로 '비enabled' 인자를 제거할 때의 조건식은 !xxx.isEnabled() 이며, 그 중 읽기 어려운 부분이 약간 있습니다.
따라서 논리적 부정!을 사용하지 않고도 추가isDisabled 방법을 판단할 수 있는 아이디어다.
그렇구나, 그렇게 생각하지만 부정적인 의미를 갖게 하는 방법은 본래 이해하기 어려워질 수 있다.isDisabled 직관적으로 이해할 수는 있지만 무엇이 좋고 무엇이 안 되는지에 대한 객관적 기준을 정하기 어려우니 이런 구분이 고민이라면 일률적으로 금지한다.
그리고 !xxx.isDisabled()라고 적힌 프로그래머가 나타나면 싫어할 거야...

끝말


서문에도 썼지만, 이 책에서 저자가 주장하는 내용 대부분은 동의할 만한 이유를 담았다.
한두 개만 준다면 다른 사람들도 할 수 있겠지만 책에서 정리한 것이라 가치가 있다고 생각해요.
이런 상황에서 그런 경향이 있다'등'악마'발생과 관련된 조건과 환경도 언급돼 저자의 다년간의 디자인 개선으로 쌓은 노하우를 체감하게 한다.
먼저 흔히 볼 수 있는'나쁜 코드'를 선보여 독자가 문제점을 이해하게 한 뒤 최종적으로'좋은 코드'로 개선하는 절차는 이해하기 쉽다는 느낌을 준다.
행사가 우선이고 디자인의 품질과 보수성(변경 용이성) 등 사려 깊지 못한 현장도 있어 황금연휴가 끝나면 일자리를 넓히려 한다.
또 제16장(설계의 개발과정을 방해하는 싸움)은 지금 제 위치와 역할에 가장 적합한 내용이다.
참고로 실천하게 해주고 싶습니다.
나는 이 보도 노트 자체가 16.4.3(경의와 예의)의 내용을 따르는지 좀 걱정된다.
각주std::vector 클래스 템플릿은 UB가 될 수 없습니다.↩︎

좋은 웹페이지 즐겨찾기