No more databases, comment moderation, or pesky updates to install-just your content. Markdown, Liquid, HTML & CSS go in. Static sites come out ready for deployment. Permalinks, categories, pages, posts, and custom layouts are all first-class citizens here.
Sick of dealing with hosting companies? GitHub Pages are powered by Jekyll, so you can easily deploy your site using GitHub for free-custom domain name and all.
What is Jekyll?
마지막 주차에는 설계를 잘하고자 고민을 많이 했다. 사실 아직 최선의 방법인 것 같지는 않지만, 여기까지의 고민과정을 정리해보았다. 코딩 컨벤션은 그대로 지키면 되는데, 좋은 구현은 아직 어렵게느껴져서 계속 고민하는 과정 중이다. 🤔
🧱 설계
MVC 설계 과정은 2, 3주차에 많이 썼기에, 이번 글에서는 생략했다. 대신 이번에는 게임 전체 흐름과, Model에서 클래스 분리하는 과정을 정리해보았다.
게임 진행 흐름 - 순서도 이번에는 게임 흐름이 단순하지 않아서 이 흐름을 잘 정리하고 싶었다. (어디에 반복문이 있어야하고, 재시작을 해줘야 하는 지 등등..) 도메인단을 고민하기 전에, 아래처럼 전체 게임의 흐름을 순서도로 정리해보았다.
이 게임의 전체 흐름을 파악하기 위해 순서도를 계속 바꿔 그려가며 그렸고, 코드에서 저 흐름이 파악될 수 있도록 구현했다. 다음은 메소드명과 합쳐진 순서도이다.
전체 흐름 메소드를 따로 빼고, 메소드명만으로도 흐름을 파악할 수 있도록 이름 짓고, 메소드 내부에서는 해당 메소드명에 맞는 기능만 구현하고자 했다. (아래 코드는 전체 흐름을 설명하기 위해 input/output 관련 View 코드는 생략했다.) private void runGame() { // 전체 시작! createBridge(bridgeSize); // 다리 생성
startBridgeGame(); // 다리 게임 시작
printGameResult(); // 종료 }
private void startBridgeGame() {
do {
playEachRound(); // 한 라운드 시작
if (isFail()) break; // 이동 성공?!
} while (isFinalRound()); // 마지막 라운드까지 성공?! } 이 전체 흐름은 Controller 상에서 구현한 내용이다. 도메인단 관련 내용을 생각하기 전에 스스로 전체 흐름을 이해하고 싶어서, 이 부분을 먼저 그림으로 정리했었다. 그리고 본격적으로 Model 클래스들을 어떻게 나눌지 고민했다.
🧶 도메인단
클래스 분리 - 객체 지향 설계? 일단 이전 과제들에서는 Move / Bridge / Referee 이런식으로, 유저 / 정답 / 판단하는 클래스 이렇게 분리했었다. 근데 이번에는 유저 / 정답 클래스로 분리하고, 유저의 이동 성공 여부를 유저 클래스 본인이 가지고 있도록 했다. 객체가 스스로의 상태를 가지고 있도록 구현하고자 했다. 아래는 주요 클래스들이 가진 상태/행위이다. 클래스명의 상태/기능만 가지게 하고 싶었다. Move : 사용자의 이동 상태 (이동 방향, 이동 성공 여부) Bridge : 다리 상태 (다리, 매 라운드 발판 위치) Result : 게임 결과 (총 시도 횟수, 이동 기록) 사실 이렇게 유저와 정답을 판단해야될 때, Referee같은 판단하는 클래스가 있는 게 좋을 지? 없는 게 좋을 지 헷갈린다…! 객체 자신이 자기 클래스명에 맞는 데이터만 가지고, 그 테이터의 상태와 기능(메소드)만 갖도록 구현하고 싶었다. 아직 헷갈리고 모호한 부분들이 있어서, 객체 지향 설계에 대해 더 고민을 많이 해봐야 될거같다 📚 (사실 이 설계가 아직 마음에 들지는 않는다..!ㅠ) ⇒ 이 부분은 후에 더 공부하면서 리팩토링하고, 글 계속 업데이트 할 예정이다! 지금까지 설계하면서 고민한 과정도 기록하고자 했다!
BridgeGame - Controller? Service?
PR에 올린 코드에서는 저 도메인 클래스들을 BridgeGame라는 도메인 클래스가 관리하고 있다. 과제 규칙 상 BridgeGame에 View 코드가 있으면 안되서 BridgeGame을 Controller로 활용하지는 못했다. 근데 지금 생각해보니 BridgeGame을 Domain단으로 두지 말고 Service단으로 하는 게 좋았을 것 같다. 그러면 Domain 클래스들(Move / Bridge / Result)을 Service단에서 관리하게 할 수 있다. 비즈니스 로직은 도메인단 클래스에만 구현하고, Service 단에서 도메인들을 조합해서 로직을 구현하고, Controller단에서 이 Service단과 View단을 조합해서 구현하는 게 더 좋은 설계이지 싶다! 회고 쓰면서 그림 그리니까 더 명확히 잘 보이는 것 같다.
Result와 Record : 컴포지션 Result 클래스에 결과와 관련된 데이터들을 모아두었다. 즉 총 시도 횟수, 다리 이동 기록를 담고 있다. 여기서 Result 클래스는 Record 클래스를 컴포지션(합성)으로 참조하고 있다. (컴포지션이란? 상속보다 컴포지션을 사용하는 이유) 즉, 결과 관련 클래스(Result)에서 이동 기록 데이터를 따로 Record 클래스로 분리했다. 왜냐하면 다리 이동 기록이 2차원 List이고 로직 상 윗방향/아랫 방향 다리가 각각의 List 인스턴스 변수로 존재해야 했다. (기록 업데이트 시, 매번 윗 방향 다리/아랫 방향 다리 중 선택해야 했다. 근데 최초로 이동기록을 업데이트할 때, 2차원 리스트.get(0) 을 사용해서 접근하면 NPE가 발생하게 된다. 그래서 윗방향/아랫방향 다리를 따로 인스턴스 변수로 정의해주었다.) 또한 다리 기록만을 위한 기능/메소드가 꽤 필요했기에 아예 Record 클래스로 분리해주고, Result가 컴포지션(합성)으로 참조하게 했다.