지금은 괜찮아 보일수도 있지만 서비스가 커져서 다른 db를 사용하거나 여러 db를 분리해서 메모리와 서비스에 맞게 db를 사용한다고 하면 Repository만 고치기 보다는 service코드까지 수정을 해야할거다
왜냐면 직접 Repository를 불러서 사용하고 있기 때문!
하지만 추상화를 높이고 의존성을 주입하는 방식으로 코드를 수정해서 느슨한 결합을 만들어준다면?
코드는 길어질수 있지만 SRP단일책임원칙을 지킬수 있게 되고
이말은 결과적으로 service코드 자체도 mock작업을 하거나 통합테스트를 한다거나 하는것이 아니라 단위테스트를 가능하게 한다는 의미일것이다.
classUserRepositoryInterface{
asyncgetUserById(userId) {
const user = { name: "test", age: 20 };
if (userId) {
return user;
}
}
}
classMysqlUsersRepositoryextendsUserRepositoryInterface{
// MySQL 데이터베이스에서 사용자 데이터를 가져올 수 있는 코드를 추가할 수 있음
}
classMongoUsersRepositoryextendsUserRepositoryInterface{
// MongoDB에서 사용자 데이터를 가져올 수 있는 코드를 추가할 수 있음
}
classUsersService{
constructor(usersRepository) {
this.usersRepository = usersRepository;
}
asyncgetUser(userId) {
returnthis.usersRepository.getUserById(userId);
}
}
const mysqlRepository = new MysqlUsersRepository();
const mongoRepository = new MongoUsersRepository();
const mysqlService = new UsersService(mysqlRepository);
const mongoService = new UsersService(mongoRepository);
mysqlService.getUser(1).then((user) => {
console.log("MySQL User:", user);
});
mongoService.getUser(1).then((user) => {
console.log("MongoDB User:", user);
});
UsersService코드가 변경되었는가?
4. Dependency Injection(의존성 주입)
의존성 주입이란 결국 강한 결합들을 느슨한 결합으로 풀어주는 방법이다.
근데 의존성 주입도 단점보단 장점이 훨씬 많지만 단점이 없는것은 아니다. 대표적으로 dependency를 위한 코드가 많이 생성이된다는것이고 이를 관리하는것은 조금 까다로운 작업이 될수 있기 때문.
여기서 IoC, 정확히는 IoC 컨테이너라고 하는 의존성주입을 도와주는 도구가 나오게 된다.
그러면서 의존성주입의 장점만을 유지시켜주는 프레임워크도 등장하게 되고 발전하게 된다.(nestjs, spring)
5. Inversion of Control , IoC(제어의 역전)
이걸 정확하게 node에서 표현하기는 쉽지가 않다. 따라서 여기서부터는 nestjs로 예시를 대체할거다.
nestjs에서는 IoC가 객체의 생명주기를 관리해주기 때문에 개발자는 좀더 비즈니스로직의 집중할 수 있게 해준다.
예를들어보자
Service객체와 Repository객체가 있고 S가 R에 의존하고 있다고 해보자
우리는 이 객체를 사용할때 생명주기를 생각하고 사용하는가? 이 생명주기관리를 IoC 컨테이너가 한다고 생각하면 된다. (최근에는 객체의 메모리관리를 가비지 컬렉터가 알아서 한다 ㅎㅎ)