문제

일반적으로 복사 및 페이스트 프로그래밍이 나쁜 생각이지만 실제로 두 가지 기능이나 코드 블록이있는 상황을 처리하는 가장 좋은 방법은 무엇입니까? 하다 몇 가지 방법으로 달라야 할 필요가 필요합니까?

몇 가지 사소한 변형을 제외하고 코드가 실질적으로 동일하지만 매개 변수, 템플릿 메소드 또는 이와 유사한 것을 추가하여 쉽게 찾을 수없는 사소한 변형이 아닌 경우 어떻게해야합니까?

더 일반적으로, 약간의 복사 및 붙여 넣기 코딩이 진정으로 정당하다는 것을 인정하는 상황을 만난 적이 있습니까?

도움이 되었습니까?

해결책

사람들은 코드를 세 곳 이상으로 사용하지 않으면 추상화가 상환되지 않기 때문에 (코드의 복제 제한을 최대 두 인스턴스로 제한) 한 번 복사 및 붙여 넣기를 말하는 것을 들었습니다. () 나 자신, 나는 필요를 보 자마자 그것을 리팩토링하는 좋은 습관으로 만들려고 노력한다.

다른 팁

당신의 기능에 대해이 질문을하십시오

"이 작은 요구 사항이 변경되면 충족시키기 위해 두 기능을 모두 변경해야합니까?"

물론 때로는 허용됩니다. 그래서 사람들은 스 니펫 파일을 보관합니다. 그러나 코드를 자주 자르고 붙여 넣거나 몇 줄 이상으로 코드를 붙잡고 있다면 서브 루틴으로 만드는 것에 대해 생각해야합니다. 왜요? 승률은 무언가를 바꿔야하며, 이런 식으로 한 번만 변경하면됩니다.

중간 케이스는 그러한 사용 가능한 경우 매크로를 사용하는 것입니다.

그렇습니다. 그리고 그것은 당신이 말하는대로 정확합니다. 사소하지만 사실이 어려운 변형. 상황이 실제로 요구되는 경우 자신을 편모하지 마십시오.

RE는 끊임없이 수용 할 수 있습니다.

예. 세그먼트가 약간 다르고 일회용 시스템 (매우 짧은 시간 동안 유지되고 유지 보수가 필요하지 않은 시스템)을 수행하는 경우. 그렇지 않으면 일반적으로 공통점을 추출하는 것이 좋습니다.

비슷하지만 정확히 똑같이 보이지 않는 세그먼트 :

차이가 데이터에있는 경우, 함수를 추출하고 데이터의 차이를 매개 변수로 사용하여 리팩터를 사용하십시오 (매개 변수로 전달하기에 너무 많은 데이터가있는 경우 객체 또는 구조로 그룹화하는 것을 고려하십시오). 차이가 함수의 일부 프로세스에있는 경우 명령 패턴 또는 추상 템플릿을 사용하여 리팩터를 리팩토링하십시오. 이러한 디자인 패턴으로도 리팩터를 리팩터링하기가 여전히 어려운 경우, 기능은 자체적으로 많은 책임을 다루려고 할 수 있습니다.

예를 들어, 두 세그먼트에서 다른 코드 세그먼트가있는 경우 -Diff#1 및 diff#2입니다. Diff#1에서는 diff1a 또는 diff1b를 가질 수 있으며 diff#2의 경우 diff2a 및 diff2b를 가질 수 있습니다.

diff1a & diff2a가 항상 함께 있고 diff1b & diff2b가 항상 함께있는 경우, diff1a & diff2a는 하나의 명령 클래스 또는 하나의 추상 템플릿 구현, diff1b & diff2b에 포함될 수 있습니다.

그러나 몇 가지 조합 (예 : diff1a & diff2a, diff1a & diff2b, diff1b & diff2a, diff1b & diff2b)이 있다면, 너무 많은 책임을 스스로 처리하려고 할 수 있기 때문에 기능을 다시 생각할 수 있습니다.

RE SQL 문 :

로직 (if-else, 루프)을 사용하여 SQL을 동적으로 구축하면 가독성이 동적입니다. 그러나 모든 SQL 변형을 만드는 것은 유지하기가 어렵습니다. 반쯤 만나고 SQL 세그먼트를 사용하십시오. 공통점을 SQL 세그먼트로 추출하고 해당 SQL 세그먼트를 상수로 모든 SQL 변형을 만듭니다.

예를 들어:

private static final String EMPLOYEE_COLUMNS = " id, fName, lName, status";

private static final String EMPLOYEE_TABLE = " employee";

private static final String EMPLOYEE_HAS_ACTIVE_STATUS = " employee";

private static final String GET_EMPLOYEE_BY_STATUS =
  " select" + EMPLOYEE_COLUMNS + " from" + EMPLOYEE_TABLE + " where" + EMPLOYEE_HAS_ACTIVE_STATUS;

private static final String GET_EMPLOYEE_BY_SOMETHING_ELSE =
  " select" + EMPLOYEE_COLUMNS + " from" + EMPLOYEE_TABLE + " where" + SOMETHING_ELSE;

회사의 코드 기반에는 공통점이 높은 일련의 약 10 정도의 큰 털이 많은 SQL 문이 있습니다. 모든 진술에는 공통된 핵심 또는 최소한 단어만이 다른 핵심이 있습니다. 그런 다음 10 개의 진술을 3 또는 4 그룹으로 그룹화하여 각 부속기마다 하나 또는 두 단어가 다른 핵심에 공통 부속기를 추가 할 수 있습니다. 여하튼, 10 SQL 문을 밴드 다이어그램의 세트로 생각하십시오.

우리는 복제를 피하는 것과 같은 방식 으로이 진술을 코딩하기로 결정했습니다. 따라서 진술을 작성하는 기능 (기술적으로 Java 방법)이 있습니다. 공통 핵심의 차이 또는 두 단어를 설명하는 일부 매개 변수가 필요합니다. 그런 다음 부속물을 구축하기 위해서는 기능이 필요합니다. 물론 더 많은 부속기에 대한 사소한 차이와 더 많은 기능을위한 더 많은 매개 변수로 매개 변수화됩니다.

코드는 SQL 중 어느 것도 반복되지 않는다는 점에서 영리합니다. SQL에서 절을 수정 해야하는 경우 한 곳에서 단지 한 곳에서 조항을 수정하고 10 SQL 문이 모두 수정됩니다.

그러나 사람은 읽기가 어렵습니다. 주어진 케이스에 대해 SQL이 실행될 수있는 유일한 방법은 디버거를 밟고 완전히 조립 된 후 SQL을 인쇄하는 것입니다. 그리고 조항을 생성하는 특정 기능이 더 큰 그림에 어떻게 맞는지 알아내는 것은 불쾌한 지 알아냅니다.

이 글을 쓴 이후, 나는 종종 우리가 SQL 쿼리를 10 번 자르고 목을 좋아하는 것이 더 좋을지 궁금했습니다. 물론, 우리 가이 작업을 수행했다면, SQL에 대한 변경 사항은 10 장소에서 발생해야 할 수도 있지만, 의견을 통해 업데이트 할 10 장소를 가리킬 수 있습니다.

SQL을 이해할 수있는 이점과 한 곳에서는 SQL 절단 및 목을 목록하는 단점을 능가 할 것입니다.

Martin Fowler가 제안한 것처럼

한 번만 해요.

두 번, 냄새가 나기 시작합니다.

시간을 보내십시오 리팩터.


편집 : 의견에 대한 답변으로, 조언의 기원은 Don Roberts입니다.

세 번의 파업과 당신은 리팩터입니다.

Martin Fowler는이를 설명합니다 리팩토링 제 2 장, 섹션 3의 규칙 (58 페이지).

절대적으로 Neeever ..

:)

문제의 코드를 게시하고 그것이 보이는 것보다 쉽다는 것을 알 수 있습니다.

그것이 그것을하는 유일한 방법이라면, 그것을 위해 가십시오. 종종 (언어에 따라) 선택적인 인수로 동일한 기능에 대한 사소한 변경을 충족시킬 수 있습니다.

최근에 PHP 스크립트에 add () 함수와 edit () 함수가있었습니다. 둘 다 거의 같은 일을했지만 edit () 함수는 삽입 쿼리 대신 업데이트 쿼리를 수행했습니다. 나는 방금 같은 일을했다

function add($title, $content, $edit = false)
{
    # ...
    $sql = edit ? "UPDATE ..." : "INSERT ...";
    mysql_unbuffered_query($sql);
}

잘 작동했지만 복사/붙여 넣기가 필요한 다른 시간이 있습니다. 그것을 방지하기 위해 이상하고 복잡한 경로를 사용하지 마십시오.

  1. 좋은 코드는 재사용 가능한 코드입니다.
  2. 바퀴를 재발 명하지 마십시오.
  3. 이유는 이유가 있습니다. 학습을 돕고 이상적으로 코드를 개선하는 데 도움이됩니다.

복사하여 붙여 넣어야합니까? 무슨 상관이야! 중요한 것은 당신은 사본과 붙여 넣기입니다. 나는 여기 누구에게도 철학적으로 얻으려고하지 않지만 실제로 이것에 대해 생각해 봅시다.

게으름에서 벗어 났습니까? "Blah Blah, 전에는 이렇게 해냈습니다 ... 몇 가지 변수 이름 만 변경합니다 .. 완료."

복사하고 붙여 넣기 전에 이미 좋은 코드라면 문제가되지 않습니다. 그렇지 않으면, 당신은 당신의 엉덩이를 길 아래로 물리는 게으름으로 인해 엉터리 코드를 영속하고 있습니다.

당신이 이해하지 못하기 때문입니까? "젠장 .. 그 기능이 어떻게 작동하는지 이해하지 못하지만 내 코드에서 작동하는지 궁금합니다." 이렇게하면 오전 9시에 마감일이 있고 오전 4 시경 시계에서 빨간 눈을 쳐다보고 있다고 스트레스를받는 즉시 시간을 절약 할 수 있습니다.

이 코드로 돌아올 때이 코드를 이해 하시겠습니까? 댓글을 달아도? 실제로는 - 수천 줄의 코드 후, 코드가 무엇을하고 있는지 이해하지 못하면 몇 주 후, 몇 주 후에 다시 돌아 오는 것을 어떻게 이해할 수 있습니까? 모든 유혹에도 불구하고 그것을 배우려고 시도하십시오. 입력하면 메모리에 커밋하는 데 도움이됩니다. 입력 한 각 줄은 그 라인이 무엇을하고 있는지, 그리고 해당 기능의 전반적인 목적에 어떻게 기여하는지 스스로에게 물어보십시오. 내부에서 배우지 않더라도 나중에 돌아올 때 최소한 인식 할 기회가있을 수 있습니다.

그래서 - 코드 복사 및 붙여 넣기? 당신이하고있는 일의 의미를 의식한다면 괜찮습니다. 그렇지 않으면? 하지 마십시오. 또한 복사하여 붙여 넣은 타사 코드의 라이센스 사본이 있는지 확인하십시오. 상식처럼 보이지만 얼마나 많은 사람들이하지 않는지 놀랄 것입니다.

나는 전염병처럼 자르고 붙여 넣는 것을 피합니다. 사촌 복제 및 수정보다 더 나쁩니다. 귀하와 같은 상황에 직면 한 경우 항상 매크로 프로세서 나 다른 스크립트를 사용하여 다양한 변형을 생성 할 준비가되었습니다. 내 경험상 a 진실의 단일 지점 매우 중요합니다.

불행히도 C 매크로 프로세서는 신축성, 표현, 진술 및 주장에 대한 성가신 인용 요구 사항 때문에이 목적에 좋지 않습니다. 나는 글쓰기가 싫다

#define RETPOS(E) do { if ((E) > 0) then return; } while(0)

그러나 그 인용문은 필수입니다. 도구 체인에 다른 항목을 추가하지 않으므로 빌드 프로세스 나 MakeFiles를 변경할 필요가 없기 때문에 결함에도 불구하고 C 전 처리기를 종종 사용합니다.

나는 이것이 확실히 주관적으로 태그가 지정되어 기쁘다! 이것은 지나치게 모호한 예이지만, 해당 섹션을 추상화하고 다른 부분을 다른 부분을 유지할 수있는 충분한 코드가 있다면 다른 부분을 차지할 수 있다고 생각합니다. 복사 할 수없는 요점은 유지하기 어려운 코드를 갖지 못하고 연약한 코드가 없다는 것입니다.

가장 좋은 방법 (일반적인 기능으로 변환하거나 매크로 사용 매크로를 사용하는 것 외에도 주석을 넣는 것입니다. 코드가 어디에서 복사되는지, 공통점, 차이점, 그리고 그 이유 ... 그럼 당신은 괜찮을 것입니다.

대부분 동일한 기능이 있지만 다른 시나리오에서 약간의 조정이 필요하다면 문제가되는 디자인입니다. 플래그 나 복사 페이스트 대신 다형성과 구성을 사용하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top