아무도 건빵을 좋아하지 않는다

15258 단어 codequality
나의 또 다른 원한에 의한 살인 문장에 오신 것을 환영합니다.지난번에는 튼튼한 디자인 원칙이 구렁이 모양이라는 것을 증명했다.이번에는 내 목표가 가장 남용되는 깨끗한 코드 원칙이다. 너 자신을 되풀이하지 마라. 아니면 보통 줄임말처럼 마르지 마라.이것은 매우 간단한 원칙이다.네가 해야 할 일은 너 자신을 되풀이하지 않는 것이다. 즉, 같은 코드를 두 번 쓰지 말라는 것이다.그것은 심지어 사람을 끌어당기는 단어도 있다. 예를 들어, "너는 이 코드를 말릴 수 있니?"또는 "이 코드는 말릴 수 있다."는 것은 내가 코드 심사에서 자주 본 것이다.나는 건조의 원칙에 반대하지 않는다.나는 그것이 깨끗한 코드의 핑계로 쓰이는 것에 동의하지 않는다. 마치 중복 코드가 없는 것처럼 코드도 깨끗하다.이것이 바로 내가 마른 과자를 좋아하는 사람이 없다고 말하는 이유다.다시 한 번 말하지만, 건빵을 좋아하는 사람은 아무도 없다.나는 케이크 대표가 영원히 멈춰서 너 자신을 되풀이해야 하기 때문에 내 말을 되풀이하지 않을 수 없다.

역사.


건조 원리의 기원부터 시작하자.앤드루 헌트(Andrew Hunt)와 데이비드 토머스(David Thomas)가 1999년 출간한 실용 프로그래머에서 나왔다.본고에서 건조 원리의 정의는 다음과 같다.

"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system."


풍자적인 것은 여러 해 동안 건조한 원리가 줄곧 많은 기술 문장의 주제가 되었다는 것이다.모든 것이 실용주의 프로그래머의 정의와 호응한 다음에 코드 세션을 통해 이 정의의 의미를 계속 설명한다.그래서 우리는 하나의 원칙을 중복했다. 그것은 바로 너 자신을 중복하지 말라는 것이다!대부분의 개발자들이 현재 실용주의 프로그래머로부터 권위적인 정의를 읽지 않고 DRY에 대한 다른 사람의 해석을 읽기 때문에 DRY에 대한 이해는 이미 파괴되었다.DRY 원칙은 중복된 코드가 나쁜 것임을 의미하는 것으로 간소화되었다. 중복된 코드를 쓰지 마라. 그렇지 않으면 너는 나쁜 것이다. 이 DRY 원칙의 유행 그림과 같다...중복은 모든 소프트웨어 죄악의 근원이다.

이것은 내가 사용하는 건조도를 경멸하기 때문이다.중복 코드는 결코 나쁘지 않다. 나는 이 점을 증명할 수 있다.

왜 반복 코드가 좋은가


나는 코드를 반복하는 것이 왜 좋은 일인지 설명하는 데 베이킹을 즐겨 한다.초콜릿 과자를 예로 들다.너는 계란, 버터, 기름 같은 젖은 식재료가 필요하다.그것들은 화학반응이 발생하는 필수 조건으로 과자를 부드럽고 씹을 수 있으며 맛있게 만든다.너는 계란, 버터, 기름을 쓰지 않고 과자를 만들어 본 적이 있니?그것들은 그다지 좋지 않다.수분은 좋은 일일 뿐만 아니라 고품질의 과자에도 매우 중요하다.코드도 마찬가지다. cookies가 개발할 때 건조해지듯이 우리의 코드도 개발할 때 건조해져야 한다.당신이 코드를 여러 번 작성하고 자신을 반복할 때, 당신은 당신의 습성분을 소개하고, 코드가 작용할 때, 당신은 재구성으로 돌아간다.재구성 과정에서 코드의 실제 용례를 볼 수 있고, 무미건조한 추상을 만들 수 있으며, 추상에서 시작할 때 예측할 수 없는 문제를 피할 수 있다.마른 과자로 끝나는 것을 피하는 데 도움을 줄 수 있는 실용적인 팁이 있다.
  • 다시 사용하지 않는 코드
  • 너무 이르는 추상은 모든 취약 소프트웨어의 근원
  • 잘못된 추상보다 복제가 저렴
  • 코드는 다시 사용할 수 없습니다.추상은 일종의 추상이다.
  • 코드를 다시 쓰는 대신 당신의 용례를 사용합니다


    대학 졸업 후 첫 직장에서 함께 일했던 고급 개발자의 말이다.그는 항상 나에게 "코드는 너의 용례를 겨냥한 것이지, 너의 중용례를 겨냥한 것이 아니다."라고 말했다.나는 이것이 무엇을 의미하는지 모르겠다. 내가 잘못을 겪을 때까지.본질적으로 그가 말하고자 하는 것은 현재의 수요가 아닌 용례를 시도하고 예측하지 말라는 것이다.개발자가 코드를 말리려고 할 때, 보통 예상되는 용례가 발생한다.그들은 유사한 코드를 작성하고 있는 것을 보았고, 그것을 모두 클래스나 함수에 넣어서 '추상적' 코드를 만들려고 시도했다.나는 이 함수와 클래스들이 추상적이지 않고 주의력을 분산시키기 쉽기 때문에 여기서 'abstract' 를 인용했다.이 예를 들어 개발자는 두 가지 함수를 실현했다.post와put은 같은 코드로 검색 문자열 파라미터를 가져오고 HTTP 요청에서 본문을 가져온다.
    import json
    
    
    def post(request):
        params = {}
        for param in request['query_string'].split('&'):
            field, value = param.split('=')
            params[field] = value
    
        body = json.loads(request['body'])
        ...
    
    
    def put(request):
        params = {}
        for param in request['query_string'].split('&'):
            field, value = param.split('=')
            params[field] = value
    
        body = json.loads(request['body'])
        ...
    
    이 코드를 없애기 위해서, 그들은 HTTP 요청의 논리를 추상적으로 해석하는 함수를 만들 수 있습니다.
    import json
    
    def parse_request(request):
        params = {}
        for param in request.query.split('&'):
            field, value = param.split('=')
            params[field] = value
    
        body = json.loads(request.body)
        return params, body
    
    def post(request):
        params, body = parse_request(request)
        ...
    
    
    def put(request):
        params, body = parse_request(request)
        ...
    
    보기에는 괜찮은데 문제가 있어요.HTTP Get 요청에 parse_request()을 사용하려면 어떻게 됩니까?Get 요청이 바디를 사용하지 않으므로 None 값이 json.loads()에 전달되어 폭발할 수 없습니다.단지 코드가 실행 중이기 때문에 그것이 다시 사용할 수 있다는 것을 의미하지는 않는다.더 중용할 수 있는 것은 get_query_params 함수와 get_body 함수다.개발자가 이 점을 보는 유일한 방법은 코드를 복제하는 것이다. 포스터,put,get 함수에서 검색 문자열 매개 변수와 요청체를 가져와 재구성하고 코드의 실제 모델에 추상적인 모델을 만드는 것이다.주의해야 할 것은 대부분의 IDE는 재구성 기능을 가지고 있으며, 흔히 볼 수 있는 모델을 찾아 추상화할 수 있다.그러나 IDE가 코드 사용 방식을 예측하는 기능을 가진 경우는 드물다.IDE의 재구성 기능은 두 가지 함수를 만들 수 있습니다. 하나는 검색 문자열 파라미터를 가져오는 데 사용되고, 다른 하나는 요청 본문을 가져오는 데 사용됩니다. 코드의 중복 모드이기 때문입니다.get_query_paramsget_body 함수는 매우 추상적이다. 왜냐하면 그들은 서로 결합을 풀고 단일한 책임이 있기 때문이다.그것들도 마침 마른 코드다.관건은 용례를 예측하려고 할 때 너무 일찍 추상을 만들어 비대해진 클래스, 함수, 추상을 초래할 수 있다는 것이다.

    너무 이르다 추상 은 모든 취약 소프트웨어 의 근원 이다


    이것이 나의 두 번째 점을 끌어냈다.너무 이르는 추상은 모든 취약 소프트웨어의 근원이다.내가 이렇게 말하는 것은 너무 이르는 추상이 너로 하여금 잘못된 가설을 작성하는 위험에 직면하게 하기 때문이다.잘못된 가설은 나쁜 추상을 초래할 수 있고, 나쁜 추상은 해커의 공격을 초래할 수 있으며, 너무 많은 해커의 공격은 취약하고 유지하기 어려운 코드를 초래할 수 있다.모든 HTTP 요청에 하나의 개체가 없기 때문에 요청체를 항상 해석하려는 것은 잘못된 가설입니다.이 예에서 간단한 해결 방안이 하나 있지만 항상 그렇지는 않다. 추상에 포함된 기능이 많을수록 모든 용례를 지원하는 데 필요한 해커가 많아진다.이것은 코드에 매듭을 짓는다. 특히 엉망진창인 추상을 대량으로 사용할 때이다.사용률이 높은 오류 추상을 복구할 때, 대량의 호출 코드를 변경해야 한다.뿐만 아니라 SOLID의 켜기/끄기 원칙을 위반해 오류 도입 위험을 증가시켰다.이것이 바로 내가 중복 코드가 잘못된 추상화보다 훨씬 싸다고 말하는 이유이다.

    잘못된 추상화보다 복제가 더 싸다


    잘못된 추상보다 중복이 바로잡기 쉽기 때문일 수도 있다.중복을 없애는 것은 장난감을 주워서 장난감 상자에 넣는 것과 같고, 오류를 복구하는 추상은 내가 암시한 것처럼 매듭을 풀는 것과 같다.이것은 중복 코드가 하나의 모델을 따르기 때문에 추상적인 것을 복원하는 것도 하나의 모델을 따르기 때문에 복원 프로그램은 중복 코드가 있는 어느 곳에서든 함수나 클래스를 호출하고 필요할 때 적당한 변수를 전달한다.앞에서 parse_request() 함수를 만들 때 이 점을 보았습니다.그러나 이 매듭을 풀기는 보통 어렵다. 왜냐하면 모든 용례와 처리해야 할 부분을 식별해야 하기 때문이다.그리고 엉망진창인 추상을 처리하기 위해 설정된 해커를 찾아서 삭제해야 합니다.다음은 개발자가 get 요청을 강제로 추상적으로 처리하면 이 매듭을 풀 수 있는 예이다.
    다음은 코드입니다. json.loads() 호출 (해커) 주위에try/except 블록이 있습니다.
    import json
    
    
    def parse_request(request):
        params = {}
        for param in request.query.split('&'):
            field, value = param.split('=')
            params[field] = value
    
        try:
            body = json.loads(request.body)
        except:
            body = {}
    
        return params, body
    
    
    def post(request):
        parse_request(request)
        ...
    
    
    def put(request):
        parse_request(request)
        ...
    
    
    def get(request):
        parse_request(request)
        ...
    
    이것은 매듭을 풀고 난 후의 코드다.
    import json
    
    
    def get_query_params(request):
        params = {}
        for param in request.query.split('&'):
            field, value = param.split('=')
            params[field] = value
    
        return params
    
    
    def get_body(request):
        return json.loads(request.body)
    
    
    def post(request):
        params = get_query_params(request)
        body = get_body(request)
        ...
    
    
    def put(request):
        params = get_query_params(request)
        body = get_body(request)
        ...
    
    이 예는 그리 나쁘지는 않지만, 여전히 필요하다.
  • 새 함수 만들기
  • 이름 바꾸기 및 이전 버전
  • 시도/예외 블록 제거
  • 어쨌든, 함수를 정확한 위치에서 호출해야 합니다. 이것은 건조가 기본적으로 복사/붙여넣는 중복 코드보다 훨씬 복잡합니다.나쁜 추상이 존재하는 시간이 길수록, 축적된 용례가 많을수록, 그것을 사용하는 곳도 많아진다.매번 접촉하거나 좋지 않은 추상적인 개념을 사용할 때마다 매듭은 더욱 팽팽해지고 복원하기 어려워진다.

    코드는 다시 사용할 수 없고 추상적으로는 다시 사용할 수 있다


    결국 코드는 다시 사용할 수 없고 추상적으로는 다시 사용할 수 있다.건조의 정의는 심지어 같다고 할 수 있다."모든 지식은 하나의 체계에 단일하고 명확하며 권위적인 표시가 있어야 한다."모든 지식에는 추상적인 개념이 있어야 한다는 것이다.하나의 추상은 검색 문자열 파라미터를 어떻게 해석하는지에 대한 지식, 하나의 추상은 해석 요청체에 대한 지식, 한 사용자의 추상적인 표현 등을 포함한다.모든 지식은 추상적이다. 이것은 코드를 안정적이고 건조하게 유지할 것이다. 당신이 자신을 반복할 때 모든 것이 시작된다. 그러므로 항상 멈추고 자신을 반복해라.

    좋은 웹페이지 즐겨찾기