8 Tips To Write Clean Code
Medium
클린 코드란 읽기 쉽고 유지보수도 쉬우며 이해하기 쉬운 코드를 뜻합니다. 클린 코드를 작성하는 것은 기술이라고 생각합니다. 또한 연습으로 향상할 수 있는 기술이라고도 생각합니다.
클린 코딩을 연습할 때 가장 좋아하는 방법은 리팩토링입니다. 클린 코드 원칙을 적용하여 오늘 한 단계씩 개선해 나가봅시다.
```
public void Process(Order? order) {
if(order is null) {
if(order.isVerified) {
if(order.Items.Count > 0) {
if(order.Items.Count > 15) {
throw new Exception("The order " + order.Id + " has too many items");
}
if(order.Status != "ReadyToProcess") {
throw new Exception("The order " + order.Id + " isn't ready to process");
}
order.IsProcessed = true;
}
}
}
```
1️⃣ 조기 반환 원칙
if 문이 깊게 중첩된 것은 굉장히 고통스럽습니다. 조건이 충족되는 즉시 반환해야 한다는 조기 반환 원칙을 사용하여 이 문제를 해결합시다.
```
public void Process(Order? order) {
if(order is null) {
return;
}
if(!order.isVerified) {
return;
}
if(order.Items.Count ==0) {
return;
}
if(order.Items.Count > 15) {
throw new Exception("The order " + order.Id + " has too many items");
}
if(order.Status != "ReadyToProcess") {
throw new Exception("The order " + order.Id + " isn't ready to process");
}
order.IsProcessed=true;
}
```
2️⃣ 가독성 향상을 위한 문장 병합
만약 반환하는 결과가 동일하다면, 문장을 병합시키는 방법도 고려해 봅시다.
```
public void Process(Order? order) {
if(order is null | !order.isVerified | order.Items.Count == 0) {
return;
}
order.IsProcessed=true;
}
```
3️⃣ 더 간결한 코드를 위해 LINQ 사용
LINQ를 이용하여 코드를 보다 간결하고 표현적으로 만듭시다. Items.Count == 0으로 체크하는 대신, 저는 Any 메소드를 선호합니다.
LINQ의 성능이 더 나쁘다고 주장할 수 있지만, 저는 가독성을 위해 활용합니다. 이 메소드 호출보다는 훨씬 더 큰 비용을 소모하는 작업이 애플리케이션 어딘가에 있을 겁니다.
```
public void Process(Order? order) {
if(order is null || !order.IsVerified || !order.Items.Any()) {
return;
}
if(order.Items.Count > 15) {
throw new Exception("The order " + order.Id + " has too many items");
}
if(order.Status != "ReadyToProcess") {
throw new Exception("The order " + order.Id + " isn't ready to process");
}
order.IsProcessed = true;
}
```
4️⃣ 부울 식을 메소드로 대체
if문에서 여러 조건을 하나로 병합하는 것은 코드를 적게 사용하지만, 복잡한 조건으로 인해 가독성을 저하할 수 있습니다.
변수나 메소드를 이용하여 이 문제를 해결하고 가독성을 높일 수 있습니다.
```
public void Process(Order? order) {
if(!Processable(order)) {
return;
}
if(order.Items.Count > 15) {
throw new Exception("The order " + order.Id + " has too many items");
}
if(order.Status != "ReadyToProcess") {
throw new Exception("The order " + order.Id + " isn't ready to process");
}
order.IsProcessed = true;
}
static bool IsProcessable(Order? order) {
return order is not null &&
order.IsVerified&&
order.Items.Any()
)
```
5️⃣ 사용자 지정 예외를 선호
저는 "예외"적인 상황에서만 예외를 사용하는 것을 좋아하고, 코드에서 흐름 제어를 위해 예외를 사용하지는 않습니다.
그런데도 흐름 조절에 예외를 사용하고 싶다면 사용자 지정 예외를 사용하는 것이 좋습니다.
```
public void Process(Order? order) {
if(!Processable(order)) {
return;
}
if(order.Items.Count > 15) {
throw new TooManyLineItemsException(order.Id);
}
if(order.Status != "ReadyToProcess") {
throw new NotReadyForProcessingException(order.Id);
}
order.IsProcessed = true;
}
static bool IsProcessable(Order? order) {
return order is not null &&
order.IsVerified&&
order.Items.Any()
)
```
6️⃣ 상수를 이용해 매직 넘버 고치기
자주 발생하는 코드 냄새는 매직 넘버를 사용하는 것입니다. 매직 넘버를 사용하면 코드를 추론하기 어렵고 오류가 발생하기 쉽습니다.
매직 넘버를 고정하는 것은 간단해야 하며, 한 가지 해결책은 상수를 도입하는 것입니다.
```
const int MaxNumberOfLineItems = 15;
public void Process(Order? order) {
if(!Processable(order)) {
return;
}
if(order.Items.Count > MaxNumberOfLineItems ) {
throw new TooManyLineItemsException(order.Id);
}
if(order.Status != "ReadyToProcess") {
throw new NotReadyForProcessingException(order.Id);
}
order.IsProcessed = true;
}
static bool IsProcessable(Order? order) {
return order is not null &&
order.IsVerified&&
order.Items.Any()
)
```
7️⃣ 매직 스트링을 열거형으로 고치기
매직 넘버와 유사하게 매직 스트링에서도 코드 냄새가 발생합니다. 매직 스트링의 전형적인 사례는 일종의 상태를 나타내는 것입니다.
열거형을 이용하여 매직 스트링을 다룹시다.
```
enum OrderStatus
{
Pending = 0,
ReadyToProcess = 1,
Processed = 2
}
```
8️⃣ Result Object Pattern 사용
저는 흐름 조절에 예외를 사용하는 것을 선호하지 않는다고 말했습니다. 하지만 그러면 어떻게 해결할 수 있을까요?
결과 클래스를 사용하여 모든 유형의 결과를 나타낼 수 있습니다.
```
public class ProcessOrderResult
{
public ProcessOrderResultType Type { get; }
public long OrderId { get; }
public string? Message { get; }
public static ProcessOrderResult NotProcessable() =>
new(ProcessOrderResultType.NotProcessable, default, "Not processable");
public static ProcessOrderResult TooManyLineItems(long oderId) =>
new(ProcessOrderResultType.TooManyLineItems, orderId, "Too many items");
public static ProcessOrderResult NotReadyForProcessing(long oderId) =>
new(ProcessOrderResultType.NotReadyForProcessing, oderId, "Not ready");
public static ProcessOrderResult Success(long oderId) =>
new(ProcessOrderResultType.Success, oderId, "Success");
}
```
클린 코드를 쓰는 것은 의도적인 연습과 경험의 문제입니다. 많은 사람이 클린 코드 원리에 대해 읽지만, 매일 적용하려고 노력하는 사람은 거의 없습니다.
바로 이것이 당신을 다르게 만들 것입니다.
🐣 원문에서 코드가 최종적으로 어떻게 달라졌는지 확인해 보세요!
다음 내용이 궁금하다면?
이미 회원이신가요?
2023년 10월 26일 오전 10:32