깨끗한 코드 : 매개 변수가 적은 짧은 방법의 결과


15

최근 코드 검토 중에 냄새가 나는 패턴이 들어있는 새로운 동료가 작성한 코드를 발견했습니다. 동료의 결정은 유명한 Clean Code 책 (그리고 아마도 다른 유사한 책들)에 의해 제안 된 규칙에 근거한 것으로 생각됩니다.

클래스 생성자가 전적으로 유효한 객체 생성을 책임지고 주요 작업이 객체의 (비공개) 속성 할당이라는 것을 이해합니다. 물론 선택적 속성 값이 클래스 생성자 이외의 메소드에 의해 설정 될 수도 있지만, 그러한 상황은 다소 드물지만 (나머지 클래스의 나머지가 그러한 속성의 선택성을 고려한다면 반드시 틀릴 필요는 없습니다). 이것은 객체가 항상 유효한 상태임을 보장 할 수 있기 때문에 중요합니다.

그러나 내가 만난 코드에서 대부분의 속성 값은 실제로 생성자 이외의 다른 방법으로 설정됩니다. 계산 결과 값은 속성 전체에 할당되어 클래스 전체의 여러 개인 메서드 내에서 사용됩니다. 저자는 클래스 속성을 필요한 함수에 매개 변수화하는 대신 클래스 전체에서 액세스 할 수있는 전역 변수 인 것처럼 클래스 특성을 사용하는 것 같습니다. 또한 클래스의 메서드는 특정 순서로 호출해야합니다. 클래스는 별다른 영향을 미치지 않기 때문입니다.

이 코드는 큰 매개 변수 목록 (<3 매개 변수)을 피하기 위해 메서드를 짧게 유지 (<= 5 줄)하는 조언에 영감을 받았으며 생성자가 작동하지 않아야한다고 생각합니다 (예 : 일종의 계산 수행) 그것은 객체의 유효성에 필수적입니다).

물론 메소드가 특정 순서로 호출되지 않을 때 모든 종류의 정의되지 않은 오류가 발생할 수 있음을 증명할 수 있다면이 패턴에 대해 사례를 만들 수 있습니다. 그러나 이에 대한 응답은 속성을 설정 해야하는 메소드가 호출되면 속성을 설정 해야하는지 확인하는 유효성 검사를 추가 할 것으로 예상됩니다.

그러나 코드를 완전히 변경하여 클래스가 특정 순서로 (절차 적으로) 호출 해야하는 일련의 메소드가 아닌 실제 객체에 대한 블루 프린트가되도록 제안합니다.

내가 만난 코드가 냄새가 나는 것 같습니다. 사실, 클래스 속성에 값을 저장할 때와 다른 방법을 사용하기 위해 매개 변수에 넣을 때에 대해 분명한 차이점이 있다고 생각합니다. . 나는이 구별에 대한 단어를 찾고 있습니다.


6
1. 악마의 옹호자를 잠시 재생하는 법 ... 코드가 실제로 작동합니까? 데이터 전송 객체 는 완벽하게 유효한 기술 이기 때문에 이것이 전부라면 ...
Robert Harvey

7
2. 문제를 설명 할 단어가 부족하면 동료의 입장을 반박 할 충분한 경험이 없습니다.
Robert Harvey

4
3. 게시 할 수있는 작업 코드가 있으면 코드 검토에 게시 한 후 살펴 보도록하십시오. 그렇지 않으면 이것은 방황하는 일반성입니다.
Robert Harvey

5
@RobertHarvey "계산을 통해 여러 개인 메서드 내에서 사용할 속성에 계산 결과가 할당 된 값"은 자존심이 강한 DTO처럼 들리지 않습니다. 좀 더 구체적이 도움이 될 것이라는 데 동의합니다.
topo Reinstate Monica

4
따로 : 누군가가 실제로 코드 를 bash 전에 읽지 않은 것처럼 들립니다. 방금 다시 스캔했는데 "생성자가 작업하지 말아야 함"(실제로는 일부 작업을 수행해야 함)을 제안하는 곳을 찾을 수 없으며 너무 많은 매개 변수를 피하기위한 제안 된 솔루션은 관련 매개 변수 개체 통합을 만드는 것입니다. 매개 변수 그룹, 기능을 방해하지 않습니다. 또한이 책 메소드 간의 시간적 종속성을 피하기 위해 리팩토링 코드를 제안합니다. 나는 그가 선호하는 몇 가지 코드 스타일에 대한 편견이 책에 대한 당신의 인식을 채색했다고 생각합니다.
Eric King

답변:


13

Clean Code를 읽고 Clean Coders 시리즈를 여러 번 보았고 다른 사람들이 더 깨끗한 코드를 작성하는 것을 가르치고 코치하는 사람은 실제로 관찰 한 내용이 정확하다는 것을 보증 할 수 있습니다. .

그러나이 책은 당신이 지적한 지침과 함께 적용되어야 할 다른 요점들을 계속 제시합니다. 다루고있는 코드에서 이것들은 무시되었습니다. 동료가 여전히 학습 단계에 있기 때문에 이런 일이 발생했을 수 있습니다.이 경우 코드 의 냄새 를 지적하는 데 필요한만큼 그들이 선의의 학습, 학습 및 시도를하고 있다는 것을 기억하는 것이 좋습니다 더 나은 코드를 작성합니다.

Clean Code는 가능한 한 적은 인수로 메소드가 짧아야한다고 제안합니다. 하지만 그 지침에 따라, 우리가 folow해야한다는 제안 S , 올 리드 원칙을 증가 응집력을 하고 감소 커플 링을 .

SOLID 의 S 는 단일 책임 원칙 (Single Responsibility Principle)의 약자로, 개체가 한 가지만 책임 져야한다는 내용입니다. "사물"은 매우 정확한 용어가 아니므로이 원리에 대한 설명은 매우 다양합니다. 그러나 Clean Code의 저자 인 Bob 아저씨도이 원칙을 만든 사람입니다. "같은 이유로 바뀌는 것들을 모으십시오. 다른 이유로 바뀌는 것들을 분리하십시오." 그는 여기여기 를 바꿔야이유가 무엇을 의미하는지 계속해서 말합니다.(더 자세한 설명은 여기에 너무 많습니다). 이 원칙을 처리하는 클래스에 적용한 경우 계산을 처리하는 부분이 여러 가지 이유 에 따라 클래스를 둘 이상으로 분할하여 보류 상태를 처리하는 항목과 분리 될 가능성이 큽니다. 그 계산 을 변경 합니다.

또한 Clean 클래스는 응집력이 있어야합니다 . 즉, 대부분의 메서드는 대부분의 속성을 사용합니다. 따라서 최대 응집력 클래스는 모든 메소드가 모든 속성을 사용하는 클래스입니다. 예를 들어, 그래픽 응용 프로그램에서 당신은 할 수 있습니다 Vector속성을 가진 클래스 Point aPoint b유일한 방법은, scaleBy(double factor)그리고 printTo(Canvas canvas), 두 속성에 모두 작동합니다. 반대로 최소 응집 클래스는 각 속성이 하나의 메소드에만 사용되는 클래스이며 각 메소드가 하나 이상의 속성을 사용하지 않습니다. 응집력 부품의 평균에서, 클래스 선물 비 응집 "그룹"- 즉, 몇 가지 방법이 속성을 사용 a, b그리고 c, 나머지는 사용하는 동안 cd -클래스를 두 개로 나누면 두 개의 응집체로 끝납니다.

마지막으로 Clean 클래스는 가능한 한 커플 링 을 줄여야 합니다. 여기에서 논의 할 가치가있는 많은 유형의 커플 링이 있지만, 코드는 주로 시간적 커플 링 으로 고통받는 것 같습니다. 여기서 지적했듯이 객체의 메소드는 올바른 순서로 호출 될 때 예상대로 작동합니다. 위에서 언급 한 두 가지 지침과 마찬가지로 이에 대한 해결 방법은 일반적으로 클래스를 둘 이상의 응집력있는 객체로 분할하는 것 입니다. 이 경우 분할 전략에는 일반적으로 빌더 또는 팩토리와 같은 패턴과 매우 복잡한 경우 상태-기계가 포함됩니다.

TL; DR : 동료가 준수한 Clean Code 지침은 훌륭하지만이 책에서 언급 한 나머지 원칙, 관행 및 패턴을 따르는 경우에만 유효합니다. 여러분이보고있는 "클래스" 의 클린 버전은 각각 단일 책임, 응집력있는 방법 및 시간적 결합이없는 여러 클래스로 나뉩니다. 이것은 작은 방법과 거의없는 논증이 이해되는 맥락입니다.


1
당신과 토포 모토 모두 좋은 답변을 썼지 만, 나는 오직 하나만 받아 들일 수 있습니다. 나는 당신이 SRP, 응집력 및 결합을 다루는 것을 좋아합니다. 이것들은 코드 검토에 사용할 수있는 유용한 용어입니다. 자신의 책임을 가지고 객체를 더 작은 객체로 나누는 것이 분명합니다. 많은 클래스 속성으로 값을 초기화하는 하나의 (비 생성자) 메소드는 새 객체를 반환해야한다는 단점입니다. 나는 그것을 보았어야했다.
user2180613

1
SRP는 가장 중요한 지침입니다. 그들 모두를 지배하는 하나의 반지. 잘 수행 된 SRP는 자연스럽게 방법이 짧아집니다. 예 : 2 개의 공용 및 약 8 개의 비 공용 메서드가있는 전면 클래스가 있습니다. 아무도 ~ 3 줄 이상입니다; 전체 수업은 약 35 LOC입니다. 그러나 나는이 수업을 마지막으로 썼다! 모든 기본 코드가 작성 될 때까지이 클래스는 본질적으로 자체 작성되었으며 실제로 메서드를 더 크게 만들 필요는 없었습니다. 나는 "이 방법이 나를 죽이면 5 줄로 작성하겠다"고 말하지 않았다. SRP를 적용 할 때마다 발생합니다.
radarbob

11

클래스 생성자는 전적으로 유효한 객체 생성에 책임이 있으며 주요 작업은 객체의 (비공개) 속성 할당이라는 것입니다.

일반적으로 객체를 초기의 유효한 상태로 만드는 책임이 있습니다. 그러면 다른 속성 또는 메서드가 상태를 다른 유효한 상태로 변경할 수 있습니다.

그러나 내가 만난 코드에서 대부분의 속성 값은 실제로 생성자 이외의 다른 방법으로 설정됩니다. 계산 결과 값은 속성 전체에 할당되어 클래스 전체의 여러 개인 메서드 내에서 사용됩니다. 저자는 클래스 속성을 필요한 함수에 매개 변수화하는 대신 클래스 전체에서 액세스 할 수있는 전역 변수 인 것처럼 클래스 특성을 사용하는 것 같습니다. 또한 클래스의 메서드는 특정 순서로 호출해야합니다. 클래스는 별다른 영향을 미치지 않기 때문입니다.

가독성 및 유지 관리 성 문제와 함께 클래스 자체에서 여러 단계의 데이터 흐름 / 변환이 진행되는 것처럼 들리는데, 이는 클래스가 단일 책임 원칙에 위배된다는 것을 나타낼 수 있습니다.

이 코드는 큰 매개 변수 목록 (<3 매개 변수)을 피하기 위해 메서드를 짧게 유지 (<= 5 줄)하는 조언에서 영감을 받았으며 생성자가 작업을 수행해서는 안된다고 생각합니다 (예 : 객체의 유효성에 필수적입니다).

다른 코딩을 무시하면서 일부 코딩 지침을 따르는 경우 종종 바보 같은 코드가 발생합니다. 경우 우리는 예를 들어, 일을 생성자를 피하려고, 분별있는 방법은 일반적으로 건설하기 전에 일을하고 생성자에서 그 일의 결과를 전달하는 것입니다. (이 접근법에 대한 한 가지 주장은 클래스의 두 가지 책임, 즉 초기화 작업과 '주요 작업'에 관계없이 두 가지 책임을지지 않는 것입니다.)

내 경험상, 클래스와 메소드를 작게 만드는 것은 별개의 고려 사항으로 염두에 두어야 할 것이 거의 없습니다. 오히려 단일 책임에서 자연스럽게 따라옵니다.

그러나 코드를 완전히 변경하여 클래스가 특정 순서로 (절차 적으로) 호출 해야하는 일련의 메소드가 아닌 실제 객체에 대한 블루 프린트가되도록 제안합니다.

당신은 아마 그렇게 할 것입니다. 간단한 절차 코드를 작성하는 데 아무런 문제가 없습니다. OO 패러다임을 남용하여 난독 화 된 절차 코드를 작성하는 데 문제가 있습니다.

클래스 속성에 값을 저장할 때와 다른 방법을 사용하기 위해 매개 변수에 넣을 때와는 분명한 차이점이 있다고 생각합니다. 서로 다른 대안이 될 수 있다고 생각하지 않습니다. 나는이 구별에 대한 단어를 찾고 있습니다.

일반적으로 한 메소드에서 다른 메소드로 값을 전달하는 방식으로 필드에 값을 입력해서는 안됩니다. 필드의 값은 주어진 시간에 객체 상태의 의미있는 부분이어야합니다. (유효한 예외는 생각할 수 있지만 그러한 메소드가 공개적이거나 클래스 사용자가 알아야 할 순서 종속성이있는 예외는 아닙니다)


2
다음과 같은 이유로 찬성 투표 1. SRP를 강조. "... 작은 방법 ... 자연스럽게 따라 가기" 2. 생성자 목적-유효한 상태. 3. "일부 코딩 지침을 따르고 다른 지침은 무시하십시오." 이것은 코딩의 워킹 데드입니다.
radarbob

6

여기에 잘못된 패턴이있을 가능성이 높습니다. 작은 기능과 낮은 arity 자체는 거의 문제가되지 않습니다. 여기서 중요한 문제는 함수 간의 순서 의존성을 유발하는 결합이므로 작은 함수의 이점을 버리지 않고 이를 해결할 수있는 방법을 찾으십시오 .

코드는 단어보다 더 크게 말합니다. 리팩토링의 일부를 실제로 수행하고 개선을 보여줄 수 있다면 사람들은 이러한 종류의 수정을 훨씬 더 잘받습니다. 이 작업을 수행 할 때 모든 기준의 균형을 맞추고 설계를 올바르게하는 것이 생각보다 어려운 경우가 많습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.