민첩한 개발의 필수 기교: 코드를 간결하게 유지

16903 단어 AgileSoftwareD
단일 직책 원칙(The Single Responsibility Principle)은 모든 종류는 하나의 이유만을 위해 수정되어야 한다고 생각한다.하나의 종류가 많은 다른 기능을 포함할 때, 단일 직책 원칙을 위반한다.저자는 간단한 예를 통해 어떻게 당신의 코드를 더욱 간결하게 하는지 보여 주었다.

민첩한 개발의 필수 기교: 코드를 간결하게 유지

Wingel은 2006-12-28 13:41:50에 발표
저자: Wingel 출처: www.matrix.org.cn

요약:

단일 직책 원칙(The Single Responsibility Principle)은 모든 종류는 한 가지 이유만을 위해 수정해야 한다고 주장했다.하나의 종류가 많은 다른 기능을 포함할 때, 단일 직책 원칙을 위반한다.저자는 간단한 예를 통해 어떻게 당신의 코드를 더욱 간결하게 하는지 보여 주었다.
 
예제
이것은 회의 관리 시스템이다.그것은 모든 참석자의 정보를 관리하는 데 쓰인다.처음에 우리는 모든 참석자의 ID(이것은 회의 조직자가 분배한 것), 이름, 전화와 주소만 기록하면 된다.그래서 우리는 다음과 같은 코드를 썼다.
    
    class Participant {                                                                            
       String id;                                                                                  
       String name;                                                                                
       String telNo;                                                                              
       String address;                                                                            
    }    
    
    class ConferenceSystem {                                                                      
       Participant participants[];                                                                
    }      
                                                                                      
이어 새로운 수요가 생겼다. 현재 모든 참석자들은 주최자에게 호텔 예약을 도와줄 수 있기 때문에 우리는 그가 예약하고 싶은 호텔 이름, 입주 날짜, 떠나는 날짜, 방 유형(1인실 또는 2인실)을 기록해야 한다.그래서 우리는 다음과 같은 코드로 확장했다.
    class Participant {                                                                            
       String id;                                                                                  
       String name;                                                                                
       String telNo;                                                                              
       String address;                                                                            
       boolean bookHotelForHim;                                                                    
       String hotelName;                                                                          
       Date checkInDate;                                                                          
       Date checkOutDate;                                                                          
       boolean isSingleRoom;                                                                      
       void setHotelBooking(String hotelName, Date checkInDate, ...) {                            
           ...                                                                                    
       }                                                                                          
    }
                                                                                              

이어서 또 하나의 새로운 수요가 생겼다. 참가자들은 서로 다른 세미나에 참가할 수 있기 때문에 우리는 참가자들이 참가한 세미나를 기록해야 한다.그가 참가하고자 하는 모든 세미나에 대해 우리는 그의 등록 시간을 기록해야 하며, 동시에 그는 어떤 번역 설비를 필요로 하는지 기록해야 한다.그래서 코드는 다음과 같이 확장되었다.
    
class Participant {                                                                            
       String id;
       String name;
       String telNo;
       String address;
       boolean bookHotelForHim;
       String hotelName;
       Date checkInDate;
       Date checkOutDate;
       boolean isSingleRoom;
       String idOfSeminarsRegistered[];
       Date seminarRegistrationDates[];
       boolean needSIDeviceForEachSeminar[];
       void setHotelBooking(String hotelName, Date checkInDate, ...) {
           ...
       }    
       void registerForSeminar(String seminarId, Date regDate, boolean needSIDevice) {
           // seminarId idOfSeminarsRegistered
           // regDate seminarRegistrationDates
           // needSIDevice needSIDeviceForEachSeminar.
       }    
       boolean isRegisteredForSeminar(String seminarId) {
           ...
       }    
       Date getSeminarRegistrationDate(String seminarId) {
           ...
       }    
       boolean needSIDeviceForSeminar(String seminarId) {
           ...
       }    
       String [] getAllSeminarsRegistered() {
           return idOfSeminarsRegistered;
       }    
    }
      
코드가 부어오르기 시작했다
이것은 이미 우리가 두 번째로 Participant류를 확충한 것이니 주의하십시오.매번 확장할 때마다, 그것은 더 많은 코드 (실례 변수와 방법) 와 더 많은 기능을 포함한다.원래 그것은 네 개의 속성만 있다.지금 12개야!이 밖에 이런 종류의 처리해야 할 업무 논리도 크게 증가했다.원래는 참석자의 기본 정보(성명, 주소 등)만 처리할 수 있었는데, 지금은 호텔, 호텔 예약, 세미나와 번역 설비 등의 논리도 포함하고 있다.만약에 이후에 새로운 수요가 또 온다면 우리는Participant이라는 종류를 확충해야 한다. 그때는 이런 종류가 복잡하고 거대해져야 한다.
그래서 우리 이런 거 고쳐야 돼!
그럼 Participant 이런 거 어떻게 고쳐요?어떻게 그것으로 하여금 첫날의 그런 간결도를 계속 유지하게 합니까?이 두 문제에 대답하기 전에, 우리는 먼저 다른 우선적으로 대답해야 할 문제를 생각해 보자. 너에게 종류를 하나 줄게. 너는 어떻게 그것이 수정되어야 한다고 생각하니?
어떤 종류를 판단하려면 수정이 필요하다
한 종류가 수정되어야 하는지 아닌지를 판단하려면 비교적 주관적인 방법은 한 종류의 코드를 읽을 때 우리가 이 종류가'너무 길다','너무 복잡하다', 또는'너무 많다'는 개념을 말하는지 보는 것이다.만약 이렇게 느낀다면, 우리는 이런 종류는 수정이 필요하다고 확신할 것이다.
또 다른 비교적 간단하고 객관적인 방법은 우리가 이미 두 번째 또는 세 번째로 이 종류를 확충한 것을 발견했을 때 우리는 이 종류를 수정해야 한다고 인정한다.이것은 비교적 게으르고 수동적인 방법이지만 매우 효과가 있다.
이제 Participant 종류를 어떻게 고치는지 봅시다.
호텔 예약에 관한 기능을 추출하다
우선 호텔 예약 기능을 어떻게 빼내는지 생각해 보자.실행 가능한 시나리오는 다음과 같습니다.
    
class Participant {                                                                            
       String id;                                                                                  
       String name;                                                                                
       String telNo;                                                                              
       String address;                                                                            
    }      
    
    class HotelBooking {                                                                          
       String participantId;                                                                      
       String hotelName;                                                                          
       Date checkInDate;                                                                          
       Date checkOutDate;                                                                          
       boolean isSingleRoom;                                                                      
    }    
    
    class HotelBookings {                                                                          
       HotelBooking hotelBookings[];                                                              
       void addBooking(HotelBooking booking) {                                                    
           ...                                                                                    
       }                                                                                          
    }        
    
    class ConferenceSystem {                                                                      
       Participant participants[];                                                                
       HotelBookings hotelBookings;                                                                
    }
                                                                                            
현재Participant류는 호텔 예약의 존재를 전혀 모른다.물론 우리는 반드시 호텔 예약 상황을 수조로 저장해야 하는 것은 아니다.예를 들어 우리는 맵을 사용할 수 있다.
   class Participant {                                                                            
       String id;                                                                                  
       String name;                                                                                
       String telNo;                                                                              
       String address;                                                                            
    }                                                                                              

    class HotelBooking {
       String participantId;
       String hotelName;
       Date checkInDate;
       Date checkOutDate;
       boolean isSingleRoom;
    }    
    
    class HotelBookings {
       HashMap mapFromPartIdToHotelBooking;
       // id
       void addBooking(String participantId, HotelBooking booking) {
           ...
       }    
    }      

    class ConferenceSystem {
       Participant participants[];
       HotelBookings hotelBookings;
    }
      
이런 방안의 장점은 Participant가 호텔북킹의 존재를 전혀 모르고 Participant가 호텔북킹에 의존하지 않는다는 것이다.
또 다른 실행 가능한 방안은 다음과 같다.
    class Participant {
       String id;
       String name;
       String telNo;
       String address;
       HotelBooking hotelBooking;
    }      
    
    class HotelBooking {
       String hotelName;
       Date checkInDate;
       Date checkOutDate;
       boolean isSingleRoom;
    }    
    
    class ConferenceSystem {
       Participant participants[];
    }    
  
이런 방안에서 Participant류는 호텔북킹의 존재를 알아야 한다. 즉, Participant는 호텔이 예약되어 있다는 것을 알아야 한다.다만 구체적인 호텔 예약은 어떻게 하는 것인지, 이런 진정한 기능은 호텔 북킹에 담겨 이루어진다.각 Participant은 본인의 호텔 예약 상황을 직접 인용했기 때문에 그의 호텔 예약 상황을 직접 찾을 수 있다.그 대가로 Pariticipant는 호텔 예약의 개념을 알아야 한다.클래스의 관계에서 볼 때 Pariticipant는 호텔북킹이라는 클래스에 의존해야 한다.
물론 상기 몇 가지 상황을 제외하고는 많은 다른 실행 가능한 방안이 있다.
추출 워크숍 관련 기능
이제 워크숍의 기능을 어떻게 추출할지 생각해 봅시다.하나의 실행 가능한 시나리오:
    class Participant {                                                                            
       String id;                                                                                  
       String name;                                                                                
       String telNo;                                                                              
       String address;                                                                            
    }  
    
    class SeminarRegistration {                                                                    
       String participantId;                                                                      
       String seminarId;                                                                          
       Date registrationDate;                                                                      
       boolean needSIDevice;                                                                      
    }  
    
    class SeminarRegistry {                                                                        
       SeminarRegistration registrations[];                                                        
       void registerForSeminar(SeminarRegistration registration) {                                
           // registration registrations.                                                    
       }                                                                                          
       boolean isRegisteredForSeminar(String participantId, String seminarId) {                    
           ...                                                                                    
       }                                                                                          
       Date getSeminarRegistrationDate(String participantId, String seminarId) {                  
           ...                                                                                    
       }                                                                                          
       boolean needSIDeviceForSeminar(String participantId, String seminarId) {                    
           ...                                                                                    
       }                                                                                          
       SeminarRegistration[] getAllRegistrations(String participantId) {                          
           ...                                                                                    
       }                                                                                          
    }  
    
    class ConferenceSystem {                                                                      
       Participant participants[];                                                                
       SeminarRegistry seminarRegistry;                                                            
    }
                                                                                              
물론 상기 방안 이외에 또 다른 실행 가능한 방안이 있으니, 여기서는 우선 말하지 않겠다.
개선된 코드
다음은 개선된 코드입니다.
    class Participant {                                                                            
       String id;                                                                                  
       String name;                                                                                
       String telNo;                                                                              
       String address;                                                                            
    }  
    
    class HotelBooking {
       String participantId;                                                                      
       String hotelName;                                                                          
       Date checkInDate;                                                                          
       Date checkOutDate;                                                                          
       boolean isSingleRoom;                                                                      
    }      
    
    class HotelBookings {
       HotelBooking hotelBookings[];                
       void addBooking(HotelBooking booking) {      
           ...                                      
       }                                            
    }    
    
    class SeminarRegistration {                    
       String participantId;                        
       String seminarId;                            
       Date registrationDate;                        
       boolean needSIDevice;                        
    }      
    
    class SeminarRegistry {                        
       SeminarRegistration registrations[];          
       void registerForSeminar(SeminarRegistration registration) {
           // registration registrations.      
       }                                            
       boolean isRegistered (String participantId, String seminarId) {
           ...                                      
       }                                            
       Date getRegistrationDate(String participantId, String seminarId) {
           ...                                      
       }                                            
       boolean needSIDevice(String participantId, String seminarId) {
           ...                                      
       }                                            
       SeminarRegistration[] getAllRegistrations(String participantId) {
           ...                                      
       }                                            
    }    
    
    class ConferenceSystem {                        
       Participant participants[];                  
       HotelBookings hotelBookings;                  
       SeminarRegistry seminarRegistry;              
    }
                                              
인용하여 서술하다
단일 직책 원칙(The Single Responsibility Principle)은 모든 종류는 하나의 이유만을 위해 수정되어야 한다고 생각한다.하나의 종류가 많은 다른 기능을 포함할 때, 단일 직책 원칙을 분명히 위반한다.자세한 내용은 다음을 참조하십시오.
http://www.objectmentor.com/resources/articles/srp.
http://c2.com/cgi/wiki?OneResponsibilityRule
시리즈 PDF 다운로드:
민첩한 개발에 필요한 기교

좋은 웹페이지 즐겨찾기