코드 냄새 | 원시적 집착
29564 단어 codequalityrefactorit
Primitive Obsession
라는 매우 흔한 코드 냄새가 어떻게 나는지 소개하려고 합니다. 명확하지 않습니까? 축소된 예를 살펴보겠습니다.class User {
#locale: string;
#age: number;
#email: string;
#SPANISH_LANGUAGE: string = "es";
#UNDERAGE_UNTIL_AGE: number = 18;
#EMAIL_REGEX: RegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
constructor(locale: string, age: number, email: string) {
this.#locale = locale;
this.#age = age;
this.#email = email;
if (!this.isValidEmail()) throw new Error("Invalid email format");
};
understandSpanish(): boolean {
const language = this.#locale.substring(0, 2);
return language === this.#SPANISH_LANGUAGE;
};
isOlderAge(): boolean {
return this.#age >= this.#UNDERAGE_UNTIL_AGE;
};
isValidEmail(): boolean {
return this.#EMAIL_REGEX.test(this.#email);
};
}
const user = new User("es", 18, "[email protected]");
user.understandSpanish(); // true
user.isOlderAge(); // true
user.isValidEmail(); // true
그렇게 나쁘지는 않지?
이 예는 작기 때문에 약간 오해의 소지가 있을 수 있지만
User
클래스의 코드가 커지기 시작하면 클래스 내에서 추상화할 수 있는 몇 가지 논리가 여전히 있음을 더 명확하게 보기 시작할 것입니다. 우리 수업이 훨씬 좋아 보인다고우리의 가장 친한 친구: 가치 객체
값 개체는 단순히 기본 유형의 모델링입니다. 예를 살펴보겠습니다.
class Email {
#email: string;
#EMAIL_REGEX: RegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
constructor(email: string) {
this.#email = email;
if (!this.isValid()) throw new Error("Invalid email format");
};
isValid(): boolean {
return this.#EMAIL_REGEX.test(this.#email);
};
value(): string {
return this.#email;
};
}
new Email("[email protected]").value(); // "[email protected]"
new Email("susogmail.com").value(); // Error: Invalid email format
보시다시피, 우리는 기본
string
유형의 추상화를 생성하고 있으며, 그 안에 수신한 이메일이 유효한지 확인하는 논리를 추가하고 있습니다. 신청VO는 어떤 이점을 제공합니까?
리팩토링 시간
초기 상태:
class User {
#locale: string;
#age: number;
#email: string;
#SPANISH_LANGUAGE: string = "es";
#UNDERAGE_UNTIL_AGE: number = 18;
#EMAIL_REGEX: RegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
constructor(locale: string, age: number, email: string) {
this.#locale = locale;
this.#age = age;
this.#email = email;
if (!this.isValidEmail()) throw new Error("Invalid email format");
};
understandSpanish(): boolean {
const language = this.#locale.substring(0, 2);
return language === this.#SPANISH_LANGUAGE;
};
isOlderAge(): boolean {
return this.#age >= this.#UNDERAGE_UNTIL_AGE;
};
isValidEmail(): boolean {
return this.#EMAIL_REGEX.test(this.#email);
};
}
VO
클래스 코드를 User
, Locale
및 Age
의 세 가지 값 개체로 분할합니다.Email
class Locale {
#locale: string;
#SPANISH_LANGUAGE: string = "es";
constructor(locale: string) {
this.#locale = locale;
};
understandSpanish(): boolean {
const language = this.#locale.substring(0, 2);
return language === this.#SPANISH_LANGUAGE;
};
value(): string {
return this.#locale;
};
}
Locale
class Age {
#age: number;
#UNDERAGE_UNTIL_AGE: number = 18;
constructor(age: number) {
this.#age = age;
};
isOlderAge(): boolean {
return this.#age >= this.#UNDERAGE_UNTIL_AGE;
};
value(): number {
return this.#age;
};
}
Age
class Email {
#email: string;
#EMAIL_REGEX: RegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
constructor(email: string) {
this.#email = email;
if (!this.isValid()) throw new Error("Invalid email format");
};
isValid(): boolean {
return this.#EMAIL_REGEX.test(this.#email);
};
value(): string {
return this.#email;
};
}
마지막으로
Email
클래스는 다음과 같이 유지됩니다.class User {
#locale: Locale;
#age: Age;
#email: Email;
constructor(locale: Locale, age: Age, email: Email) {
this.#locale = locale;
this.#age = age;
this.#email = email;
};
understandSpanish(): boolean {
return this.#locale.understandSpanish();
};
isOlderAge(): boolean {
return this.#age.isOlderAge();
};
}
이러한 방식으로 볼 수 있듯이 사용자 클래스가 유효성 검사를 수행할 책임이 없는 방식으로 각 기능을 해당 기능
User
에 캡슐화하므로 시간이 지남에 따라 더 읽기 쉽고 유지 관리 가능한 코드를 얻을 수 있습니다.새 리팩터링된
value object
클래스 사용:// with valid email
const user1 = new User(
new Locale("es"),
new Age(18),
new Email("[email protected]")
);
user1.understandSpanish(); // true
// with invalid email
const user2 = new User(
new Locale("es"),
new Age(18),
new Email("susogmail.com")
);
user2.understandSpanish(); // Error: Invalid email format
경고!
모든 것이 장점은 아닙니다. 아래에서 이러한 추상화를 적용할 때 고려해야 하는 몇 가지 단점을 볼 수 있습니다.
읽어주셔서 감사합니다 😊
Reference
이 문제에 관하여(코드 냄새 | 원시적 집착), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/producthackers/refactoring-primitive-obsession-3oaf텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)