클린 코드란?
클린 코드는 간결하고 이해하기 쉽고 수정이 용이한 코드를 말합니다.
가독성을 높이고 그에 따라 유지보수도 쉽고 또 에러가 발생할 가능성이 적기 때문에 협업에 있어서 매우 중요하다고 할 수 있습니다.
코드를 작성할 때 항상 고민하지만 막상 다른 사람에게 코드를 보여주거나 설명을 하기 위해 코드를 다시 보면 다른 사람이 보고 이해할 수 있을까 라는 생각이 들 때가 많아 클린 코드에 대해 정리해 보겠습니다.
클린 코드의 주요 원칙
가독성 : 다른 개발자가 코드를 읽고 이해하기 쉬워야 합니다.
간결성 : 코드는 가능한 짧으면서 하나의 기능만 수행해야 합니다.
재사용성 : 코드는 재사용 가능하도록 일반적인 형태로 작성되어야 합니다.
테스트 용이 : 코드를 테스트하기 쉬워야 합니다.
유지보수성 : 코드는 변경하기 쉬워야 하며 결합도를 낮춰야 합니다.
가독성
함수 이름과 변수의 명이 명확하지 않아 어떤 기능을 수행하는지 알 수 없기 때문에 명확히 해야 합니다.
// 배드 코드
async a(id: number): Promise<User> {
return await this.b.findOne(id);
}
// 클린 코드
async findUserById(userId: number): Promise<User> {
return await this.userRepository.findOne(userId);
}
간결성
가급적 하나의 함수는 하나의 작업을 수행해야 합니다.
// 배드 코드
// 얼핏 보면 하나의 기능을 수행한다고 보여지지만 2개의 기능을 수행
async updateUser(id: number, userData: UpdateUserDto) {
const user = await this.userRepository.findOne(id);
user.name = userData.name;
user.email = userData.email;
await this.userRepository.save(user);
}
// 클린 코드
async updateUser(id: number, userData: UpdateUserDto) {
const user = await this.findUserById(id);
this.updateValues(user, userData);
await this.userRepository.save(user);
}
// 함수를 더 작은 단위로 분리하여 한 가지 작업만 수행하도록 수정
updateValues(user: User, userData: UpdateUserDto) {
user.name = userData.name;
user.email = userData.email;
}
재사용성
특정 상황에서만 사용될 수 있는 함수는 재사용성이 떨어지기 때문에 지향해야 합니다.
// 배드 코드
// isUsed가 true인 상황에서만 동작
getActiveUsers() {
return this.userRepository.find({ where: { isUsed: true } });
}
// 클린 코드
getUsersByStatus(isUsed: boolean) {
return this.userRepository.find({ where: { isUsed } });
}
테스트 용이
외부 서비스에 강한 의존성을 가지고 있으면 테스트하기 어렵습니다.
// 배드 코드
async sendEmail(user: User, message: string) {
const emailService = new EmailService(); // 직접적으로 객체를 생성하면 강한 의존성을 띔
await emailService.send(user.email, message);
}
// 클린 코드
// 의존성 주입을 통해 외부 서비스를 가져와서 사용
constructor(private emailService: EmailService) {}
async sendEmail(user: User, message: string) {
await this.emailService.send(user.email, message);
}
유지보수성
높은 결합도를 가지게 되면 코드 수정 시 다른 부분에도 영향을 미칠 수 있기 때문에 책임을 분리하는 것이 좋습니다.
// 배드 코드
// 유저를 삭제하기 전 해당 유저가 작성한 게시글을 모두 삭제
class UserService {
async deleteUser(id: number) {
const posts = await this.postRepository.find({ userId: id });
await this.postRepository.remove(posts);
await this.userRepository.delete(id);
}
}
// 클린 코드
// 게시글을 삭제하는 기능과 유저를 삭제하는 기능을 분리하여 유지보수성 향상
// 각각 해당하는 서비스에서 동작
class PostService {
async deletePostsByUser(userId: number) {
const posts = await this.postRepository.find({ userId });
await this.postRepository.remove(posts);
}
}
class UserService {
constructor(private postService: PostService) {}
async deleteUser(id: number) {
await this.postService.deletePostsByUser(id);
await this.userRepository.delete(id);
}
}
NestJs에서 클린 코드 작성 방법
모듈화와 컴포넌트 기반 설계 : 기능별로 모듈을 분리하여 각각의 모듈이 하나의 책임을 갖도록 설계하는 것이 바람직합니다.
서비스와 컨트롤러의 분리 : 비즈니스 로직은 Service, Controller에서는 요청을 받아 Service에 전달하는 구조로 용도를 명확히 해야 합니다.
의존성 주입 사용 : 결합도를 낮추고 테스트에 용이한 코드를 작성해야 합니다.
환경 설정 관리 : 환경 설정 파일을 환경 별로 분리하여 유연성 있게 관리해야 합니다.
코드 일관성 : Prettier나 ESLint 같은 도구를 사용하여 코드 스타일을 일관되게 유지해야 합니다.
'Nestjs' 카테고리의 다른 글
| [NestJs] config 사용하기 (0) | 2024.03.30 |
|---|---|
| [NestJs] 로그인 기능 구현 (0) | 2024.03.23 |
| [NestJs] Repository 패턴 사용해보기 (0) | 2024.03.20 |
| [NestJs] TypeORM 연결하기 (3) | 2024.03.18 |
| [NestJs] Middleware 알아보기 (1) | 2024.03.15 |