GitHub - songhaechan/Black_Jack
Contribute to songhaechan/Black_Jack development by creating an account on GitHub.
github.com
자바를 학습하고 처음으로 진행한 사이드프로젝트 BlackJack은 재미있는(?) 카드게임이다.
규칙도 정말 단순하고 구현하는데 그리 오래걸리진 않았다. 그래서인지 나의 문제점도 알지 못했고 돌아가면 그만이지 라는 아주 못된 생각을 하며... 코드리뷰를 받았다.
절대 코드는 돌아가면 그만이지라는 생각으로 작성해서는 안된다.
코드는 유지보수하기 쉬워야하며, 새로운 요구사항에 빠르게 반응할 수 있어야한다.
처음엔 이런 말 조차 와닿지가 않았다. 왜냐고? 유지보수를 할 필요성을 전혀 느끼고있지 않았기때문이다.
사실 대학교 2학년이 진행하는 조그마한 사이드프로젝트에 무슨 이용자며 트래픽이며 확장이 일어나겠는가...
하지만 그 어떤 프로그래머도 사용자없는 프로그램은 작성하지않는다. 사이드프로젝트를 하더라도 항상 이 마음가짐을 가지고 있어야한다.
이 글은 그동안의 코드리뷰에대한 나의 느낀점 기억해야할 점 또한 프로젝트를 진행하며 맞딱드린 문제점과 그 해결방안을 기록하고자한다.
높은 가독성을 가진 코드를 작성하자
BlackJackPrinter bjp = new BlackJackPrinter bjp;
bjp.printAll();
bjp ? 도대체 이게 무슨 단어란 말인가.
지금껏 그 누구와도 약속하지않은 나만의 축약어를 많이 사용했다. 필드명이 길어져도 좋으니 명확한 이름을 지어주자!
메서드와 클래스 네이밍도 마찬가지다. 이름만 보고도 주석을 보지않고서도 알아 들을 수 있을 정도의 이름을 지어야한다.
약속되지않은 축약어는 금지
if(dealer.getScore() > 17){
// DoSomething
}
나는 17이라는 숫자가 가지는 의미를 알고있다. 하지만 코드를 작성하는 것은 나만의 비밀일기를 쓰는 것이 아니다.
소위 저런 숫자를 보고 매직넘버라고 한다. 아무도 알지 못하지만 나만 아는 비밀 숫자...
실제 17은 딜러가 17점이상 획득하면 더 이상 카드를 받지 않는다는 의미다.
의미를 가지는 숫자는 상수화 시키자.
JAVA Convention 을 지키도록 하자.
접근제어자를 고민하자
클래스 내에 있는 필드들은 보통의 경우 밖에서의 접근을 막아야한다. 작성자가 의도를 가지고 필드를 수정하려한다면 오직 메서드를 통해서 변경해야한다.
Player player = new Player();
player.score = 10;
위와 같은 코드는 작성하지않도록 private를 선언해 원천적으로 방어하자.
객체의 책임을 생각하자
객체의 책임을 규정하기란 참 어려운 일이다. 너무 작게 만들자니 클래스의 증가가 걱정되고 너무 크게 만들자니 객체지향원칙을 지킬 수 없게된다.
이번 프로젝트를 할 때에는 설계에대해 깊게 고민하지 않았었다. 하지만 직접 프로젝트를 해보니 객체의 책임이 커지면 프로그램 확장에 지장이 생긴다는 것을 느꼈다.
객체지향과 디자인패턴 이라는 책을 읽으면서 객체의 책임을 고려하고 그에 맞게 설계하는게 얼마나 중요한지를 깨닫게되었다.
SOLID 원칙 중 SRP (Single Responsbility Principle)가 바로 단일 책임 원칙이다.
클래스를 변경하는 이유가 오직 하나이기 위해서는 객체의 책임은 하나여야한다.
정말 모호한것 같지만 SRP를 지키기위한 좋은 방법이 한 가지 있다.
바로 해당 객체의 기능을 이용하는 다른 객체를 바라보는 것이다.
A객체는 1 과 2 라는 기능을 제공한다고 가정했을 때 이 객체를 사용하는 B와C가 각각 1과 2를 따로 사용할 경우 간접적으로 서로 기능을 나눠 사용한다고 볼 수 있으며 객체의 책임이 크다는 반증이기도하다. 즉, 객체 분리의 대상이 된다.
물론 이 방법이 만능은 아닐 것이다. 하지만 초반에 길을 잡아 줄 수 있는 좋은 방법이라 생각한다.
If-Else 지옥에서 벗어나자
중첩된 if - else문은 첫 번째로 언급했던 코드의 가독성과 밀접한 관계가있다.
if-else문을 아예 사용하지 않을 수는 없겠지만 else문자체는 그 자체로 어떤 조건을 표시할 수가없다.
else문을 해석하기위해선 if문의 해석이 필수적이라는 뜻이다.
else문을 최소화해서 if문 만으로도 해석이가능한 코드를 작성하자.
문제의 시작 확장과 변경의 어려움
언급했지만 대학교 2학년의 작은 프로젝트에는 사용자의 요구로 인한 수정은 발생하기 어렵다.
하지만 멘토님께서 개선하라고 말씀하신 부분들이 점점 수정이 어려워졌다.
내가 멘토님께 했던 카톡이 기억난다. "지금 개선을 해보고는 있는데 맞물려있는 메서드들이 너무 많네요..."
문제는 이렇다. 객체의 잘못된 관계와 객체 책임의 방대함 그리고 추상화의 부재.
이번엔 추상화와 관계에대해 되돌아보고자한다.
추상화라는 것은 다형성을 이용한다는 것이고 SOLID원칙 중 OCP원칙을 지킬 수 있게해준다.
처음에 언급했던 프로그램의 확장과 유연함은 다형성을 통해 얻을 수 있다.
추상화를 진행하면 무한한 확장의 힘을 가질 수 있다.
초기설계 시 아래와 같이 A는 B에 직접적인 의존관계를 가지고있다.
A ----- > B
직접적으로 의존하다보니 A클래스 내에는 B의 기능을 이용한 수 많은 코드들이 존재할 것이다.
근데 이게 왠걸 B는 시대에 뒤떨어진다 생각한 사장님께서 C라는 클래스로 교체를 원한다.
기존에 모든 코드가 B를 의존하기때문에 B를 의존하는 모든 코드는 C를 의존하는 코드로 변경해야한다.
명심하자 변화되는 부분은 추상화의 대상이다 !!
절망을 느낀 개발자는 A ---- > Interface 의 구조로 추상화를 이용해 개발하기 시작한다.
Interface < ------ B , C 와 같이 인터페이스에 의존하여 구체클래스를 개발하다보니 A내부에는 B 나 C 어떤 클래스에도 의존하지 않고
Interface 타입에 의존하게된다.
이젠 사장님의 변덕, 세상의 변덕은 두렵지 않다. D E F 라는 요구사항이 들어와도 그저 새로운 기능만 인터페이스에 맞춰 구현해주면 되기 때문이다.
하지만 안정적인 인터페이스 설계가 선행되어야한다.
OCP는 인터페이스에 대고 개발하기 때문에 무한한 확장을 가능케한다.
하지만 불안정한 인터페이스를 설계한다면 어떤 일이 벌어질까?
변하지 않을 것만 같았던 인터페이스가 변한다면 그를 믿고있던 B C D E F 는 엄청난 배신감에 휩싸인다.
그렇기때문에 흔들리지않는 인터페이스 설계가 선행되어야 OCP원칙을 최고의 효율로 사용할 수 있는 것이다.
'Java' 카테고리의 다른 글
[WAS를 만들어보자 (3)] HttpMessageBody 추출하기 (1) | 2024.03.23 |
---|---|
[WAS를 만들어보자 (2)] HTTP 메세지 출력하기 (0) | 2024.03.23 |
[WAS를 만들어보자 (1)] 자바로 TCP/IP 통신하기 (0) | 2024.03.23 |
Faker를 이용한 테스트데이터 만들기 + 데이터 30만건 밀어넣기 (0) | 2023.07.16 |
Exception Performance Cost (0) | 2023.07.05 |