좋은 코드의 조건이란?
💋 1. 코드를 통해 의도를 전달하자!
p같이 의도를 알기 어려운 구린 변수명보다는 position같이 의도가 드러나고 이름이 정갈한 변수명을 사용한다.
물론 그것보다 좋은 것은 그것보다 좋은건 원시값 포장이다. 예) class Position
그렇다고 모든 원시값을 포장할 수는 없다! 개발자라면 알아서 잘 느낄 것이다.
💋 2. 일관된 코드 스타일을 가져가자!
💋 3. 하나의 메서드는 하나의 일만!
하나의 함수가 많은 일을 하면 추상화 계층이 나빠질 수 있다. 이게 무슨 말인지 이해하기가 좀 어려운데, 좋은코드, 나쁜코드의 추상화 계층 내용을 읽어보면 도움이 될 수 있다.
테스트 코드를 작성하기 너무 힘들다면, 추상화계층이 너무 커진 것 아닌지 의심해 본다.
그렇다고 갈기갈기 찢아서 먼지만하게 나누면 안된다~
추상은 사람의 주관이 들어가고, 사람의 생각/시스템의 변화에 따라 달라지기 때문에 어렵다
💋 4. 파라미터가 너무 많으면...?
헷갈려서 잘못될 수 있음! 빌더패턴을 활용해보는것도 추천한다. 이펙티브 자바에서 찾아볼 수 있다.
💋 5. 비즈니스 로직을 제외하고는 API가 이미 있는 경우가 많다
적절한 자료구조를 사용하는 것도 좋다. 예) 중복을 체크하는 경우라면 Set를 사용해 본다.
그렇다고 해서 API를 떡칠하면 안된다. 기능을 위해서 API를 사용하고, API를 위한 API를 하지말자!
나는 스트림을 처음 공부하고 나서, 이런 획기적인 방법이 있다니! 하고 모든 반복문을 스트림으로 떡칠한 적이 있다. 당시에 단순히 반복하는 for i문에서조차도 IntStream을 사용하다가, 너무 과한 것 같다는 피드백을 받은 적이 있다.
산업공학과에서 공부할 때에도 교수님께서 여러 번 언급했던 내용이다. 다양한 기업들은 요즘 뜨는 것이 머신러닝이다, 하면 자신의 문제점에 대해 파악하기보다는 문제점에 대한 해결책을 머신러닝에 끼워맞추려고 한다고 한다고 한다. 사람이라면 누구나 저지를 수 있는 실수이지만, 항상 나의 목적이 무엇인지 생각하는 태도를 통해 좀 개선할 수 있다.
문제점을 먼저 생각하자!
💋 6. 의미없는 매직넘버는... 피하자!
예를 들어, 현재 사용자에게 정수 입력값을 받으려 하고, 만약 내가 설정한 기준에 맞지 않는 정수가 입력된다면 -1을 반환값으로 보내 처리하는 코드를 작성했다고 생각해 보자. 그렇다면 코드를 작성하는 나는 그 코드에서 -1이 반환되었을 때에 어떤 상태인지 알 수 있지만, 1년 후의 나 혹은 다른 사람이 이 코드를 사용할 때에 이상한데서 갑자기 -1을 반환한다면 상당히 당황스러울 것이다.
매직 넘버는 밖에서 호출하는 사람 입장에서는 내부구현이 어떻게 되어있나 신경써야 하므로 추천하지 않는다.
.orElseThrow(-1)로 이번 메서드 내에서 완벽히 내가 모든 것을 처리하겠다 생각하기 보다는 때로는 차라리 Optional을 반환해서 외부에서 처리하도록 하는 방법도 있다. 또한 예외를 발생시켜서 명시적으로 처리하는 방법도 있다.
항상 이 코드는 잊혀질 것이라 생각하면서 코드를 작성하는 것이 좋다고 생각한다.
💋 7. 부수효과를 제거하자!
부수효과란, 입력된 내용을 DB에 저장한다던가, 변수에 담긴 내용을 변경하는 등등, 부수적으로 일어나는 효과를 말한다.
실제로 나조차도 이전에 데이터를 조회에서 데이터를 조회하고, 특정 조건에 어긋나지 않은 그대로 데이터베이스에 저장을 명령하는 코드를 작성했다가 예상할 수 없는 시점에 DB에 중복으로 데이터가 마구 저장되는 당황스러운 일을 겪은 적이 있다.
이처럼 명령과 조회를 동시에 하면, 나중에 조회하기가 힘들어진다.
조회할 때는 무언가가 변경이 된다면 조심히 다뤄야하는 메서드가 된다. 따라서 분리하는 것이 좋다.
더 알아보고 싶다면, command query seperation에 대해 공부해보자!
💋 8. 중요한 입력을 무시하지 말자!
중요한 입력을 무시하면, 서비스가 동작하지 않은 건지 동작했는데 결과가 없는건지 확인이 불가능하다.
하지만 중요도를 정하는 과정에 주관이 들어가 사람마다 다르고, 따라서 수많은 협업자들은 정책을 정한다.
Public 메서드를 여러 개 제공하면서, 내가 의도한 생각대로 사용할 거라고 가정하지 말자
메서드 사용자는 메서드를 구현한 사람의 의도를 모른다고 가정해야 한다.
💋 9. Enum을 활용해 보는 것도 방법이다!
enum은 상수일 수도, 객체일 수도 있다.
어떠한 관점으로 볼지에 따라 코드가 작성되고 사용되는 것 또한 다르다.
- Enum은 상수 용도로만 사용하고 복잡한 메서드를 넣지 말아야한다는 딱딱파
- Enum은 클래스이므로 객체처럼 사용해도 된다는 말랑파
나는 enum을 사용하는 큰 이유가 타입에 대한 안전한 비교, 생성자에 대한 인스턴스를 외부에서 무제한 생성하는걸 방지하는 역할이라고 생각하기 때문에 객체처럼 사용해도 괜찮다고 생각한다.
이 논쟁에 정답은 없다...
협업하는 사람들과 의견이 맞으면 그걸로 될 뿐...
다른분들의 의견: Enum 타입과 관련된 기능들을 분리하는 것보다 상태와 행위들을 한 곳에서 관리할 수 있는 일급 컬렉션을 사용하는 것처럼 Enum과 관련된 행위들을 Enum 안에서 관리해주면 괜찮지 않을까?
💋 10. 실수를 줄이는 코드를 작성하자!
원시값 포장에 대해서 고민해볼 수 있다.
int 값을 value 필드로 가지고 있는 객체가 있다고 생각해 보자.
만약 value에 1을 더해야 하는 상황이 발생했을 때 두 가지 방법을 생각할 수 있다.
1. int 값(value)을 불변객체(final)로 설정하고, increase()하는 경우 new Position(value+1)을 반환한다.
2. value를 당장 수정해 value++한다.
둘 중 어떤 면에서 1번 방법이 더 실수를 줄이는 방법이 될 수 있다. 외부에서 함부로 value의 값을 건드릴 수 없기 때문이다. 근데 메모리에 대한 문제가 걱정되기도 한다...? 여러 가지 해결책이 있을 것 같은데,
1. 포지션 최대값을 제한하고 캐싱한다. [공부해보자]
2. 가비지컬렉터를 믿고 그냥 간다.
자바는 블루 컬러 언어니깐, 현장에서 생각해보면 실수를 줄이는게 메모리보다 값지다고 느낄 수도 있다...?
또 다른 예시로, List를 필드로 가지는 객체에서 실수를 줄이는 코드를 작성하려면 어떻게 해야할까?
List<String> dislikeMenus()를 그냥 반환하면 외부에서 clear해버릴 수 있다.
new ArrayList<>(dislikeMenus)를 반환하면 외부에서 조작해도 원본이 손실되지 않는다.
아니면 `unmodifiableList`도 있다! 하지만 만능은 아니니 조심하도록 하자!
책팔이는 아니지만 개인적으로 코치가 다룬 내용이 좋은 코드, 나쁜 코드와 많이 겹친다고 느꼈다.
다 읽지 못했는데 이참에 잘 읽어봐야지!
'우아한테크코스5기' 카테고리의 다른 글
[우테코] 사다리 미션 1단계 회고 (2) | 2023.02.19 |
---|---|
[우테코] 자동차 경주 게임 회고 (4) | 2023.02.18 |
[우테코] 웹 기초: HTML, CSS, JS를 사용해 자기소개 페이지 만들기 (0) | 2023.02.17 |
[우테코] TDD (Test Driven Development): 테스트 주도 개발이 뭐지? 사용하는 이유? (0) | 2023.02.14 |
[우테코] 코드 품질: 좋은 코드는 어떤 코드일까? (0) | 2023.02.08 |