|
| 1 | +--- |
| 2 | +date: 2025-10-12 |
| 3 | +category: [에세이] |
| 4 | +published: true |
| 5 | +--- |
| 6 | + |
| 7 | +추석 때 켄트 벡의 Tidy First를 읽게 되었다. |
| 8 | +이 책에서 첫 번째로 나오는 개념인 '방어 코드'를 설명해 보도록 하겠다. |
| 9 | + |
| 10 | +방어 코드란, 전제조건이라고 생각하면 된다. |
| 11 | +즉, 어떤 x 로직이 돌아가기 위해서 선재적으로 만족되어야 하는 조건들을 직관적으로 명시할 수 있는 방법이다. |
| 12 | + |
| 13 | +예제가 최고의 문서이므로, 나의 [github.com/chebread/cvtr](https://github.com/chebread/cvtr) 레거시 코드를 통해 설명해 보도록 하겠다. |
| 14 | + |
| 15 | +```go |
| 16 | +if len(os.Args) >= 2 { |
| 17 | + switch os.Args[1] { |
| 18 | + case "convert": |
| 19 | + if len(os.Args) <= 5 { |
| 20 | + fmt.Printf("error: Not enough arguments provided\n") |
| 21 | + } else { |
| 22 | + amountStr := os.Args[2] |
| 23 | + sourceCurrency := os.Args[3] |
| 24 | + keyword := os.Args[4] |
| 25 | + targetCurrency := os.Args[5] |
| 26 | + |
| 27 | + if keyword != "to" { |
| 28 | + fmt.Printf("Error: Use 'to' keyword, instead of '%s' keyword\n", keyword) |
| 29 | + return |
| 30 | + } |
| 31 | + ... 코드 생략 ... |
| 32 | +``` |
| 33 | +
|
| 34 | +먼저 방어 코드로 바꾸기 위해서는 전제조건을 찾아야 한다. |
| 35 | +
|
| 36 | +위 코드에서 전제조건으로 사용되는 코드는 |
| 37 | +- `if len(os.Args) >= 2 { ... }` |
| 38 | +- `if len(os.Args) <= 5 { ... }` |
| 39 | +- `if keyword != "to" { ... }` |
| 40 | +
|
| 41 | +이다. |
| 42 | +
|
| 43 | +참고로 이게 왜 전제조건이냐 하면, 이 3가지가 만족되지 않으면 로직 실행 전에 프로그램을 종료해버리기 때문이다. |
| 44 | +즉, 이것은 로직 실행의 선재적인 조건에 해당된다. |
| 45 | +
|
| 46 | +전제조건을 찾았으면 이제 방어 코드로 바꾸면 된다. |
| 47 | +
|
| 48 | +방어 코드는 무조건 단일 if 문을 사용하며, 로직 실행 부의 최상단에 위치한다. |
| 49 | +최상단에 위치해야 하는 까닭은, 최상단에 위치해야만 그 로직 전체에 '전제 조건'으로 비춰질 수 있기 때문이다. |
| 50 | +
|
| 51 | +먼저 `if len(os.Args) >= 2 { ... }` 부터 바꿔보도록 하겠다. |
| 52 | +
|
| 53 | +```go |
| 54 | +if len(os.Args) < 2 { |
| 55 | + help() |
| 56 | + return |
| 57 | +} |
| 58 | + |
| 59 | +switch os.Args[1] { |
| 60 | + ... 코드 ... |
| 61 | +} |
| 62 | +``` |
| 63 | +
|
| 64 | +이렇게 `if len(os.Args) >= 2 { ... }`를 전제조건처럼 단독 if문으로 최상단에 위치하고, switch 문을 if else 문 바깥으로 빼면 된다. |
| 65 | +
|
| 66 | +이제 `if len(os.Args) <= 5 { ... }`를 바꿔 보겠다. |
| 67 | +
|
| 68 | +```go |
| 69 | +if len(os.Args) < 2 { |
| 70 | + help() |
| 71 | + return |
| 72 | +} |
| 73 | + |
| 74 | +switch os.Args[1] { |
| 75 | + if len(os.Args) <= 5 { |
| 76 | + boldRed("error: Not enough arguments provided\n") |
| 77 | + break |
| 78 | + } |
| 79 | + |
| 80 | + ... 코드 ... |
| 81 | +} |
| 82 | +``` |
| 83 | +
|
| 84 | +이것도 if else 문에서 빠져나와서 `if len(os.Args) <= 5 { ... }`를 전제조건화하면 된다. |
| 85 | +
|
| 86 | +이제 `if keyword != "to" {` 를 바꿔보자. |
| 87 | +```go |
| 88 | +if len(os.Args) < 2 { |
| 89 | + help() |
| 90 | + return |
| 91 | +} |
| 92 | + |
| 93 | +switch os.Args[1] { |
| 94 | + if len(os.Args) <= 5 { |
| 95 | + boldRed("error: Not enough arguments provided\n") |
| 96 | + break |
| 97 | + } |
| 98 | + |
| 99 | + if keyword := os.Args[4]; keyword != "to" { |
| 100 | + boldRed("error: Use 'to' keyword, instead of '%s' keyword\n", keyword) |
| 101 | + break |
| 102 | + } |
| 103 | + |
| 104 | + ... 코드 ... |
| 105 | +} |
| 106 | +``` |
| 107 | +
|
| 108 | +`keyword` 변수는 이 전제조건에서만 쓰임으로 이렇게 처리했다. |
| 109 | +
|
| 110 | +이게 레거시 코드이고 |
| 111 | +```go |
| 112 | +if len(os.Args) >= 2 { |
| 113 | + switch os.Args[1] { |
| 114 | + case "convert": |
| 115 | + if len(os.Args) <= 5 { |
| 116 | + fmt.Printf("error: Not enough arguments provided\n") |
| 117 | + } else { |
| 118 | + amountStr := os.Args[2] |
| 119 | + sourceCurrency := os.Args[3] |
| 120 | + keyword := os.Args[4] |
| 121 | + targetCurrency := os.Args[5] |
| 122 | + |
| 123 | + if keyword != "to" { |
| 124 | + fmt.Printf("Error: Use 'to' keyword, instead of '%s' keyword\n", keyword) |
| 125 | + return |
| 126 | + } |
| 127 | + ... 코드 생략 ... |
| 128 | +``` |
| 129 | +
|
| 130 | +이게 방어 코드로 바꾼 코드이다. |
| 131 | +```go |
| 132 | +if len(os.Args) < 2 { |
| 133 | + help() |
| 134 | + return |
| 135 | +} |
| 136 | + |
| 137 | +switch os.Args[1] { |
| 138 | + if len(os.Args) <= 5 { |
| 139 | + boldRed("error: Not enough arguments provided\n") |
| 140 | + break |
| 141 | + } |
| 142 | + |
| 143 | + if keyword := os.Args[4]; keyword != "to" { |
| 144 | + boldRed("error: Use 'to' keyword, instead of '%s' keyword\n", keyword) |
| 145 | + break |
| 146 | + } |
| 147 | + |
| 148 | + amountStr := os.Args[2] |
| 149 | + sourceCurrency := os.Args[3] |
| 150 | + targetCurrency := os.Args[5] |
| 151 | +} |
| 152 | +``` |
| 153 | +
|
| 154 | +방어 코드를 활용한 코드가 더 읽기 쉬울 것이다. |
| 155 | +
|
| 156 | +이제부터 이렇게 전제 조건으로 if문을 사용하는 경우에는 방어 코드를 적극 활용 해보기 바란다. |
0 commit comments