내부 구조가 있으면 긴 기능을 사용할 수 있습니까?


23

Python 및 D와 같은 중첩 함수를 지원하는 언어에서 복잡한 알고리즘을 처리 할 때 알고리즘이 복잡하기 때문에 종종 큰 함수를 작성하지만 중첩 함수를 사용하여 복잡한 코드를 구성하여이를 완화합니다. 중첩 된 함수를 사용하여 내부적으로 잘 구조화되어 있어도 거대한 (100+ 라인) 함수가 여전히 악의적 인 것으로 간주됩니까?

편집 : Python 또는 D에 익숙하지 않은 사람들을 위해 이러한 언어의 중첩 함수는 외부 함수 범위에 대한 액세스를 허용합니다. D에서이 접근은 외부 범위에서 변수의 변이를 허용합니다. 파이썬에서는 읽기만 허용합니다. D에서는 중첩 함수에서 외부 범위에 대한 액세스를 선언하여 명시 적으로 비활성화 할 수 있습니다 static.


5
나는 400 개 이상의 라인 함수 / 메소드를 정기적으로 작성합니다. 꼭 그 500의 경우 스위치 문 어딘가에 :) 넣어
캘럼 로저스

7
@Callum Rogers : Python에서는 500 개의 case switch 문 대신 조회 사전 / 매핑을 사용합니다. 나는 그들이 500 대 스위치 사례 진술보다 우수하다고 생각합니다. 여전히 500 줄의 사전 정의가 필요합니다 (또는 파이썬에서는 리플렉션을 사용하여 동적으로 열거 할 수 있음). 사전 정의는 코드가 아닌 데이터입니다. 큰 함수 정의보다 큰 데이터 정의를 갖는 것에 대한 퀄리티가 훨씬 적습니다. 또한 데이터는 코드보다 강력합니다.
Lie Ryan

LOC가 많은 함수를 볼 때마다 울부 짖고 모듈화의 목적이 무엇인지 궁금해합니다. 논리를 따르고 더 작은 함수로 디버그하는 것이 더 쉽습니다.
Aditya P

고대의 친숙한 파스칼 언어는 외부 스코프에 액세스 할 수 있으며 GNU C의 중첩 함수 확장도 가능합니다. (이 언어는 하향 펑크 만 만 허용합니다. 즉, 스코프를 전달하는 함수 인 인수 만 가능합니다. 전체 어휘 폐쇄 지원이 필요한 경우 전달 및 반환되지 않음).
Kaz

긴 경향이있는 함수의 좋은 예는 반응 형 프로그래밍을 수행 할 때 작성하는 조합기입니다. 그들은 쉽게 30 라인을 친다. 그러나 당신이 폐쇄를 잃기 때문에 분리되면 크기가 두 배가 될 것이다.
Craig Gidney

답변:


21

항상 규칙을 기억하십시오. 함수는 한 가지 일을하고 잘합니다! 그렇게 할 수 있으면 중첩 함수를 피하십시오.

가독성과 테스트를 방해합니다.


9
높은 수준의 추상화에서 볼 때 "하나의 것"을 수행하는 함수가 낮은 수준에서 볼 때 "많은 것"을 수행 할 수 있기 때문에 항상이 규칙을 싫어했습니다. 잘못 적용하면 "한 가지"규칙이 지나치게 세분화 된 API로 이어질 수 있습니다.
dsimcha

1
@ dsimcha : 어떤 규칙을 잘못 적용하여 문제를 일으킬 수 없습니까? 누군가가 유용한 지점을지나 "규칙"/ 기준을 적용하는 경우 다른 규칙을 제시하십시오. 모든 일반화는 거짓입니다.

2
@Roger : IMHO 규칙이 실제로 잘못 적용되어 지나치게 세분화되고 지나치게 엔지니어링 된 API를 정당화한다는 점을 제외하고는 합법적 인 불만. 이는 단순하고 일반적인 사용 사례에 API를 사용하기가 점점 어려워지고 구체적인 비용이 발생합니다.
dsimcha

2
"예, 규칙이 잘못 적용되었지만 규칙이 잘못 적용되었습니다!"? : P

1
내 기능은 한 가지 일을하고 그 일을 아주 잘 수행합니다. 즉, 27 화면을 차지합니다. :)
Kaz

12

일부는 짧은 기능이 긴 기능보다 오류가 발생하기 쉽다고 주장했습니다 .

Card and Glass (1990)는 설계 복잡성에는 실제로 각 구성 요소 내의 복잡성과 구성 요소 간의 관계의 복잡성이라는 두 가지 측면이 관련되어 있다고 지적합니다.

개인적으로, 나는 잘 작성된 직선 코드가 다른 곳에서는 사용되지 않는 여러 함수로 나뉘어 질 때보 다 (특히 처음에 작성한 코드가 아닌 경우) 따라 가기가 더 쉽다는 것을 알았습니다. 그러나 그것은 실제로 상황에 달려 있습니다.

주요 테이크 아웃은 코드 블록을 분할 할 때 한 종류의 복잡성을 다른 것으로 교환한다는 것입니다. 아마도 어딘가에 달콤한 장소가있을 것입니다.


"클린 코드"를 읽었습니까? 이것에 대해 자세히 설명합니다. amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
Martin Wickman

9

이상적으로는 스크롤하지 않아도 전체 기능을 볼 수 있어야합니다. 때로는 불가능합니다. 그러나 조각으로 나눌 수 있다면 코드를 훨씬 쉽게 읽을 수 있습니다.

Page Up / Down을 누르거나 코드의 다른 섹션으로 이동하자마자 이전 페이지의 7 +/- 2 가지만 기억할 수 있습니다. 불행히도 새 코드를 읽을 때 이러한 위치 중 일부가 사용됩니다.

저는 항상 컴퓨터 레지스터 (RISC가 아닌 CISC)와 같은 단기 기억에 대해 생각하고 싶습니다. 동일한 페이지에 전체 기능이있는 경우 프로그램의 다른 섹션에서 필요한 정보를 얻기 위해 캐시로 이동할 수 있습니다. 전체 기능이 페이지에 맞지 않으면 모든 작업 후 항상 메모리를 디스크에 넣는 것과 같습니다.


3
매트릭스 프린터로 인쇄하면됩니다. 10 미터 코드를 한 번에 모두 참조하십시오.)

또는 더 높은 해상도의 모니터를
구입하십시오

그리고 세로 방향으로 사용하십시오.
Calmarius

4

일반 외부 함수가 아닌 중첩 함수를 사용하는 이유는 무엇입니까?

외부 기능이 이전에 큰 기능 중 하나에서만 사용 되었더라도 여전히 전체 엉망을 쉽게 읽을 수 있습니다.

DoThing(int x){
    x += ;1
    int y = FirstThing(x);
    x = SecondThing(x, y);
    while(spoo > fleem){
        x = ThirdThing(x+y);
    }
}

FirstThing(int x){...}
SecondThing(int x, int y){...}
ThirdThing(int z){...}

2
가능한 두 가지 이유 : 네임 스페이스를 어지럽히고 내가 어휘 근접성이라고 부릅니다. 언어에 따라 좋은 이유나 나쁜 이유가있을 수 있습니다.
Frank Shearar

그러나 중첩 함수는 하향 funargs를 지원하고 어쩌면 완전히 닫힌 어휘 클로저를 지원해야하기 때문에 효율성이 떨어질 수 있습니다. 언어가 제대로 최적화되지 않으면 하위 기능에 전달할 동적 환경을 만들기 위해 추가 작업이 필요할 수 있습니다.
Kaz

3

나는 지금이 책을 가지고 있지 않다 (인용). Code Complete에 따르면 기능 길이에 대한 "sweetspot"은 그의 연구에 따르면 약 25-50 줄의 코드였다.

긴 기능을 수행해도 괜찮은 경우가 있습니다.

  • 함수의 순환 복잡성이 낮을 때. 동료 개발자가 거대한 if 문과 if 화면이 동시에 화면에 표시되지 않는 else 문이 포함 된 함수를 살펴보면 약간 실망 할 수 있습니다.

긴 기능을 갖는 것이 좋지 않은 시간 :

  • 깊이 중첩 된 조건을 가진 함수가 있습니다. 동료 코드 리더에게 호의를 베풀고 기능을 분해하여 가독성을 향상 시키십시오. 함수는 독자에게 "이것은 한 가지 역할을하는 코드 블록"이라는 표시를 제공합니다. 또한 함수의 길이가 너무 많은 일을하고 있고 다른 클래스에 포함시켜야 하는지를 스스로에게 물어보십시오.

결론은 유지 관리 성이 목록에서 가장 높은 우선 순위 중 하나 여야한다는 것입니다. 다른 개발자가 귀하의 코드를보고 5 초 이내에 코드가 수행하는 작업의 "요점"을 얻을 수없는 경우 ur 코드는 수행중인 작업을 알려주기에 충분한 "메타 데이터"를 제공하지 않습니다. 다른 개발자는 100 줄 이상의 코드를 읽는 대신 선택한 IDE에서 객체 브라우저를 보면서 클래스가 수행중인 작업을 알 수 있어야합니다.

작은 기능에는 다음과 같은 장점이 있습니다.

  • 이식성 : 기능을 다른 곳으로 리팩토링하는 클래스 내에서 훨씬 쉽게 이동할 수 있습니다.
  • 디버깅 : 스택 추적을 볼 때 100이 아닌 25 줄의 코드가있는 함수를 보면 오류를 정확하게 찾아내는 것이 훨씬 빠릅니다.
  • 가독성-함수의 이름은 전체 코드 블록이 수행하는 작업을 알려줍니다. 팀원이 작업하지 않으면 해당 블록을 읽고 싶지 않을 수 있습니다. 또한 대부분의 최신 IDE에서 다른 개발자는 객체 브라우저에서 함수 이름을 읽음으로써 클래스의 작업을 더 잘 이해할 수 있습니다.
  • 탐색-대부분의 IDE에서는 기능 이름을 검색 할 수 있습니다. 또한 대부분의 최신 IDE에는 다른 창에서 함수 소스를 볼 수있는 기능이 있으므로 다른 개발자는 긴 함수를 스크롤하지 않고 2 개의 화면 (멀티 모니터의 경우)에서 볼 수 있습니다.

목록은 계속됩니다 .....


2

대답은 그것이 달려 있지만 아마도 그것을 수업으로 바꿔야 할 것입니다.


당신이이 경우에 아마 :) OOPL에 기록하지하지 않는 한
프랭크 Shearar

dsimcha는 D와 Python을 사용한다고 언급했습니다.
frogstarr78

어휘 폐쇄와 같은 것을 들어 본 적이없는 사람들에게는 수업이 너무 자주 목발됩니다.
Kaz

2

나는 대부분의 중첩 함수를 좋아하지 않습니다. Lambdas는 해당 카테고리에 속하지만 일반적으로 30-40자를 초과하지 않는 한 나에게 플래그를 지정하지 않습니다.

기본적인 이유는, 내부 순환 론적으로 매우 국부적 밀도 함수가되도록 인 의미 나 주위에 내 머리를 포장하는 것이 어려운 것을, 그리고 코드 공간을 혼란하지 않는 도우미 함수에 물건을 밀어 그냥 쉽게 .

함수가해야 할 일이라고 생각합니다. 다른 일을하는 것은 다른 기능이하는 일입니다. 따라서 200 행 함수 Doing It Thing을하고 모든 것이 흐르면 ​​A-OK입니다.


때로는 외부 컨텍스트 (로컬 함수로 편리하게 액세스 할 수 있음)에 많은 컨텍스트를 전달해야 함수보다 함수가 호출되는 방식보다 더 복잡합니다.
Kaz

1

괜찮습니까? 그것은 오직 당신 만이 대답 할 수있는 질문입니다. 기능이 필요한 것을 달성합니까? 유지 관리가 가능합니까? 팀의 다른 구성원에게 '허용'됩니까? 그렇다면, 그것이 정말로 중요한 것입니다.

편집 : 중첩 함수에 대한 것을 보지 못했습니다. 개인적으로는 사용하지 않겠습니다. 대신 일반 기능을 사용합니다.


1

긴 "직선"기능은 특정 시퀀스에서 항상 발생하는 긴 시퀀스 시퀀스를 명확하게 지정하는 방법입니다.

그러나, 다른 사람들이 언급했듯이,이 형태는 전체 흐름이 덜 분명한 국부적 인 복잡성을 갖는 경향이있다. 로컬 복잡성을 중첩 된 함수 (예 : 긴 함수 내의 다른 곳에 정의되어 있거나 맨 위 또는 맨 아래에 정의)에 배치하면 기본 흐름에 대한 명확성을 복원 할 수 있습니다.

두 번째로 중요한 고려 사항은 긴 함수의 로컬 확장에서만 사용되도록 변수의 범위를 제어하는 ​​것입니다. 이러한 종류의 실수는 컴파일 또는 런타임 오류로 표시되지 않기 때문에 코드의 한 섹션에 도입 된 변수가 의도하지 않은 다른 위치 (예 : 편집주기 후)에 도입되지 않도록주의해야합니다.

일부 언어에서는이 문제를 쉽게 피할 수 있습니다. "{...}"과 같이 로컬로 확장 된 코드를 자체 블록에 싸서 새로 도입 된 변수를 해당 블록에서만 볼 수 있습니다. Python과 같은 일부 언어에는이 기능이 부족하므로 로컬 함수는 더 작은 범위의 영역을 적용하는 데 유용 할 수 있습니다.


1

다중 페이지 기능은 바람직하지 않으며 코드 검토를 통과해서는 안됩니다. 나는 긴 함수도 작성했지만 Martin Fowler의 Refactoring 을 읽은 후에 중단되었습니다. 긴 기능은 올바르게 작성하기 어렵고 이해하기 어렵고 테스트하기가 어렵습니다. 나는 50 줄의 기능조차 보지 못했습니다.이 기능은 더 작은 기능으로 나뉘어져 있으면 더 쉽게 이해하고 테스트 할 수 없습니다. 다중 페이지 함수에는 반드시 고려해야 할 전체 클래스가 거의 있습니다. 좀 더 구체적으로는 어렵습니다. 어쩌면 긴 기능 중 하나를 Code Review에 게시해야 하고 누군가 (아마도) 개선 방법을 보여줄 수 있습니다.


0

파이썬으로 프로그래밍 할 때 함수를 작성한 후 뒤로 물러서서 "파이썬 해석기에서 '가져 오기'를 입력하십시오."

못생긴 것보다 아름답습니다.
암시적인 것보다 명시적인 것이 좋습니다.
단순함이 복잡한 것보다 낫습니다.
복잡한 것이 복잡한 것보다 낫습니다.
평평한 것이 중첩보다 낫습니다.
스파 스가 밀도보다 낫습니다.
가독성이 중요합니다.
특별한 경우는 규칙을 어길만큼 특별하지 않습니다.
실용성은 순도를 능가하지만.
오류가 자동으로 전달되지 않아야합니다.
명시 적으로 침묵하지 않는 한.
모호함에 직면하여 추측하려는 유혹을 거부하십시오.
그것을하는 명백한 방법이 있어야합니다.
비록 당신이 네덜란드 인이 아니라면 처음에는 그 방법이 분명하지 않을 수도 있습니다.
지금보다 결코 낫습니다. 지금.
결코 결코 옳은 것보다 낫지는 않지만
구현이 설명하기 어렵다면 나쁜 생각입니다.
구현이 설명하기 쉬운 경우 좋은 생각 일 수 있습니다.
네임 스페이스는 훌륭한 아이디어 중 하나입니다. 더 많은 것을 해보자!


1
명시 적이 암시 적보다 낫다면 기계 언어로 코딩해야합니다. 어셈블러에서도 마찬가지입니다. 명령으로 분기 지연 슬롯을 자동으로 채우고 상대 분기 오프셋을 계산하며 전역 간의 기호 참조를 해결하는 등의 암시적인 작업을 수행합니다. 사람,이 멍청한 파이썬 사용자와 그들의 작은 종교 ...
Kaz

0

별도의 모듈에 넣으십시오.

너무 많은 옵션이 필요하지 않은 것보다 솔루션이 부풀어 오르지 않는다고 가정하십시오. 이미 다른 하위 기능으로 기능을 분할 했으므로 질문은 어디에 두어야합니까?

  1. "공개"기능이 하나만있는 모듈에 넣으십시오.
  2. "공개"(정적) 함수가 하나만있는 클래스에 배치하십시오.
  3. 함수를 설명에 따라 중첩시킵니다.

이제 두 번째와 세 번째 대안은 모두 중첩 적이지만 일부 프로그래머는 두 번째 대안을 나쁘지 않은 것으로 보입니다. 두 번째 대안을 배제하지 않으면 세 번째 대안을 배제 할 이유가 너무 많지 않습니다.

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