문맥
최근에는 더 나은 형식의 코드를 만드는 데 관심이있었습니다. 그리고 더 나은 의미는 "충분한 사람들이 승인 한 규칙을 따르는 것이 좋습니다."
요즘에는 대부분 Ruby로 코드를 작성하기 때문에 linter (Rubocop)를 사용하여 코드의 "품질"에 대한 정보를 제공하기 시작했습니다 (이 "품질"은 커뮤니티 주도 프로젝트 ruby-style-guide에 의해 정의 됨 ).
나는 어떤 경우에는, 코드 효율성이 실제로 경우에도 그다지 코드의 효율성에 대해, "를 형식화하는 품질"과 "품질"을 사용할 것이라는 점을주의 한다 코드를 작성하는 방법에 의해 영향을 미쳤다.
어쨌든, 모든 것을하면서 나는 몇 가지 일을 깨달았습니다 (적어도 기억했습니다).
- 일부 언어 (주로 Python, Ruby 등)는 훌륭한 코드를 만들 수 있습니다
- 코드에 대한 몇 가지 지침을 따르면 코드가 훨씬 짧아 지지만 여전히 명확 해집니다.
- 그러나이 지침을 너무 엄격하게 따르면 코드가 명확하지 않고 읽기가 쉽지 않습니다.
- 이 코드는 일부 지침을 거의 완벽하게 준수 할 수 있지만 여전히 품질이 좋지 않습니다.
- 코드 가독성은 대부분 주관적입니다 ( "명백한 것이 동료 개발자에게는 완전히 모호 할 수 있음").
이것들은 단지 절대적인 규칙이 아니라 단지 관찰입니다. 또한이 시점에서 코드 가독성과 지침을 따르지 않는 것처럼 보일 수 있지만 여기서는 지침이 하나의 코드를 다시 작성하는 방법의 수를 좁히는 방법입니다.
이제 몇 가지 예를 더 명확하게 설명하겠습니다.
예
간단한 사용 사례를 보자 : " User
"모델을 가진 애플리케이션이있다 . 사용자는 선택 firstname
적이고 surname
필수 email
주소를 가지고 있습니다.
최소한 " 또는 그 존재하는 경우 사용자의 name
이름 ( firstname + surname
)을 반환 firstname
하거나 그렇지 않은 경우 대체 값으로 반환하는 " " 메소드를 작성하고 싶습니다 .surname
email
또한이 메소드가 " use_email
"를 매개 변수 (부울)로 사용하여 사용자 이메일을 폴백 값으로 사용할 수 있기를 원합니다 . 이 " use_email
"매개 변수는 기본적으로 전달되지 않은 경우 " "로 설정해야합니다 true
.
루비로 작성하는 가장 간단한 방법은 다음과 같습니다.
def name(use_email = true)
# If firstname and surname are both blank (empty string or undefined)
# and we can use the email...
if (firstname.blank? && surname.blank?) && use_email
# ... then, return the email
return email
else
# ... else, concatenate the firstname and surname...
name = "#{firstname} #{surname}"
# ... and return the result striped from leading and trailing spaces
return name.strip
end
end
이 코드는 가장 간단하고 이해하기 쉬운 방법입니다. 루비를 "말하지"않는 사람에게도.
이제 더 짧게 만들어 봅시다 :
def name(use_email = true)
# 'if' condition is used as a guard clause instead of a conditional block
return email if (firstname.blank? && surname.blank?) && use_email
# Use of 'return' makes 'else' useless anyway
name = "#{firstname} #{surname}"
return name.strip
end
이것은 쉽지는 않지만 더 짧고 이해하기 쉽습니다 (guard 절은 조건부 블록보다 읽기에 더 자연 스럽습니다). Guard 절은 또한 내가 사용하는 지침을보다 잘 준수하므로 여기에서 승리하십시오. 또한 들여 쓰기 수준을 줄입니다.
이제 좀 더 짧게하기 위해 Ruby 매직을 사용하자 :
def name(use_email = true)
return email if (firstname.blank? && surname.blank?) && use_email
# Ruby can return the last called value, making 'return' useless
# and we can apply strip directly to our string, no need to store it
"#{firstname} #{surname}".strip
end
더 짧고 지침을 완벽하게 준수하지만 반환 진술이 없기 때문에 명확하지 않으므로이 연습에 익숙하지 않은 사람들에게는 다소 혼란 스럽습니다.
우리가 질문을 시작할 수있는 곳이 여기 있습니다. 정말 가치가 있습니까? "아니오"라고 말하면 읽을 수있게하고 ' return
'를 추가하십시오 (이를 알면 지침을 따르지 않음). 아니면 "괜찮아, 루비 방식이야, 젠장 언어를 배워라!"라고 말해야합니까?
옵션 B를 취하면 더 짧게 만들 수 없습니다.
def name(use_email = true)
(email if (firstname.blank? && surname.blank?) && use_email) || "#{firstname} #{surname}".strip
end
여기는 하나의 라이너입니다! 물론 더 짧습니다 ... 여기서 우리는 루비 가 정의 된 값 에 따라 값 또는 다른 값을 반환한다는 사실을 이용합니다 (이메일은 이전과 동일한 조건에서 정의되므로).
우리는 또한 그것을 쓸 수 있습니다 :
def name(use_email = true)
(email if [firstname, surname].all?(&:blank?) && use_email) || "#{firstname} #{surname}".strip
end
짧지 않고 읽기가 어렵지 않습니다 (저는 추악한 한 줄짜리 라이너가 어떻게 보이는지 보았습니다), 좋은 루비, 내가 사용하는 지침을 준수합니다 ...하지만 여전히 첫 번째 작성 방법과 비교 읽고 이해하기가 훨씬 쉽지 않습니다. 이 줄이 너무 길다 (80 자 이상).
질문
코드의 일부 예는 "풀 사이즈"코드와 여러 축소 버전 (유명한 한 줄짜리 줄) 중에서 선택하는 것이 어려울 수 있음을 알 수 있습니다. 여전히 가독성 측면에서 "전체 크기"코드를 능가하는 것은 없습니다.
여기 진짜 질문이 있습니다. 어디에서 멈출까요? 언제 짧고 짧습니까? 코드가 "너무 짧고"읽기 어려운 시점을 아는 방법 (주관적임을 명심)? 그리고 더 많은 것 : 항상 코드를 작성하고 느낌이 좋을 때 하나의 라이너를 "풀 사이즈"코드 덩어리와 섞지 않는 방법은 무엇입니까?
TL; DR
여기서 가장 중요한 질문은 "길지만 명확하고 읽기 쉽고 이해하기 쉬운 코드 덩어리"와 "한 줄을 읽고 이해하기 어려운 강력하고 더 짧지 만 이해하기 어려운"중에서 선택하는 것입니다. 두 가지 유일한 옵션이 아닌 척도의 맨 아래 : "충분히 명확함"과 "정확하지 않은 것"사이의 경계를 정의하는 방법은 무엇입니까?
주요 질문은 고전적인 "한 줄짜리 대 가독성 : 어느 쪽이 더 낫습니까?" "둘 사이의 균형을 찾는 방법은?"
편집 1
코드 예제의 주석은 "무시"되어야하며, 발생하는 상황을 명확하게하기 위해 여기에 있지만 코드의 가독성을 평가할 때 고려해서는 안됩니다.
return
선호합니다 . 그 일곱 캐릭터는 내 눈에 약간의 선명도를 더합니다.
[firstname,surname,!use_email].all?(&:blank?) ? email : "#{firstname} #{surname}".strip
... 로 쓸 수 있습니다 . 왜냐하면 false.blank?
true를 반환하고 삼항 연산자는 몇 개의 문자를 저장 하기 때문입니다 ... ¯ \ _ (ツ) _ / ¯
return
키워드를 추가해야하는 명확성은 무엇 입니까?! 어떤 정보도 제공 하지 않습니다 . 순수한 혼란입니다.