수업에 얼마나 큰가요?


29

나는 오랜 개발자 (나는 49입니다)이지만 객체 지향 개발에 익숙하지 않습니다. Bertrand Meyer 's Eiffel 이후 OO에 대해 읽었지만 OO 프로그래밍은 거의하지 않았습니다.

요점은 OO 디자인에 대한 모든 책은 보트, 자동차 또는 우리가 자주 사용하는 일반적인 객체의 예로 시작하며 속성과 메소드를 추가하고 객체의 상태를 모델링하는 방법과 수행 할 수있는 것을 설명하기 시작합니다 그것.

따라서 일반적으로 "모델이 좋을수록 응용 프로그램의 객체를 더 잘 표현하고 더 잘 나옵니다"와 같은 방식으로 진행됩니다.

지금까지는 좋지만 다른 한편으로,“클래스는 한 페이지에 맞아야합니다”와 같은 레시피를 제공하는 여러 저자를 발견했습니다 (이제“어떤 모니터 크기에 추가 하시겠습니까?”). 코드를 인쇄하십시오!).

예를 들어 PurchaseOrder유한 상태 머신이 동작을 제어 하는 클래스와의 컬렉션 을 예로 들어 보겠습니다. PurchaseOrderItem여기서 논란 중 하나는 PurchaseOrder일부 메소드 (데이터 클래스가 아닌)와 함께 간단한 클래스를 사용해야한다는 것입니다. PurchaseOrderFSM"전문가 클래스"를 위해 그 핸들 유한 상태 기계를 PurchaseOrder.

나는 그것이 코딩 호러에 관한 Jeff Atwood의 Code Smells 포스트 의 "Feature Envy"또는 "Inappropriate Intimacy"분류에 해당한다고 말하고 싶습니다 . 그냥 상식이라고 부릅니다. 실제 구매 주문을 발행, 승인 또는 취소 할 수있는 경우 PurchaseOrder클래스 issuePOapprovePOcancelPO메소드 가 있어야 합니다.

OO의 초석으로 이해하는 "통합 최대화"및 "커플 링 최소화"시대의 오래된 원칙과 함께 사용되지 않습니까?

게다가, 그것은 클래스의 유지 보수에 도움이되지 않습니까?


17
typename을 메소드 이름으로 인코딩 할 이유가 없습니다. 당신이있는 경우 즉 PurchaseOrder, 당신은 당신의 방법을 이름을 수 issue, approvecancel. PO접미사은 음의 값을 추가한다.
dash-tom-bang

2
블랙홀 방법 에서 멀리 떨어져 있으면 괜찮습니다. :)
Mark C

1
현재 화면 해상도에서는 145 자라고 말합니다.
DavRob60

의견을 보내 주셔서 감사합니다.이 문제를 해결하는 데 정말 도움이되었습니다. 이 사이트가 허용된다면 TMN과 나사로의 대답도 선택했지만 하나만 허용하므로 Craig로갔습니다. 친애하는.
Miguel Veloso

답변:


27

수업은 단일 책임 원칙을 사용해야합니다. 내가 본 대부분의 매우 큰 수업은 많은 것들을하기 때문에 너무 큰 것입니다. 각 메소드를보고 코드가이 클래스에 있는지 아니면 별도의 중복 코드가 힌트인지 결정하십시오. 당신은 issuePO 방법을 가지고 있지만 예를 들어 10 줄의 데이터 액세스 코드를 포함합니까? 그 코드는 아마도 없을 것입니다.


1
크레이그, 저는 단일 책임 원칙을 알지 못했고 그것에 대해 읽었습니다. 내 생각에 가장 먼저 온 것은 책임의 범위는 무엇입니까? PO의 경우 상태를 관리하는 것이므로 이것이 IssuePO, approvePO 및 cancelPO 메소드의 이유이지만 PO 항목의 상태를 처리하는 PurchaseOrderItem 클래스와의 상호 작용도 포함합니다. 따라서이 접근법이 SRP와 일치하는지 확실하지 않습니다. 뭐라고 하시겠습니까?
Miguel Veloso

1
아주 좋고 간결한 답변을 얻으려면 +1하십시오. 현실적으로, 클래스의 규모에 대한 결정적인 척도는 없습니다. 이 같은 클래스는 큰 인 SRP의 보장하지만 적용 이 필요 로합니다.
S.Robins

1
@MiguelVeloso-PO를 승인하면 PO를 발행하는 것과 다른 논리 및 규칙이 연관 될 수 있습니다. 그렇다면 책임을 POApprover와 POIssuer로 분리하는 것이 좋습니다. 아이디어는 규칙이 하나 바뀌면 왜 다른 규칙이 포함 된 클래스를 망쳐 버리고 싶은가입니다.
Matthew Flynn

12

내 생각에 클래스 크기는 변수, 함수 및 메소드가 해당 클래스와 관련이있는 한 중요하지 않습니다.


1
반면에 큰 크기는 해당 메소드가 해당 클래스와 관련이 없음을 나타냅니다.
Billy ONeal

5
@ 빌리 : 큰 클래스는 코드 냄새라고 말하지만 자동으로 나쁘지는 않습니다.
David Thornley

@David : 저기에 "아마도"라는 단어가있는 이유가 중요합니다 :)
Billy ONeal

나는 동의하지 않을 것이다. 나는 꽤 일관된 명명 규칙을 가진 프로젝트에서 일하고 일들이 잘 정리되어 있지만 ... 여전히 50k 줄의 클래스가 있습니다. 너무 큽니다 :)
Jay

2
이 답변은 "지옥으로가는 길"이 어떻게 진행되는지를 보여줍니다. 만약 클래스의 책임을 제한하지 않으면, 많은 변수, 함수 및 메소드가 클래스와 관련이 있게 될 것입니다. 그리고 이것은 너무 많은 것을 갖도록합니다.
Doc Brown

7

큰 클래스의 가장 큰 문제는 해당 클래스를 테스트하거나 다른 클래스와의 상호 작용에 관한 것입니다. 큰 학급 규모 자체는 문제가되지 않지만 모든 냄새와 마찬가지로 잠재적 인 문제를 나타냅니다 . 일반적으로 클래스가 클 때 클래스가 단일 클래스 이상의 작업을 수행하고 있음을 나타냅니다.

자동차 비유의 경우 클래스 car가 너무 크면 클래스 engine, 클래스 door및 클래스 windshield등 으로 나뉘어 야 함을 나타냅니다 .


8
또한 차량 인터페이스를 구현해야합니다. :-)
Chris

7

클래스의 특정 정의가 너무 크다고 생각하지 않습니다. 그러나 다음 지침을 사용하여 수업을 리팩터링해야하는지 또는 수업 범위를 재정의해야하는지 결정합니다.

  1. 서로 독립적 인 많은 변수가 있습니까? (대부분의 경우 내 개인적인 관용은 약 10 ~ 20입니다)
  2. 코너 케이스를 위해 설계된 많은 방법이 있습니까? (내 개인적인 관용은 ... 글쎄, 그것은 내 생각에 따라 크게 달라집니다)

1과 관련하여 앞 유리 크기, 휠 크기, 테일 라이트 전구 모델 및 클래스에서 100 개의 기타 세부 사항을 정의한다고 가정하십시오 car. 그것들은 모두 차와 "관련"되지만, 그러한 클래스의 행동을 추적하는 것은 매우 어렵다 car. 그리고 언젠가 동료가 실수로 (또는 경우에 따라 의도적으로) 테일 라이트 전구 모델을 기준으로 윈드 쉴드 크기를 변경하면, 윈드 쉴드가 더 이상 자동차에 맞지 않는 이유를 영원히 알 수 있습니다.

2와 관련하여 클래스에서 자동차가 가질 수있는 모든 동작을 정의하려고 car하지만 car::open_roof()컨버터블에만 사용할 수 있으며 car::open_rear_door()해당 2 도어 자동차에는 적용되지 않는다고 가정하십시오. 컨버터블과 2 도어 차량은 정의상 "자동차"이지만 클래스에 구현하면 클래스가 car복잡해집니다. 수업이 더 어려워지고 유지 관리가 어려워집니다.

이 두 가지 지침 외에 클래스 범위에 대한 명확한 정의를 제안합니다. 범위를 정의한 후에는 정의에 따라 엄격하게 클래스를 구현하십시오. 대부분의 경우, 사람들은 범위의 정의가 잘못되었거나 클래스에 추가 된 임의의 기능 때문에 "너무 큰"클래스를받습니다.


7

300 줄로 필요한 것을 말하십시오

참고 :이 경험 법칙은 당신이 그 자체로 좋은 유지 관리 아이디어라는 '파일 당 하나의 클래스'접근법을 따르고 있다고 가정합니다.

절대 규칙은 아니지만 한 클래스에서 200 줄 이상의 코드를 보면 의심됩니다. 300 줄과 경고음이 울립니다. 다른 사람의 코드를 열고 2000 줄을 찾으면 첫 페이지를 읽지 않고도 시간을 리팩토링한다는 것을 알고 있습니다.

대부분 이것은 유지 보수성에 달려 있습니다. 당신이 반대하는 것이 너무 복잡해서 300 행으로 행동을 표현할 수 없다면, 다른 사람이 이해하기가 매우 어려울 것입니다.

UI 페이지에 대해 '행동 객체'를 생성하는 Model-> ViewModel-> View 세계 에서이 규칙을 구부리고 있음을 발견했습니다. 페이지. 그러나 나는 여전히이 프로그래밍 모델을 처음 사용하고 있으며 페이지 / 뷰 모델 사이의 동작을 리팩토링 / 재사용하는 좋은 방법을 찾아 내 ViewModel의 크기를 점차 줄입니다.


저의 개인 지침도 약 300 줄입니다. +1
Marcie

나는 OP가 휴리스틱을 찾고 있다고 생각하며 이것은 좋은 것입니다.
neontapir

감사합니다. 정확한 숫자를 지침으로 사용하는 것이 좋습니다.
윌 셰퍼드

6

거꾸로 살펴 보자.

OO의 초석으로 이해하는 "통합 최대화"및 "커플 링 최소화"시대의 오래된 원칙과 함께 사용되지 않습니까?

실제로 이것은 프로그래밍의 초석이며 OO는 하나의 패러다임입니다.

앙투안 드 생 텍쥐페리 (Antoine de Saint-Exupéry)가 귀하의 질문에 답변 하도록하겠습니다 .

더 이상 추가 할 것이 아니라 빼앗을 것이 없을 때 완벽이 이루어집니다.

간단한 클래스, 당신이 바로, 쉽게 그것을 할 수 있습니다 것 수 있습니다 더 많은 자신감을 완벽하게 테스트합니다.


3

Feature Envy 분류에서 OP를 사용하고 있습니다. 다른 클래스의 내부에서 작동하는 메소드가 많은 클래스를 갖는 것보다 더 짜증나는 것은 없습니다. OO는 데이터와 해당 데이터에 대한 작업을 모델링 할 것을 제안합니다. 그렇다고 데이터와 다른 위치에 작업을 넣었다는 의미는 아닙니다! 데이터와 그 메소드를 함께 모 으려고 합니다 .

carperson모델 널리 그래서, 그것은으로, 전기 연결을, 또는 스타터를 회전에 대한 코드를 넣어 같은 것 person클래스입니다. 나는 이것이 숙련 된 프로그래머에게 분명히 잘못 되기를 바랍니다 .

이상적인 클래스 또는 메서드 크기는 없지만 한 화면에서 메서드와 함수를 모두 유지하여 전체를 한 곳에서 볼 수 있도록하는 것을 선호합니다. Vim이 60 라인 창을 열도록 구성했습니다.이 페이지는 인쇄 된 페이지의 줄 수 바로 근처에 나타납니다. 클래스 정의에 대해 동일한 지침을 따르고 파일을 몇 개의 "페이지"아래로 유지하려고합니다. 300, 400 개가 넘는 줄은 다루기 어려워지기 시작합니다 (주로 수업이 너무 많은 직접적인 책임을 맡기 시작했기 때문에).


+1-좋은 경험 법칙이지만 권위적이지는 않습니다. 그러나 클래스가 깨 졌다고해서 다른 클래스가 서로의 개인 구성원과 접촉해야한다는 의미는 아닙니다.
Billy ONeal

다른 학급이 서로의 사적인 부분에 닿아 야한다고 생각하지 않습니다. '친구'액세스는 무언가를 준비하고 실행하는 데 편리하지만 더 나은 디자인을위한 디딤돌입니다. 다른 클래스의 내부에 따라 다른 Code Smell 이기 때문에 일반적으로 접근 자를 피하십시오 .
dash-tom-bang

1

클래스 정의에 수백 개의 메소드가 있으면 너무 큽니다.


1

나는 수업 에 대한 단일 책임 원칙 의 사용에 전적으로 동의 하지만 그에 따라 큰 수업을 듣는다면 그렇게해야합니다. 개별적인 방법과 속성이 너무 크지 않다는 점에 중점을 두어야하며, 순환적인 복잡성에 따라 가이드 라인을 따라야하며, 그에 따라 전체 클래스 크기를 증가시킬 수 있지만 세분화 된 수준으로 읽고 테스트 할 수있는 많은 개인용 메서드가 생성 될 수 있습니다. 코드를 읽을 수 있으면 크기는 관련이 없습니다.


1

구매 오더 발행은 종종 구매 오더 이상의 복잡한 프로세스입니다. 이 경우 비즈니스 로직을 별도의 클래스로 유지하고 구매 주문을 더 간단하게 만드는 것이 아마도 옳은 일입니다. 그러나 일반적으로 그렇습니다. "데이터 구조"클래스는 원하지 않습니다. 예를 들어, "POManager"비즈니스 클래스의 issue()메소드는 아마도 PO의 issue()메소드를 호출해야합니다 . 그런 다음 PO는 상태를 "발급"으로 설정하고 발행일을 기록 할 수있는 반면 POManager는 지불 가능한 계정에 통지를 보내서 송장을 기대할 수있게하고 재고에 다른 통지를 보내서 예상 날짜

메서드 / 클래스 크기에 대해 "규칙"을 적용한 사람은 실제 세계에서 충분한 시간을 소비하지 않은 것 같습니다. 다른 사람들이 언급했듯이, 그것은 종종 리팩토링 지표이지만 때로는 (특히 "데이터 처리"유형 작업에서) 500 개 이상의 라인에 걸친 단일 메소드로 클래스를 작성해야합니다. 그것에 매달리지 마십시오.


POManager가 "제어 자"이고 PurchaseOrder가 MVC 패턴에서 "모델"이 될 것 같습니다.
Miguel Veloso

0

“한 페이지에 맞는 수업이어야합니다”와 같은 레시피를 제공하는 여러 저자를 발견했습니다.

클래스의 실제 크기 측면에서 큰 클래스를 보는 것이 코드 냄새를 나타내는 것이지만 반드시 냄새가 항상 있다는 것을 의미하지는 않습니다. 캐리비안의 해적에있는 해적들이 말한 것처럼, 이것이 실제 규칙보다 "지침"이라고 부르는 것입니다. 나는 "클래스에서 100 LOC 이하"를 한 번 엄격히 따르려고 노력했고 결과는 불필요한 과도한 엔지니어링이었습니다.

따라서 일반적으로 "모델이 좋을수록 응용 프로그램의 객체를 더 잘 표현하고 더 잘 나옵니다"와 같은 방식으로 진행됩니다.

나는 보통 이것으로 디자인을 시작한다. 이 수업은 실제 세계에서 무엇을합니까? 요구 사항에 명시된대로이 수업을 어떻게 반영해야합니까? 여기에 약간의 상태를 추가하고, 필드, 해당 필드에서 작업하는 방법, 몇 가지를 추가하십시오. 우리는 노동 계급을 가지고 있습니다. 이제 적절한 구현으로 서명을 작성하면 좋을 것입니다. 이제 필요한 모든 기능을 갖춘 멋진 클래스가 있습니다. 그러나 이것의 문제점은 실제 세계가 작동하는 방식을 고려하지 않는다는 것입니다. 그리고 그것은 "CHANGE"를 고려하지 않는다는 것을 의미합니다.

클래스가 더 작은 부분으로 분할되는 이유는 기존 논리에 영향을 미치거나 새로운 버그 또는 두 가지를 의도하지 않게 도입하지 않고 모든 클래스를 재사용하기가 어렵 기 때문에 나중에 큰 클래스를 변경하기가 어렵 기 때문입니다. 리팩토링, 디자인 패턴, SOLID 등이 사용되며 최종 결과는 일반적으로 더 작고 더 세분화 된 다른 하위 클래스에서 작업하는 소규모 클래스입니다.

또한 귀하의 예에서 IssuePO, ApprovePO 및 Cancel PO를 PurchaseOrder 클래스에 추가하는 것은 비논리적 인 것 같습니다. 구매 주문은 발행, 승인 또는 취소되지 않습니다. PO가 메소드를 가져야한다면, 메소드는 클래스 전체가 아닌 상태에서 작동해야합니다. 그들은 실제로 다른 클래스가 작업하는 데이터 / 레코드 클래스입니다.


0

작업을 수행하는 데 필요한 모든 논리를 포함 할 수있을만큼 큽니다.

유지 보수가 가능하고 단일 책임 원칙을 준수하기에 충분히 작습니다 .

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