(λ²μ) SOLID μμΉμΌλ‘ 리μ‘νΈ ν μμ±νκΈ°
μ΄λ»κ² νλ©΄ μ΅μ ν λ μ»΄ν¬λνΈ μ€κ³λ₯Ό ν μ μμκΉ, μ΄ λΆλΆμ λν΄μ 맀μΌμ΄ λ°°μμ κ³Όμ μ΄κ³ νμ κΆκΈνλ€. κ΄λ ¨ν΄μ, SOLID κ°μ²΄μ§ν₯ μμΉμ νμ©νμ¬ λ¦¬μ‘νΈμ μ΅μ ν λ 리μ‘νΈ ν μ μμ±ν μ μλ μ 보λ₯Ό μ λ¬ λ°μ μ 리 μ°¨μμΌλ‘ μμ±νκ² λμλ€.
SRP - Single Responsibility Principle
λͺ¨λμ λ¨ νλμ μ‘ν°λ§ λ΄λΉν΄μΌ ν©λλ€.
import { useState } from 'react';
import { getUser, getTodoTasks } from 'somewhere';
// useUser ν
μ λ μ΄μ todo taskλ₯Ό κ°μ Έμ€λ μμ
μ λ΄λΉνμ§ μμ΅λλ€.
const useUser = () => {
const [user, setUser] = useState();
useEffect(() => {
const userInfo = getUser();
setUser(userInfo);
}, []);
return { user };
};
// Todo taskλ₯Ό κ°μ Έμ€λ μμ
μ κ·Έ μμ μ κ³ μ ν ν
μ΄ μνν©λλ€.
// μ΄ ν
μ μ€μ λ‘ λ³λ νμΌμ μμ΄μΌ ν©λλ€. νλμ νμΌμλ νλμ ν
λ§ λμΈμ!
const useTodoTasks = () => {
const [todoTasks, setTodoTasks] = useState();
useEffect(() => {
const tasks = getTodoTasks();
setTodoTasks(tasks);
}, []);
return { todoTasks };
};
OCP - Open / Closed Principle
λ€μ 건λ€μ§ μμ μ μλλ‘ ν κ³Ό μ»΄ν¬λνΈλ₯Ό μμ±νκ³ ,
λ€λ₯Έ ν / μ»΄ν¬λνΈμμλ μ¬μ¬μ©λ§ νμΈμ.
import { useState } from 'react';
import { getUser, updateUser } from 'somewhere';
const useUser = ({ userType }) => {
const [user, setUser] = useState();
useEffect(() => {
const userInfo = getUser();
setUser(userInfo);
}, []);
const updateEmail = newEmail => {
if (user && userType === 'admin') {
updateUser({ ...user, email: newEmail });
} else {
console.error('Cannot update email');
}
};
return { user, updateEmail };
};
import { useState } from 'react';
import { getUser, updateUser } from 'somewhere';
// useUser ν
μ μ΄μ μ΄λ©μΌ μ
λ°μ΄νΈ κΈ°λ₯ μμ΄
// μ¬μ©μλ§ λ°νν©λλ€.
const useUser = () => {
const [user, setUser] = useState();
useEffect(() => {
const userInfo = getUser();
setUser(userInfo);
}, []);
return { user };
};
// μλ‘μ΄ ν
μΈ useAdminμ useUser ν
μ νμ₯νλ©°,
// μ΄λ©μΌμ μ
λ°μ΄νΈνλ μΆκ° κΈ°λ₯μ μ 곡ν©λλ€.
const useAdmin = () => {
const { user } = useUser();
const updateEmail = newEmail => {
if (user) {
updateUser({ ...user, email: newEmail });
} else {
console.error('Cannot update email');
}
};
return { user, updateEmail };
};
LSP - Liskov Substitution Principle
ν / μ»΄ν¬λνΈλ₯Ό νμ₯νλ λͺ¨λ ν κ³Ό μ»΄ν¬λνΈλ propsλ₯Ό λ°μλ€μ¬μΌ ν©λλ€.
λ°νκ°λ λ§μ°¬κ°μ§μ λλ€.
import { useState } from 'react';
import {
getFromLocalStorage,
saveToLocalStorage,
getFromRemoteStorage,
} from 'somewhere';
// 리μ€μ½νλ ν
μ μΈν°νμ΄μ€(λ³μ μ΄λ¦)μ μΌμΉμν€κΈ° μν΄μ
// λ°μ΄ν° μν λ³μμ μ΄λ¦μ localDataλ‘ λ³κ²½νμ΅λλ€.
const useLocalStorage = ({ onDataSaved }) => {
const [localData, setLocalData] = useState();
useEffect(() => {
const storageData = getFromLocalStorage();
setLocalData(storageData);
}, []);
const saveToStorage = newData => {
saveToLocalStorage(newData);
onDataSaved(newData);
};
// μ΄ ν
μ μ΄μ "data" λμ "localData"λ₯Ό λ°νν©λλ€.
return { localData, saveToStorage };
};
// 리μ€μ½νλ useLocalStorageμ νλ‘ μΈν°νμ΄μ€μ μΌμΉμν€κΈ° μν΄
// μ΄ ν
μ onDataSaved μ½λ°±μ μΆκ°νμ΅λλ€,
const useLocalAndRemoteStorage = ({ onDataSaved }) => {
const [localData, setLocalData] = useState();
const [remoteData, setRemoteData] = useState();
useEffect(() => {
const storageData = getFromLocalStorage();
setLocalData(storageData);
}, []);
useEffect(() => {
const storageData = getFromRemoteStorage();
setRemoteData(storageData);
}, []);
const saveToStorage = newData => {
saveToLocalStorage(newData);
onDataSaved(newData);
};
return { localData, remoteData, saveToStorage };
};
ISP - Interface Segregation Principle
μ¬μ©νμ§ μλ λ©μλμ μμ‘΄νλλ‘ μ½λλ₯Ό κ°μ ν΄μλ μ λ©λλ€.
// λμ 1
// μ΄ μΈν°νμ΄μ€μλ λ€μκ³Ό κ°μ λ¬Έμ κ° μμ΅λλ€.
// μμ±μ΄ μΈν°νμ΄μ€μ μΌλΆ μλΉμμκ² νμμμλ λΆκ΅¬νκ³
// μ νμ μμ±μ΄ ν¬ν¨λμ΄ μμ΅λλ€.
interface Website {
companyName?: string;
ownerFirstname?: string;
ownerFamilyName?: number;
domain: string;
type: string;
}
// λμ 2
// μ΄κ²μ μλ μΉμ¬μ΄νΈ μΈν°νμ΄μ€κ° μ¬λμ λ§κ² μ΄λ¦μ΄ λ°λ κ²μ
λλ€.
// μ¦, μ΄μ μ½λμ ν
μ€νΈλ₯Ό μ
λ°μ΄νΈν΄μΌ νκ³
// μ μ¬μ μΌλ‘ λͺ κ°μ§ λ²κ·Έκ° λ°μν μ μμ΅λλ€.
interface PersonWebsite {
ownerFirstname: string;
ownerFamilyName: number;
domain: string;
type: string;
}
// νμ¬μμ μ¬μ©ν μ μλ μλ‘μ΄ μΈν°νμ΄μ€μ
λλ€.
interface CompanyOwnedWebsite {
companyName: string;
domain: string;
type: string;
}
interface Person {
firstname: string;
familyName: string;
age: number;
}
interface Company {
companyName: string;
}
interface Website {
domain: string;
type: string;
}
Dependency Inversion Principle, DIP
κ³ μμ€ λͺ¨λμ μ μμ€ λͺ¨λλ‘λΆν° μ무κ²λ κ°μ Έμ€μ§ λ§μμΌ νλ©°,
λ λ€ μΆμνμ μμ‘΄ν΄μΌ ν©λλ€.
const withAuth = (Component) => {
return (props) => {
const { user } = useContext(AuthContext)
if (!user) {
return <LoginComponent>
}
return <Component {...props} user={user} />
}
}
const Profile = () => { // Profile μ»΄ν¬λνΈ... }
// withAuth HOCλ₯Ό μ¬μ©νμ¬ Profile μ»΄ν¬λνΈμ userλ₯Ό μ½μ
ν©λλ€.
const ProfileWithAuth = withAuth(Profile)