함수가 수용해야하는 매개 변수 수에 대한 지침이 있습니까?


114

내가 사용하는 몇 가지 함수에는 6 개 이상의 매개 변수가 있지만 대부분의 라이브러리에서는 3 개 이상의 함수를 찾는 것이 거의 없습니다.

이러한 많은 추가 매개 변수는 종종 함수 동작을 변경하기위한 이진 옵션입니다. 나는이 매개 변수가없는 함수 중 일부는 리팩토링되어야한다고 생각합니다. 너무 많은 숫자에 대한 지침이 있습니까?


4
@Ominus : 아이디어는 수업에 집중하고 싶다는 것입니다. 집중된 클래스는 일반적으로 많은 종속성 / 속성을 갖지 않으므로 생성자에 대한 매개 변수가 적습니다. 이 시점에서 사람들이 던지는 몇 가지 유행어는 높은 응집력단일 책임 원칙 입니다. 이러한 사항을 위반하지 않았고 여전히 많은 매개 변수가 필요하다고 생각되면 빌더 패턴 사용을 고려하십시오.
c_maker

2
12 개의 매개 변수를 취하는 MPI_Sendrecv () 의 예를 따르지 마십시오 !
chrisaycock

6
현재 작업중 인 프로젝트는 10 개 이상의 매개 변수가있는 메소드가 일반적 인 특정 프레임 워크를 사용합니다. 두 곳에서 27 개의 매개 변수를 사용하여 하나의 특정 메소드를 호출하고 있습니다. 내가 그것을 볼 때마다 나는 조금 안에 죽는다.
perp

3
기능 동작을 변경하기 위해 부울 스위치를 추가하지 마십시오. 대신 함수를 분할하십시오. 일반적인 동작을 새로운 기능으로 나눕니다.
kevin cline

2
@Ominus 무엇? 10 개의 매개 변수 만? 아무것도 아닙니다. 훨씬 더 많이 필요합니다 . : D
maaartinus

답변:


106

가이드 라인을 본 적이 없지만 경험상 3 ~ 4 개 이상의 매개 변수를 사용하는 함수는 다음 두 가지 문제 중 하나를 나타냅니다.

  1. 기능이 너무 많이 수행되고 있습니다. 각각 더 작은 매개 변수 세트를 갖는 여러 개의 작은 기능으로 분할해야합니다.
  2. 거기에 또 다른 물체가 숨겨져 있습니다. 이러한 매개 변수를 포함하는 다른 오브젝트 또는 데이터 구조를 작성해야 할 수도 있습니다. 자세한 정보 는 매개 변수 오브젝트 패턴에 대한 이 기사 를 참조하십시오.

더 많은 정보 없이는보고있는 내용을 말하기가 어렵습니다. 리팩토링은 현재 함수에 전달되는 플래그에 따라 함수를 더 작은 함수로 분할하는 것입니다.

이 작업을 수행하면 좋은 이점이 있습니다.

  • 코드를보다 쉽게 ​​읽을 수 있습니다. 필자는 개인적 if으로 하나의 메소드에서 모두 수행하는 구조보다 설명적인 이름을 가진 많은 메소드를 호출 하는 구조 로 구성된 "규칙 목록"을 읽는 것이 훨씬 쉽다 는 것을 알게되었습니다.
  • 더 단위 테스트가 가능합니다. 개별적으로 매우 간단한 여러 개의 작은 작업으로 문제를 분할했습니다. 유닛 테스트 콜렉션은 마스터 메소드를 통해 경로를 점검하는 행동 테스트 스위트와 각 개별 프로 시저에 대한 더 작은 테스트 콜렉션으로 구성됩니다.

5
매개 변수 추상화가 디자인 패턴으로 바뀌 었습니까? 3 개의 매개 변수 클래스가 있으면 어떻게됩니까? 다른 가능한 매개 변수 조합을 처리하기 위해 9 개의 메서드 오버로드를 추가합니까? 불쾌한 O (n ^ 2) 매개 변수 선언 문제처럼 들립니다. 아 잠깐, Java / C #에서 1 개의 클래스 만 상속 할 수 있으므로 실제로 작동하려면 좀 더 biolerplate (아마도 서브 클래 싱)가 더 필요합니다. 미안하지만 확신이 없습니다. 복잡성을 위해 언어가 제공 할 수있는보다 표현적인 접근 방식을 무시하는 것은 잘못된 생각입니다.
Evan Plaice

패턴 오브젝트 패턴을 사용하여 오브젝트 인스턴스에서 변수를 패키지하고이를 매개 변수로 전달하지 않는 한. 패키징에는 효과적이지만 메소드 정의를 단순화하기 위해 유사하지 않은 변수 클래스를 작성하려는 유혹이있을 수 있습니다.
Evan Plaice

@EvanPlaice 나는 하나 이상의 매개 변수가있을 때마다 해당 패턴을 사용해야한다고 말하는 것이 아닙니다. 첫 번째 목록보다 훨씬 나쁘다는 것이 절대적으로 정확합니다. 실제로 많은 수의 매개 변수가 필요하고 객체로 감싸는 데 효과가없는 경우가 있습니다. 엔터프라이즈 개발에서 필자가 대답 한 두 가지 버킷 중 하나에 해당하지 않는 사례를 아직 만나지 못했습니다.
Michael K

@MichaelK 사용하지 않은 경우 인터넷 검색 '객체 초기화 프로그램'을 사용해보십시오. 정의 상용구를 크게 줄이는 매우 새로운 접근 방식입니다. 이론적으로 클래스 생성자, 매개 변수 및 오버로드를 모두 한 번에 제거 할 수 있습니다. 실제로는 일반적으로 하나의 공통 생성자를 유지 관리하고 나머지 모호한 / 틈새 속성에 대해 '개체 이니셜 라이저'구문에 의존하는 것이 좋습니다. IMHO는 정적 형식 언어에서 동적 형식 언어의 표현력에 가장 가깝습니다.
Evan Plaice

@Evain Plaice : 언제부터 동적으로 입력되는 언어가 표현 적인가?
ThomasX

41

"Clean Code : Agile Software Craftsmanship 핸드북"에 따르면, 0은 이상적이며, 1 ~ 2 개는 허용되며, 특별한 경우 3 개, 4 개 이상은 절대 허용되지 않습니다!

저자의 말 :

함수에 대한 이상적인 인수 수는 0입니다 (나일론). 다음은 하나 (모나 딕)가오고 그 뒤에는 2 (이차)가옵니다. 가능한 경우 세 가지 주장 (삼국 법)을 피해야합니다. 3 개 이상 (다 극적)은 매우 특별한 타당성을 요구하므로 어쨌든 사용해서는 안됩니다.

이 책에는 매개 변수가 큰 기능에 대해서만 이야기하는 장이 있으므로이 책은 필요한 매개 변수의 양을 잘 설명 할 수 있다고 생각합니다.

내 개인적인 견해로는 한 가지 매개 변수가 아무도 아닌 것보다 낫습니다.

예를 들어, 내 의견으로는 두 번째 선택이 더 낫습니다. 왜냐하면 메소드가 처리하는 것이 더 명확하기 때문입니다.

LangDetector detector = new LangDetector(someText);
//lots of lines
String language = detector.detectLanguage();

vs.

LangDetector detector = new LangDetector();
//lots of lines
String language = detector.detectLanguage(someText);

많은 매개 변수에 대해 이것은 일부 변수가 단일 객체로 그룹화 될 수 있다는 표시 일 수 있습니다.이 경우 많은 부울은 함수 / 메소드가 하나 이상의 작업을 수행하고 있음을 나타낼 수 있습니다. 이러한 기능을 각각 다른 기능으로 리팩토링하는 것이 좋습니다.


8
"특별한 경우에는 3 개, 4 개 이상은 절대! BS. Matrix.Create (x1, x2, x3, x4, x5, x6, x7, x8, x9)는 어떻습니까? ?
Lukasz Madon

71
제로가 이상적입니까? 도대체 함수는 어떻게 정보를 얻습니까? 글로벌 / 인스턴스 / 정적 / 무슨 변수? 왝.
피터 C

9
나쁜 예입니다. 대답은 분명히 : String language = detectLanguage(someText);. 두 경우 모두 정확히 같은 수의 인수를 전달하면 언어가 좋지 않기 때문에 함수 실행을 두 개로 나눕니다.
Matthieu M.

8
@lukas, 배열 또는 (가장자리!) 목록과 같은 멋진 구성을 지원하는 언어 에서 .NET 은 Matrix.Create(input);어디에 있습니까? 이렇게하면 9 대신 10 개의 요소를 포함하는 행렬을 만들 때 별도의 과부하가 필요하지 않습니다.inputIEnumerable<SomeAppropriateType>
CVn

9
"이상적인"이라는 제로의 주장은 고치기이며 Clean Code가 과대 평가되었다고 생각하는 한 가지 이유입니다.
user949300

24

응용 프로그램의 도메인 클래스가 올바르게 설계된 경우 클래스가 작업을 수행하는 방법을 알고 작업을 수행하기에 충분한 데이터가 있기 때문에 함수에 전달하는 매개 변수의 수가 자동으로 줄어 듭니다.

예를 들어, 3 학년 학급에 과제를 완료하도록 요청하는 관리자 클래스가 있다고 가정합니다.

올바르게 모델링하면

3rdGradeClass.finishHomework(int lessonId) {
    result = students.assignHomework(lessonId, dueDate);
    teacher.verifyHomeWork(result);
}

이것은 간단합니다.

올바른 모델이 없으면 방법은 다음과 같습니다.

Manager.finishHomework(grade, students, lessonId, teacher, ...) {
    // This is not good.
}

올바른 모델은 올바른 함수가 자신의 클래스에 위임되고 (단일 책임) 작업을 수행하기에 충분한 데이터가 있기 때문에 항상 메서드 호출 사이의 함수 매개 변수를 줄입니다.

매개 변수 수가 증가 할 때마다 모델을 검사하여 응용 프로그램 모델을 올바르게 설계했는지 확인합니다.

전송 객체 또는 구성 객체를 생성해야 할 경우, 큰 구성 객체를 생성하기 전에 먼저 빌더 패턴을 사용하여 작은 빌드 된 객체를 생성합니다.


16

다른 답변이 취하지 않는 한 가지 측면은 성능입니다.

충분히 낮은 수준의 언어 (C, C ++, 어셈블리)로 프로그래밍하는 경우, 특히 많은 수의 함수가 호출되는 경우 많은 아키텍처의 매개 변수가 일부 아키텍처에서 성능을 저하시킬 수 있습니다.

예를 들어 ARM에서 함수를 호출하면 처음 4 개의 인수가 레지스터 r0에 배치 r3되고 나머지 인수는 스택으로 푸시되어야합니다. 인수 수를 5 미만으로 유지하면 중요한 기능에 상당한 차이가 생길 수 있습니다.

매우 자주 호출되는 함수, 프로그램이 호출 할 때마다 성능에 영향을 줄 수 있습니다 (전에 인수를 설정해야한다는 심지어는 사실 r0r3호출 된 함수에 의해 덮어 쓸 수 있습니다 및 다음 호출하기 전에 교체되어야 할 것이다) 그래서 그런 측면에서 인수가 0이 가장 좋습니다.

최신 정보:

KjMag는 흥미로운 인라인 주제를 제시합니다. 인라이닝은 컴파일러가 순수한 어셈블리로 작성하는 경우 수행 할 수있는 것과 동일한 최적화를 수행 할 수 있도록하기 때문에이를 완화시킵니다. 다시 말해, 컴파일러는 호출 된 함수가 사용하는 매개 변수와 변수를 확인할 수 있으며 스택 읽기 / 쓰기가 최소화되도록 레지스터 사용을 최적화 할 수 있습니다.

그래도 인라인에 문제가 있습니다.

  1. 인라인은 컴파일 된 바이너리가 여러 위치에서 호출되는 경우 동일한 코드가 바이너리 형태로 복제되므로 커지는 바이너리를 증가시킵니다. 이것은 I- 캐시 사용에있어 해 롭습니다.
  2. 컴파일러는 일반적으로 특정 수준 (3 단계 IIRC?)까지만 인라인 할 수 있습니다. 인라인 함수에서 인라인 함수에서 인라인 함수를 호출한다고 상상해보십시오. inline모든 경우에 필수적으로 취급 된다면 이진 성장은 폭발 할 것이다 .
  3. 완전히 무시 inline하거나 실제로 발생할 때 오류를 발생시키는 컴파일러가 많이 있습니다.

성능 관점에서 많은 매개 변수를 전달하는 것이 좋은지 나쁜지는 대안에 따라 다릅니다. 메소드에 수십 개의 정보가 필요하고 11 개에 대해 동일한 값으로 수백 번 호출하는 경우 메소드가 배열을 가져가는 것이 수십 개의 매개 변수를 취하는 것보다 빠를 수 있습니다. 반면, 모든 호출에 고유 한 12 개의 값 세트가 필요한 경우 각 호출에 대해 배열을 작성하고 채우는 것이 단순히 값을 직접 전달하는 것보다 쉽게 ​​느려질 수 있습니다.
supercat

인라인이이 문제를 해결하지 않습니까?
KjMag

@ KjMag : 예, 어느 정도입니다. 그러나 컴파일러에 따라 많은 어려움이 있습니다. 함수는 일반적으로 특정 수준까지만 인라인됩니다 (인라인 함수를 호출하는 인라인 함수를 호출하는 인라인 함수를 호출하는 경우 ...). 함수가 크고 많은 곳에서 호출되는 경우 모든 위치를 인라인하면 바이너리가 커지므로 I- 캐시에서 더 많은 누락이 발생할 수 있습니다. 따라서 인라인이 도움이 될 수 있지만 은색 총알이 아닙니다. (이를 지원하지 않는 오래된 임베디드 컴파일러는 거의 없습니다 inline.)
Leo

7

매개 변수 목록이 5 개 이상으로 증가하면 "컨텍스트"구조 또는 오브젝트 정의를 고려하십시오.

이것은 기본적으로 합리적인 기본값이 설정된 모든 선택적 매개 변수를 보유하는 구조입니다.

C 절차 세계에서는 일반 구조가 수행됩니다. Java, C ++에서는 간단한 객체로 충분합니다. 객체의 유일한 목적은 "공개"로 설정 가능한 값을 보유하는 것이므로 게터 나 세터를 망설이지 마십시오.


함수 매개 변수 구조가 다소 복잡해지기 시작하면 컨텍스트 객체가 매우 유용하다는 데 동의합니다. 최근 에 방문자와 같은 패턴으로 컨텍스트 객체를 사용하는 방법
Lukas Eder

5

아니요, 표준 가이드 라인이 없습니다.

그러나 많은 매개 변수가있는 기능을 더 견딜 수있게하는 몇 가지 기술이 있습니다.

인수 목록 매개 변수 (args *) 또는 사전 인수 매개 변수 (kwargs **)를 사용할 수 있습니다.

예를 들어, 파이썬에서 :

// Example definition
def example_function(normalParam, args*, kwargs**):
  for i in args:
    print 'args' + i + ': ' + args[i] 
  for key in kwargs:
    print 'keyword: %s: %s' % (key, kwargs[key])
  somevar = kwargs.get('somevar','found')
  missingvar = kwargs.get('somevar','missing')
  print somevar
  print missingvar

// Example usage

    example_function('normal parameter', 'args1', args2, 
                      somevar='value', missingvar='novalue')

출력 :

args1
args2
somevar:value
someothervar:novalue
value
missing

또는 객체 리터럴 정의 구문을 사용할 수 있습니다

예를 들어 AJAX GET 요청을 시작하기위한 JavaScript jQuery 호출은 다음과 같습니다.

$.ajax({
  type: 'GET',
  url: 'http://someurl.com/feed',
  data: data,
  success: success(),
  error: error(),
  complete: complete(),
  dataType: 'jsonp'
});

jQuery의 ajax 클래스를 살펴보면 설정할 수있는 속성이 훨씬 더 많다 (약 30 개). 대부분 아약스 통신은 매우 복잡하기 때문입니다. 다행히도 객체 리터럴 구문은 삶을 쉽게 만듭니다.


C # intellisense는 매개 변수에 대한 능동적 인 문서를 제공하므로 오버로드 된 메서드의 매우 복잡한 배열을 보는 것은 드문 일이 아닙니다.

python / javascript와 같이 동적으로 유형이 지정된 언어에는 그러한 기능이 없으므로 키워드 인수와 객체 리터럴 정의를 보는 것이 훨씬 일반적입니다.

객체가 인스턴스화 될 때 설정되는 속성을 명시 적으로 볼 수 있기 때문에 복잡한 메소드를 관리하기 위해 객체 리터럴 정의 ( C #에서도 )를 선호합니다 . 기본 인수를 처리하려면 약간 더 많은 작업을 수행해야하지만 장기적으로 코드를 훨씬 더 읽기 쉽게 할 수 있습니다. 객체 리터럴 정의를 사용하면 문서에 대한 의존성을 깨뜨려 코드가 한 눈에 무엇을하고 있는지 이해할 수 있습니다.

IMHO, 오버로드 된 메소드는 과대 평가되었습니다.

참고 : 올바른 읽기 전용 액세스 제어를 기억하면 C #의 객체 리터럴 생성자에 대해 작동해야합니다. 본질적으로 생성자에서 속성을 설정하는 것과 동일하게 작동합니다.


사소하지 않은 코드를 동적으로 유형이 지정된 (python) 및 / 또는 기능 / 시제품 javaScript 기반 언어로 작성하지 않은 경우 직접 사용해 보는 것이 좋습니다. 깨달은 경험이 될 수 있습니다.

함수 / 메소드 초기화에 대한 포괄적 인 접근 방식에 대한 매개 변수에 의존하는 것이 먼저 무섭지 않을 수 있지만 불필요한 복잡성을 추가하지 않고도 코드로 훨씬 더 많은 것을 배우게됩니다.

최신 정보:

정적으로 형식이 지정된 언어에서 사용하는 방법을 보여주는 예제를 제공했을 수도 있지만 현재는 정적으로 형식화 된 컨텍스트에서 생각하지 않습니다. 기본적으로 동적으로 입력 된 컨텍스트에서 갑자기 다시 전환하기 위해 너무 많은 작업을 수행했습니다.

내가 알고있는 것은 내가 전에 그것들을 사용했기 때문에 (적어도 C # 및 Java로) 문자 정의 구문이 정적으로 입력 된 언어로 완전하게 가능하다 개체입니다. 정적으로 입력 된 언어에서는 '개체 이니셜 라이저'라고합니다. 다음은 JavaC # 에서의 사용법을 보여주는 링크 입니다.


3
개별 매개 변수의 자체 문서화 값을 잃기 때문에이 방법이 마음에 들지 않습니다. 유사한 항목 목록의 경우 이것은 완벽하게 의미가 있습니다 (예 : 문자열 목록을 가져 와서 연결하는 메소드). 임의의 매개 변수 세트의 경우 이는 긴 메소드 호출보다 나쁩니다.
Michael K

@MichaelK 객체 이니셜 라이저를 다시 살펴보십시오. 기존 메소드 / 함수 매개 변수에서 암시 적으로 정의되는 방식과 달리 속성을 명시 적으로 정의 할 수 있습니다. msdn.microsoft.com/en-us/library/bb397680.aspx를 읽고 의미하는 바를 확인하십시오.
Evan Plaice

3
매개 변수 목록을 처리하기 위해 새 유형을 만드는 것은 불필요한 복잡성의 정의와 똑같습니다 ... 물론, 동적 언어는이를 피할 수 있지만 goo 매개 변수의 단일 공을 얻습니다. 그럼에도 불구하고 이것은 질문에 대답하지 않습니다.
Telastyn

@Telastyn 무슨 소리 야? 새 유형이 작성되지 않았으므로 오브젝트 리터럴 구문을 사용하여 직접 특성을 선언하십시오. 익명 객체를 정의하는 것과 비슷하지만 메소드는이를 객체를 키 = 값 매개 변수 그룹으로 해석합니다. 당신이보고있는 것은 메소드 인스턴스화입니다 (매개 변수 캡슐화 객체가 아닙니다). 소고기에 패키징 패키징이 포함 된 경우 다른 질문 중 하나에서 언급 한 Parameter Object 패턴을 살펴보십시오.
Evan Plaice

@EvanPlaice-정적 프로그래밍 언어는 매개 변수 개체 패턴을 허용하기 위해 (종종 새로 새로 선언 된) 유형을 요구하는 것을 제외하고.
Telastyn

3

개인적으로 2 개 이상이 코드 냄새 경보가 울리는 곳입니다. 함수를 조작 (입력에서 출력으로 변환)으로 간주 할 때 조작 에 둘 이상의 매개 변수가 사용되는 경우는 드 un니다. 절차 (목표를 달성하기위한 일련의 단계)는 더 많은 정보를 필요로하며 때로는 최선의 접근 방법이지만 대부분의 언어에서 요즘은 표준이되어서는 안됩니다.

그러나 다시, 그것은 규칙이 아니라 지침입니다. 비정상적인 상황이나 사용 편의성으로 인해 두 개 이상의 매개 변수를 사용하는 기능이 종종 있습니다.


2

Evan Plaice가 말한 것과 마찬가지로, 가능한 경우 연관 배열 (또는 언어의 비교 가능한 데이터 구조)을 함수에 전달하는 것을 좋아합니다.

따라서 (예를 들어) 대신 :

<?php

createBlogPost('the title', 'the summary', 'the author', 'the date of publication, 'the keywords', 'the category', 'etc');

?>

간다 :

<?php

// create a hash of post data
$post_data = array(
  'title'    => 'the title',
  'summary'  => 'the summary',
  'author'   => 'the author',
  'pubdate'  => 'the publication date',
  'keywords' => 'the keywords',
  'category' => 'the category',
  'etc'      => 'etc',
);

// and pass it to the appropriate function
createBlogPost($post_data);

?>

워드 프레스는 이런 식으로 많은 일을하는데 잘 작동한다고 생각합니다. (위의 예제 코드는 상상력이 뛰어나며 Wordpress의 예제는 아닙니다.)

이 기술을 사용하면 많은 데이터를 함수에 쉽게 전달할 수 있지만 각 데이터를 전달해야하는 순서를 기억하지 않아도됩니다.

리팩토링 할 때가되면이 기술에 감사 할 것입니다. 함수 인수의 순서를 변경하지 않고 (예 : 다른 인수를 전달해야한다는 것을 알고있을 때) 함수의 매개 변수를 변경할 필요가 없습니다. 전혀 나열하지 마십시오.

이렇게하면 함수 정의를 다시 작성하지 않아도되며 함수가 호출 될 때마다 인수 순서를 변경하지 않아도됩니다. 대단한 승리입니다.


이 게시물을 보면 pass-a-hash 접근 방식의 또 다른 이점이 있습니다. 첫 번째 코드 예제는 너무 길어서 스크롤 막대를 생성하고 두 번째 코드는 페이지에 깔끔하게 맞습니다. 코드 편집기에서도 마찬가지입니다.
Chris Allen Lane

0

이전 답변 에서는 함수의 매개 변수가 적을수록 더 잘 수행한다고 말한 신뢰할 수있는 작성자를 언급했습니다. 대답은 왜 그 이유를 설명하지 않았지만 책은 그것을 설명합니다. 그리고 여기 당신이이 철학을 채택해야하고 내가 개인적으로 동의하는 가장 설득력있는 두 가지 이유가 있습니다.

  • 매개 변수는 함수와 다른 추상화 레벨에 속합니다. 이것은 코드의 독자가 함수의 매개 변수의 본질과 목적에 대해 생각해야한다는 것을 의미합니다.이 생각은 이름의 의미와 해당 함수의 목적보다 "낮은 수준"입니다.

  • 함수에 대해 가능한 한 적은 매개 변수를 갖는 두 번째 이유는 테스트입니다. 예를 들어, 10 개의 매개 변수가있는 함수가있는 경우 단위와 같이 모든 테스트 케이스를 포함해야하는 매개 변수 조합 수에 대해 생각하십시오. 테스트. 적은 매개 변수 = 적은 테스트.


0

Robert Martin의 "Clean Code : Handbook of Agile Software Craftsmanship"에서 함수 인수의 이상적인 수에 대한 조언에 대한 더 많은 컨텍스트를 제공하기 위해 저자는 다음과 같이 말합니다.

인수는 어렵다. 그들은 많은 개념적 힘을 취합니다. 그렇기 때문에 예제에서 거의 모든 것을 제거했습니다. 예를 들어, 예를 고려하십시오 StringBuffer. 인스턴스 변수로 만드는 대신 인수로 전달할 수 있었지만 독자는 그것을 볼 때마다 해석해야했습니다. 모듈이 말한 이야기를 읽을 includeSetupPage() 때보다 이해하기 쉽습니다 includeSetupPageInto(newPageContent). 인수는 함수 이름과는 다른 추상화 수준에 있으며, StringBuffer그 시점에서 특별히 중요하지 않은 세부 사항 (즉, )을 강제로 알려 줍니다.

includeSetupPage()위의 예를 들어, 다음 장의 마지막 부분에서 리팩토링 된 "깨끗한 코드"에 대한 작은 스 니펫이 있습니다.

// *** NOTE: Commments are mine, not the author's ***
//
// Java example
public class SetupTeardownIncluder {
    private StringBuffer newPageContent;

    // [...] (skipped over 4 other instance variables and many very small functions)

    // this is the zero-argument function in the example,
    // which calls a method that eventually uses the StringBuffer instance variable
    private void includeSetupPage() throws Exception {
        include("SetUp", "-setup");
    }

    private void include(String pageName, String arg) throws Exception {
        WikiPage inheritedPage = findInheritedPage(pageName);
        if (inheritedPage != null) {
            String pagePathName = getPathNameForPage(inheritedPage);
            buildIncludeDirective(pagePathName, arg);
        }
    }

    private void buildIncludeDirective(String pagePathName, String arg) {
        newPageContent
            .append("\n!include ")
            .append(arg)
            .append(" .")
            .append(pagePathName)
            .append("\n");
    }
}

저자의 "스쿨 오브 스쿨"은 작은 클래스, (이상적으로는 0) 개의 함수 인수 및 매우 작은 함수를 주장합니다. 나는 또한 그에게 완전히 동의하지는 않지만 생각을 자극하는 것을 발견했으며 함수로서 제로 함수 인수에 대한 아이디어를 고려해 볼 가치가 있다고 생각합니다. 또한 위의 작은 코드 스 니펫조차도 0이 아닌 인수 함수도 있으므로 컨텍스트에 따라 다릅니다.

(그리고 다른 사람들이 지적했듯이, 그는 또한 더 많은 논증이 테스트 관점에서 어려워 진다고 주장하지만 여기서는 주로 위의 예와 제로 함수 논증에 대한 그의 이론적 근거를 강조하고 싶었습니다.)


-2

이상적으로는 0입니다. 어떤 경우에는 한두 개는 괜찮습니다.
일반적으로 4 개 이상이 나쁜 습관입니다.

다른 사람들이 지적한 단일 책임 원칙뿐만 아니라 관점을 테스트하고 디버깅하여 생각할 수도 있습니다.

하나의 매개 변수가 있으면 값을 알고 테스트하고 오류를 찾는 것이 한 가지 요소 만 있기 때문에 상대적으로 쉽습니다. 요인을 늘리면 총 복잡성이 빠르게 증가합니다. 추상적 인 예를 들면 :

'이 날씨에 무엇을 입을 까'프로그램을 고려하십시오. 하나의 입력 온도로 무엇을 할 수 있는지 고려하십시오. 당신이 상상할 수 있듯이, 무엇을 입을 것인가의 결과는 그 한 가지 요소에 근거하여 매우 간단합니다. 이제 프로그램이 실제로 온도, 습도, 이슬점, 강수량 등을 통과 한 경우 수행 할 수있는 / 할 수있는 / 할 수있는 일을 고려하십시오.


12
함수에 매개 변수가없는 경우 상수 값을 반환하거나 (일부 상황에서는 유용하지만 제한적 임) 은닉 상태를 사용하여 명시 적으로 만드는 것이 좋습니다. (OO 메소드 호출에서 컨텍스트 오브젝트는 문제점을 일으키지 않도록 충분히 명시 적입니다.)
Donal Fellows

4
-1 출처를 인용하지 않은
조슈아 드레이크

이상적으로 모든 기능이 매개 변수를 사용하지 않을 것이라고 진지하게 말하고 있습니까? 아니면이 과장인가?
GreenAsJade

1
infoit.com/articles/article.aspx?p=1375308 에서 Bob 아저씨의 주장을 참조 하고 맨 아래에 "함수에는 적은 수의 인수가 있어야합니다. 가장 좋은 인수는 없으며, 1, 2, 3이 뒤 따릅니다." 세 명 이상이 매우 의심스럽고 편견을 피해야합니다. "
Michael Durrant

나는 소스를 주었다. 그 이후로 댓글이 없습니다. 나는 또한 많은 사람들이 밥 삼촌과 클린 코드를 지침으로 간주하면서 '지침'부분에 답하려고 노력했다. (현재) 엄청나게 인기있는 최고 답변이 가이드 라인을 모른다고 말하는 것에 흥미가 있습니다. Bob 아저씨는 권한을 가지 려고 의도 하지 않았지만 다소 그렇습니다.이 답변은 최소한 질문의 구체적 내용에 대한 답변이 되려고합니다.
Michael Durrant
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.