
Interpace Segregation Principle (ISP)ISP 란 구현에 의존하고 있는 인터페이스가 Compact 해야 한다는 것을 의미한다.
React 에서 사용되는 ISP 에 대한 원칙을 하기 전 , 객체 지향에서 이야기 하는 ISP 에 대해 먼저 이야기 한 후 React 에서 사용되는 ISP 원칙에 대해이야기 해보자
ISPclass Calculator {
introduce() {
console.log('안녕하세요 저는 계산기입니다');
}
add(num1, num2) {
return num1 + num2;
}
subtract(num1, num2) {
return num1 - num2;
}
multiply(num1, num2) {
return num1 * num2;
}
devide(num1, num2) {
return num1 / num2;
}
}
const adder = new Calculator();
const subtracter = new Calculator();
const multiplier = new Calculator();
const devider = new Calculator();
다음과 같이 Calculator 라는 추상화 된 인터페이스를 사용하는 adder , subtracter , mutiplier , devider 객체들이 존재한다고 이야기 해보자
각 객체들은 객체명에서 알 수 있듯이 한 가지 기능만을 하는 객체이다.
현재 아키텍쳐의 관계는 객체의 기능은 제한적임에도 불가하고 다양한 기능이 있는 Calculator 인터페이스에 의존성을 가지고 있는 모습을 볼 수 있다.
이렇게 사용하는 인터페이스가 무거워질 수록 (교재에서는 fat 이라는 표현을 한다.) 아키텍쳐의 구조를 명확하게 아는 것이 힘들다.
뚱뚱한 인터페이스를 수정하던 과정에서 예기치 못한 다른 메소드에도 영항을 미쳐 오류들이 범잡을 수 없이 늘어나기도 하고 말이다.
또한 우리는 현재 런타임 시 컴파일 되는 자바스크립트 언어를 이용하고 있지만 만약 컴파일을 사용하는 언어를 사용 할 시 뚱뚱한 인터페이스인 Calculator 에 새 기능이 추가되거나 객체와 상관없는 메소드가 수정되게 되면
수정된 부분과 상관 없는 객체들 마저도 다시 컴파일 해줘야 한다는 단점이 존재한다.
ISP추상화된 클래스와 해당 클래스를 이용해 만든 객체의 관계가 1:1로 잘 대응 될 수록 아키텍쳐의 구조를 명확하게 보는 것이 쉽고
객체와 클래스를 관리하는 것이 더 용이해진다.
class Calculator {
introduce() {
console.log('안녕하세요 저는 계산기입니다');
}
}
class Adder extends Calculator {
add(num1, num2) {
return num1 + num2;
}
}
class Subtracter extends Calculator {
subtract(num1, num2) {
return num1 - num2;
}
}
...
class Devider extends Calculator {
devide(num1, num2) {
return num1 / num2;
}
}
const adder = new Adder();
const subtracter = new Subtracter();
const multiplier = new Multiplier();
const devider = new Devider();
다음처럼 인터페이스와 객체의 관계가 1:1로 잘 대응 될 수록 하여 클래스와 객체 간의 관계를 명확하게 이해하는 것이 가능하다.
항상 기억하자 , 뚱뚱한 인터페이스는 관리하기가 매우 힘들다.
React 에서의 ISPReact 에서의 ISP 는 객체지향에서의 ISP 와 깊은 연관은 없지만
뚱뚱한 요소들과 의존성을 갖고 있는 경우는 자주 볼 수 있다. 예를 들어
props 가 뚱뚱한 경우const users = {
lastName: 'dongdong',
age: 20,
};
export default function GreetingName ({users}) {
return <h1>안녕하세요 {users.lastName} 님 </h1>
}
export default function GreetingAge ({users}) {
return <h1>안녕하세요 {users.age} 살이시군요 </h1>
}
GreetingName , GreetingAge 컴포넌트의 경우는 props 로 뚱뚱한 users 객체를 받는다.
실제 필요한 기능은 users 객체의 일부 정보인데 말이다.
이 때 users 에 새로운 값이 추가되거나 , 기존의 값이 수정이 되게 된다면
본인이 사용하지 않는 property 일지라도 객체가 변경됨에 따라 각 컴포넌트는 불필요한 리렌더링을 겪게 된다.
const users = {
lastName: 'dongdong',
age: 20,
};
export default function GreetingName ({lastName}) {
return <h1>안녕하세요 {lastName} 님 </h1>
}
export default function GreetingAge ({age}) {
return <h1>안녕하세요 {age} 살이시군요 </h1>
}
뚱뚱한 props 를 받는 것이 아니라 본인에게 필요한 내용만 props 를 받음으로서 의존성의 관계를
뚱뚱한 props 가 아닌 필요한 부분에만 의존성을 갖도록 변경해줄 수 있다.
추가적으로 불필요한
state문이나context를 컴포넌트 내부에서 불러오는 등의 경우도ISP를 지키지 못한 경우로 생각 할 수 있을 것이다.