주로 하나의 정규 표현식으로 구성된 큰 함수를 리팩터링해야합니까? [닫은]


15

방금 약 100 줄에 걸친 함수를 작성했습니다. 그 말을 듣고, 당신은 아마 하나의 책임에 대해 말하고 리팩토링을 촉구하는 유혹을 느낍니다. 이것은 내 직감이기도하지만 여기에 문제가 있습니다. 함수 작동 합니다. 복잡한 문자열 조작을 수행하며 함수 본문은 대부분 하나의 자세한 정규식으로 구성되며 문서화 된 여러 줄로 나뉩니다. 정규 표현식을 여러 기능으로 나눈 경우 언어를 효과적으로 전환 하고 정규 표현식 이 제공하는 일부 기능을 활용할 수 없으므로 실제로 가독성을 잃어 버릴 것 같습니다 . 여기 내 질문이 있습니다.

정규 표현식을 사용한 문자열 조작과 관련하여 큰 함수 본문은 여전히 ​​안티 패턴입니까? 명명 된 캡처 그룹은 기능과 매우 유사한 용도로 사용됩니다. 그건 그렇고, 정규식을 통과하는 모든 흐름에 대한 테스트가 있습니다.


3
나는 그 기능의 대부분이 문서 라는 것을 고려할 때 함수에 문제가 있다고 생각하지 않습니다 . 그러나 처음에는 큰 정규식을 사용하는 경우 유지 관리 성 문제가있을 수 있습니다.
Joel Cornett

2
거대한 정규 표현식이 문제에 대한 최상의 솔루션이라고 확신하십니까? 파서 라이브러리 나 사용자 지정 파일 형식을 표준 형식 (XML, JSON 등)으로 바꾸는 것과 같은 간단한 대안을 생각해 보셨습니까?
lortabac

2
이 정규식의 변경 / 강화 / 단순화 버전을 사용하는 다른 기능이 있습니까? 리팩토링이 이루어져야한다는 중요한 지표가 될 것입니다. 그렇지 않다면 그대로 두겠습니다. 이와 같은 복잡한 문자열 조작이 필요한 것은 그 자체로 노란 깃발입니다 (물론 컨텍스트를 알지 못하므로 노랑색으로 나타냅니다). it;)
Konrad Morawski

8
100 줄 정규 표현식은 어떻게 1 가지만 할 수 있습니까?
Pieter B

@lortabac : 입력은 사용자 생성 텍스트 (prose.)입니다.
DudeOnRock

답변:


36

당신이 겪고있는 것은 합리적인 의사 결정보다는 "모범 사례"라는 지침에 따라 가이드 라인을 노예로 따르는 사람들의 말을 듣는 데서 오는인지 부조화입니다.

당신은 분명히 숙제를 끝냈습니다 :

  • 기능의 목적이 이해됩니다.
  • 구현의 작업은 이해됩니다 (즉, 읽을 수 있음).
  • 구현에 대한 전체 범위 테스트가 있습니다.
  • 이 테스트는 통과되었으므로 구현이 정확하다고 생각합니다.

그 점 중 하나라도 맞지 않으면 먼저 함수가 작동해야한다고 말한 것입니다. 따라서 코드를 그대로 두는 것에 대한 투표가 하나 있습니다.

두 번째 투표는 옵션과 각 옵션에서 얻는 것과 잃어버린 것을 살펴 보는 것입니다.

  • 리 팩터 이렇게하면 함수의 길이에 대한 누군가의 아이디어를 준수하고 가독성을 희생 할 수 있습니다.
  • 아무것도하지 마세요. 이것은 기존의 가독성을 유지하고 기능의 길이에 대한 누군가의 아이디어 준수를 희생합니다.

이 결정은 가독성 또는 길이보다 더 중요하게 생각합니다. 나는 길이는 좋지만 가독성이 중요 하다고 생각하는 수용소에 빠지고 후자는 주중에 후자를 취할 것입니다.

결론 : 깨진 것이 아니라면 수정하지 마십시오.


10
"손상되지 않은 경우 수정하지 마십시오."+1
Giorgio

과연. Sandy Metz 규칙 ( gist.github.com/henrik/4509394 )은 훌륭하지만 전부 youtube.com/watch?v=VO-NvnZfMA4#t=1379에서 그녀는 어떻게 생겼는지, 사람들이 왜 복용하고 있는지에 대해 이야기합니다. 너무 진지해
Amadan

@ Amdan : 비디오의 추가 맥락에서 Metz는 말이됩니다. 한 고객에 대한 그녀의 추천은 고객을보다 합리적 중간으로 끌어 오는 방법으로 다른 고객에게는 극단적 인 행동에 대항하기 위해 의도적으로 극단적 인 것이 었습니다. 그 토론의 나머지 부분은 제 대답의 추력으로 요약됩니다. 믿음이 아니라 추론이 최선의 행동을 결정하는 방법입니다.
Blrfl

19

솔직히, 당신의 기능은 "한가지 일을"할 수 있지만, 당신이 언급 한대로

정규식을 여러 기능으로 나눌 수 있습니다.

정규 표현식 코드가 많은 일을한다는 것을 의미합니다. 그리고 그것은 더 작고 개별적으로 테스트 가능한 단위로 나눌 수 있다고 생각합니다. 그러나 이것이 좋은 생각이라면 대답하기 쉽지 않습니다 (특히 실제 코드를 보지 않고). 정답은 "예"또는 "아니오"일 수 있지만 "아직 아니라 다음 번에는 정규 표현식에서 무언가를 변경해야합니다"일 수 있습니다.

언어를 효과적으로 전환하기 때문에 가독성이 떨어질 것 같습니다.

그리고 이것이 핵심 요점 입니다. 정규 언어로 작성된 코드가 있습니다 . 이 언어는 그 자체로 좋은 추상화 수단을 제공하지 않습니다 (그리고 나는 "명명 된 캡처 그룹"을 함수의 대체물로 간주하지 않습니다). 따라서 "정규 ex 언어로"리팩토링은 실제로 가능하지 않으며 호스트 언어로 작은 정규 표현식을 섞어 짜는 것은 실제로 가독성을 향상시키지 않을 수 있습니다 (적어도 느낌 이 있지만 의심이 있습니다. 그렇지 않으면 질문을 게시하지 않았을 것입니다) . 여기 내 조언이 있습니다

  • 다른 고급 개발자 (예 : /codereview// )에게 코드를 표시하여 다른 사람들이 가독성에 대해 생각하도록합니다. 다른 사람들이 당신처럼 읽을 수있는 100 줄 정규 표현식을 찾지 못할 수도 있다는 생각에 개방적입니다. 때때로 "작은 조각으로 쉽게 깨지지 않는다"는 개념은 두 번째 눈으로 극복 할 수 있습니다.

  • 실제 진화 가능성을 관찰하십시오-새로운 요구 사항이 도착하고이를 구현하고 테스트해야 할 때 반짝이는 정규 표현식이 여전히 좋아 보입니까? 정규 표현식이 작동하는 한, 나는 그것을 만지지 않을 것이지만, 무언가를 바꿔야 할 때마다,이 큰 블록에 모든 것을 넣는 것이 정말로 좋은 생각이라면 다시 생각할 것입니다. 작은 조각은 더 나은 옵션이 아닙니다.

  • 유지 보수성을 관찰하십시오-현재 형식으로 정규 표현식을 효과적으로 디버깅 할 수 있습니까? 특히 무언가를 변경 한 후, 테스트 결과에 무언가 잘못되었다는 것이 밝혀지면 근본 원인을 찾는 데 도움이되는 정규 exp 디버거가 있습니까? 디버깅이 어려워지면 디자인을 재고해야 할 수도 있습니다.


명명 된 캡처 그룹 (일반적으로 캡처 그룹)은 final / write-once 변수 또는 매크로와 가장 유사하다고합니다. 정규식 프로세서에서 반환 된 일치 객체 또는 이후 정규 표현식 자체에서 일치의 특정 부분을 참조 할 수 있습니다.
JAB

4

때로는 하나의 작업을 수행하는 더 긴 기능이 작업 단위를 처리하는 가장 적절한 방법입니다. 데이터베이스 쿼리를 처리 할 때 (원하는 쿼리 언어를 사용하여) 매우 긴 기능을 쉽게 이용할 수 있습니다. 명시된 목적으로 제한하면서 함수 (또는 메소드)를 더 읽기 쉽게 만드는 것은 함수의 가장 바람직한 결과라고 생각하는 것입니다.

길이는 코드 크기와 관련하여 임의의 "표준"입니다. C #의 100 줄 함수가 더 길다고 생각되는 경우 일부 버전의 어셈블리에서는 작습니다. 200 줄의 코드 범위에 잘 들어간 보고서에 대해 매우 복잡한 데이터 집합을 반환하는 일부 SQL 쿼리를 보았습니다.

완벽하게 작동하는 코드 , 즉 합리적으로 목표를 달성 할 수있는만큼 간단 합니다.

길이가 길기 때문에 변경하지 마십시오.


3

항상 정규식을 하위 정규식으로 나누고 점차적으로 최종 표현식을 작성할 수 있습니다. 이는 특히 동일한 하위 패턴이 여러 번 반복되는 경우 매우 큰 패턴에 대한 이해를 도울 수 있습니다. 예를 들어 Perl;

my $start_re = qr/(?:\w+\.\w+)/;
my $middle_re = qr/(?:DOG)|(?:CAT)/;
my $end_re = qr/ => \d+/;

my $final_re = $start_re . $middle_re . $end_re;
# or: 
# my $final_re = qr/${start_re}${middle_re}${end_re}/

나는 당신이 제안하는 것보다 훨씬 편리한 verbose 플래그를 사용합니다.
DudeOnRock

1

깨질 수 있다면 깨뜨릴 것이라고 말하고 싶습니다. 유지 관리 성 관점에서 그리고 아마도 재현성에서 그것을 깨뜨리는 것이 합리적이지만, 물론 함수의 자연 성과 입력을 얻는 방법 및 반환되는 것을 고려해야합니다.

나는 청크 분할 된 데이터를 객체로 파싱하는 작업을 기억 했으므로 기본적으로 내가 두 가지 주요 부분으로 나누었습니다. 하나는 인코딩 된 텍스트로 문자열의 완전한 단위를 작성하고 두 번째 부분은 데이터 사전으로 데이터 단위를 구문 분석하고 구성하는 것이 었습니다 그것들은 (다른 객체에 대한 임의의 속성 일 수 있음) 객체를 업데이트하거나 만드는 것보다.

또한 각 주요 부분을 더 작고 구체적인 여러 기능으로 나눌 수 있으므로 결국에는 5 가지 기능을 사용하여 모든 작업을 수행하고 일부 기능을 다른 위치에서 재사용 할 수 있습니다.


1

고려하거나 고려하지 않은 한 가지는 해당 언어의 정규 표현식을 사용하는 대신 사용중인 언어로 작은 파서를 작성하는 것입니다. 읽기, 테스트 및 유지 관리가 더 쉬울 수 있습니다.


나는 이것에 대해 스스로 생각했다. 문제는 입력이 산문이며 컨텍스트와 형식에서 신호를 받고 있다는 것입니다. 이런 식으로 파서를 작성하는 것이 가능하다면 그것에 대해 더 많이 배우고 싶습니다! 나는 아무것도 찾을 수 없었다.
DudeOnRock

1
정규식으로 구문 분석 할 수 있으면 구문 분석 할 수 있습니다. 귀하의 응답으로 인해 구문 분석에 정통하지 않을 수 있습니다. 이 경우 정규식을 고수 할 수 있습니다. 그 중 하나이거나 새로운 기술을 배우십시오.
Thomas Eding

새로운 기술을 배우고 싶습니다. 추천 할만한 좋은 자료가 있습니까? 나는 그 배후의 이론에도 관심이 있습니다.
DudeOnRock

1

거대한 정규 표현식은 대부분의 경우 나쁜 선택입니다. 내 경험상 개발자가 파싱에 익숙하지 않기 때문에 자주 사용됩니다 ( Thomas Eding의 답변 참조 ).

어쨌든 정규식 기반 솔루션을 고수한다고 가정 해 봅시다.

실제 코드를 모르므로 가능한 두 가지 시나리오를 살펴 보겠습니다.

  • 정규식은 간단합니다 (많은 리터럴 일치 및 몇 가지 대안)

    이 경우 단일 정규식에서 제공하는 고급 기능이 반드시 필요한 것은 아닙니다. 이것은 분할로 이익을 얻을 수 있음을 의미합니다.

  • 정규식은 복잡합니다 (많은 대안)

    이 경우 아마도 수백만 개의 가능성있는 흐름이 있기 때문에 실제적으로 전체 테스트 범위를 가질 수 없습니다. 따라서 테스트하려면 분할해야합니다.

상상력이 부족할 수도 있지만 100 줄 정규식이 좋은 솔루션 인 실제 상황은 생각할 수 없습니다.

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