최근 Nest.js를 이용해 다중 사용자가 참여할 수 있는 웹 기반 퀴즈 게임 프로젝트의 백엔드를 구현하고 있습니다. 이는 과거에 인기 있었던 큐플레이와 유사한 서비스로, 팀 구성원들과 함께 애자일 개발을 통해 필수 기능들을 배포하고 점진적으로 확장해 나가기로 결정했습니다.
초기에는 싱글 플레이어 퀴즈 기능을 우선 구현하고 있으며, 현재 퀴즈 플레이 정보(이하 퀴즈존)를 서버 메모리에서 관리하고 있습니다. 하지만 이 과정에서 서버 메모리와 확장성에 대한 고민이 생겼습니다.
이로 인해 이후에는 Redis
같은 외부 스토리지를 사용하는 것이 필요할 수 있겠다고 판단했고, 현재 메모리 스토리지를 인터페이스를 통해 구현해 둠으로써 확장성에 대비하기로 했습니다.
인터페이스를 사용한 의존성 주입이 필요한 이유와 이를 구현하는 과정을 소개하겠습니다.
Nest는 아키텍처 문제를 해결하기 위해 만들어진 프레임워크로, 테스트 가능성, 확장성, 느슨한 결합성을 가진 애플리케이션 아키텍처를 지향합니다. 이를 통해 팀원들이 유지보수가 쉬운 애플리케이션을 개발할 수 있도록 돕습니다.
Nest provides an out-of-the-box application architecture which allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications. (Nest 공식 문서)
Nest는 도메인 주도 설계(DDD)를 쉽게 적용할 수 있도록 설계되었습니다. Nest CLI의 nest g resource
명령어를 사용해 특정 도메인에 대한 모듈, 서비스, 컨트롤러 등을 생성하면, 관련 기능들이 한 모듈에 모여 코드의 가독성과 관리 용이성이 높아집니다. 이 방식은 코드의 확장성과 재사용성을 높이며, 모듈 간 결합도를 낮춰 유지보수를 용이하게 합니다.
Nest에서는 **의존성 주입(DI)**을 통해 객체 간의 의존성을 해결합니다. 이는 코드가 다른 객체와의 결합도를 낮춰, 테스트 및 확장이 용이하게 만들어 줍니다. DI는 @Injectable
데코레이터를 사용해 프로바이더를 정의하고, 이를 생성자에서 주입받아 사용할 수 있게 합니다.
@Injectable()
export class QuizService {
constructor(private readonly questionService: QuestionService) {}
}
여기서는 스토리지 인터페이스를 통해 퀴즈존 정보를 관리하는 클래스를 만들고, 이 인터페이스를 기반으로 한 메모리 기반 스토리지와, 확장이 필요한 경우 외부 스토리지를 구현하도록 설계할 수 있습니다.
먼저 QuizStorage
라는 스토리지 인터페이스를 정의합니다.