[Week 1-1] 컴포넌트가 복잡해지는 원인에 대해 고찰해 보기
1-1) 챌린지 메이커 / 코스 커리큘럼 소개
-챌린지 오종택 멘토님-
아직 일을 시작하지 않은 예비 개발자의 입장에서 실무에 도움이 될 활동을 하고자 원티드 프리온보딩을 참여했다.
Reat 기반의 비즈니스 로직과 주니어 개발자들이 가장 약한 컴포넌트 작성법을 배워 개발 생산성을 높이고자 했다.
직접 고민하는 시간이 바로 진정한 의미에서의 챌린지! 💪
지속 가능성을 위하여 절대로 재미 를 잊지 말기! 😄
제일 먼저 챌린지에서 달성하고자 하는 목표를 정확히 이해할 필요가 있었다.
⚽ “1) 채용 과정에서 회사 측에 2) 나의 포텐셜을 3) 측정 가능한 형태로 어필하기”
회사와 지원자 모두 해당하는 내용이다.
서로가 서로에게 필요한지, 서로가 성장 가능한지
이 점에서 지원자는 내가 회사에 필요하고 충분한 포텐셜이 있음을 보여주어야 한다고 생각했다.
Q : "Promise 대신 async/await를 사용한 이유가 있을까요?"
A : "더 좋다고 해서요"
논리적으로 본인의 견해를 밝힐 수 있어야 하므로 간단하게 안다/모른다 보다 직접 사용해 보니 어떤 면에서 좋더라/이렇기 때문에 이러한 상황에선 더 좋더라로 대답하기 위해 노력해야 한다.
따라서 직접 실전 지식을 쌓고 기록으로 남겨 반복적인 학습이 가능하게 하는 것이 방법이 될 수 있다.
1-2) 모든 행복한 가정은 서로 닮았고, 불행한 가정은 제각각 나름으로 불행하다
장사가 잘 되는 식당은 공통점이 있고 안 되는 식당은 저마다 다양한 원인들이 있으리라 생각한다.
좋은 개발자 혹은 잘하는 개발자들도 마찬가지 일 텐데 오늘 챌린지에선 그 공통점으로 최적화된 코드라고 소개했다.
당연한 말이겠지만 그중에서도 가독성, 재사용성을 좋게 하고 유지보수에 용이하게 분리하기 위한 추상화에 대해 알아보았다.
지금까지 작고 나름대로의 큰 프로젝트를 진행하며 적용이 잘 되지 않던 부분이다.
코드를 작성하면서 오류를 잡아내고 추가하고 싶은 기능을 즉흥적으로 작성하다 보니 재사용성이나 변수관리를 제대로 하지 못한 것 같다.
“당신이 만든 시스템은 서로 강하게 연관되어 있고 복잡하게 결합되어서, 아주 사소한 변경에도 몇 주가 걸릴 뿐만 아니라 큰 위험을 감수해야 하지는 않았나?"
- 클린 아키텍처
그렇게 추가에 추가를 하고 코드를 덧대며 작업을 하다보니 기존의 코드를 리펙터링과 같은 최적화 작업을 하기가 어려워졌다. 만약 이 상태에서 다시 작업을 한다 해도 크게 나아질 점이 없다는 게 뻔해 보였다.
기존의 코드를 수정하면 엉뚱한 곳에서 문제가 발생하고 재사용성을 위해 함수 또는 hook으로 분리하면 잘 되던 것이 기똥차게 멈추어 버린다. 엉킨 코드를 풀고 나름 열심히 해보지만 늘어나는 것은 ChatGPT와의 대화들 뿐
“빨리 가는 유일한 방법은 제대로 가는 것이다.”
- 로버트 C. 마틴
https://www.youtube.com/watch?v=SxdOUGdseq4
1-3) [실전 스킬 1] 데이터 / 계산 / 액션만 구분해도 중간은 간다
그렇다면 복잡도 해결을 위한 추상화/최적화는 어떻게 해야 할까요?
챌린지에선 함수 분리를 위해 3가지로 구분할 줄 알아야 한다고 했다.
하나의 함수에서 두 가지 이상의 작업이 이루어지거나 너무 많은 파라미터를 받게 되면 유지보수, 가독성면에서 좋지 않다.
// 사용자의 이름을 환영하는 함수
function greetUser() {
let userName = prompt("안녕하세요! 당신의 이름은 무엇인가요?");
alert("환영합니다, " + userName + "님!");
}
// 사용자를 인사하는 함수 호출
greetUser();
// 사용자의 이름을 받는 함수
function getUserName() {
return prompt("안녕하세요! 당신의 이름은 무엇인가요?");
}
// 사용자를 환영하는 함수
function greetUser(userName) {
alert("환영합니다, " + userName + "님!");
}
// 사용자와 상호작용하여 환영 메시지를 보여주는 부분
let userName = getUserName(); // 사용자의 이름을 받음
greetUser(userName); // 사용자를 환영하는 함수 호출
순수 함수란
1) 입력 값에 대해 항상 동일한 출력값을 반환하며, 2) 부수 효과가 없는 함수입니다.
부수 효과란
함수의 핵심 목적에서 벗어나 외부 세계에 영향을 주는 행위가 포함된 함수입니다.
오늘 내용 중 함수 분리를 위해 가장 중요하다고 생각하는 부분이다.
순수 입력 값에만 의해 결과를 반환하기에 외부의 상태를 변경하지 않는다.
반대로 예를 들어 fetch 함수의 경우 외부 세계와 소통을 하는 함수이기에 부수 효과를 일으킨다.
React에선 이런 부수 효과를 일으키는 장소로 useEffect를 사용한다고 설명한다.
순수 함수와 부수 효과에 대한 개념을 이해했으므로 다음으로 넘어갔다.
1) 데이터 : 이벤트에 대한 사실. 문자열, 객체 등 단순한 값 그 자체.
ex) 사용자가 입력한 이메일 주소, 은행 API로 읽은 달러 수량
2) 계산 : 입력으로 얻은 출력. 순수 함수, 수학 함수라고 부르기도 함.
ex) 최댓값 찾기, 이메일 주소가 올바른지 확인하기
3) 액션 : 외부 세계와 소통하므로 실행 시점과 횟수에 의존. 부수 효과를 일으킴.
ex) 이메일 보내기, 데이터베이스 읽기
- 쏙쏙 들어오는 함수형 코딩
데이터와 계산에서 가급적 액션을 분리하고 액션으로부터 계산을 추출할 수 있다면 그렇게 하라고 설명한다.
즉 서로 다른 기능 혹은 테스트 환경에 있는 것들을 분리해야 한다.
const TodoList = () => {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState("");
const [filter, setFilter] = useState(FilterType.ALL);
const [searchQuery, setSearchQuery] = useState("");
// 액션
const addTodo = () => {
// 계산
const nextTodos = TodosController(todos)
.add({ text, completed: false, id: Math.random() })
.get();
// 액션
setTodos(nextTodos);
setInput("");
};
// 액션
const toggleComplete = (targetTodo) => {
// 계산
const nextTodos = TodosController(todos).toggleComplete(targetTodo).get();
// 액션
setTodos(nextTodos);
};
return ...
이를 위해선 계산과 액션에 대한 구분을 잘해야 한다고 생각한다.
여기서 추가적으로 알 수 있는 점은 순수 함수인 계산은 컴포넌트 밖으로 분리해도 상관이 없고, 액션에 속하는 함수는 부수 효과를 일으키기 때문에 밖으로 분리하기 어렵다는 점이다. 또한 String + Number = String처럼 액션과 계산이 합쳐지면 액션으로 만들어 버린다는 것을 인지해야 한다.
https://www.yes24.com/Product/Goods/108748841
📝 오늘의 3줄 요약
1. 좋은 아키텍처를 만들기 위해 많은 시간과 노력이 필요하다.
2. 기존의 코드를 리펙터링 하는 것은 더 어렵기에 처음부터 클린 코드를 짜는 것에 시간을 투자하자.
3. 주니어 개발자가 할 수 있는 첫번째 단계는 기능별로 함수를 구분하는 것이다.