이번 과제에서는 SPA(Single Page Application) 구조를 설계하는 과정에서 많은 어려움을 겪었다. 특히 SPA의 전반적인 구조를 어떻게 구성해야 할지에 대한 감이 전혀 잡히지 않았다.
라우팅 시스템을 직접 구현해야 했기 때문에 라우터에 대한 개념이 부족하여 초반에 한참 헤맸다.
더불어 옵저버 패턴, 컴포넌트의 생애주기, 상태 관리와 같은 프론트엔드 개발의 핵심 개념들에 대한 이해도 부족해서, 전체적인 흐름을 설계하고 구현하는 데 특히 어려움을 느꼈다.
이러한 개념들이 제대로 정립되지 않다 보니, 상태가 변경될 때 화면을 어떻게 렌더링해야 하는지, 어떤 구조로 코드를 나누고 흐름을 설계해야 하는지 명확하지 않아 어려움을 크게 느꼈다.
하지만 개념을 이해하고 코드에 적용하려고 해도 정확한 이해가 부족했는지 제대로 활용하지 못했고, 시간이 점점 흘러갔다.
그래서 다른 사람이 작성한 코드를 찾아보고 어떻게 구현했는지 자세히 살펴본 뒤, 그 내용을 참고하여 내 코드에 적용하려고 노력했다.
타인의 코드가 이해되지 않을 때는 직접 코드를 작성한 사람 또는 다른 사람들에게 코드의 흐름 및 설명을 요청했고, 모르는 개념이 나오면 질문하며 개념에 대한 이해를 높이기 위해 노력했다.
SPA 구조 설계에서 가장 먼저 폴더 구조부터 명확하게 정의하는 작업을 진행했다.
UI 컴포넌트를 어떻게 효율적으로 분리할지 고민하며, 컴포넌트 기반 아키텍처 원칙에 따라 폴더와 파일을 체계적으로 나누어 전체 프로젝트의 뼈대를 구성했다.
참고문서
옵저버 패턴 등 복잡한 상태 관리에 대한 이해가 부족해 이를 도입하지 못했고, 대신 이벤트 핸들러에서 상태가 변경될 때마다 수동으로 렌더링을 실행하는 방식으로 문제를 해결했다.
옵저버 패턴(observer pattern)은 주체가 어떤 객체(subject)의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴
여기서 주체란 객체의 상태 변화를 보고 있는 관찰자이며, 옵저버들이란 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 ‘추가 변화 사항’이 생기는 객체들을 의미한다.
🧠 주요 개념 요약
Observable: 상태를 가지고 있고, 상태 변경 시 구독자에게 알림을 보냄
Observer: 상태가 변경되면 알림을 받고 동작하는 쪽
subscribe(): 구독자 등록
notify(): 구독자들에게 알림 전송
예시 코드
// Subject (관찰 대상)
class Observable {
constructor() {
this.observers = []; // 구독자 리스트
this.state = null;
}
// 구독자 추가
subscribe(observer) {
this.observers.push(observer);
}
// 구독자 제거
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
// 상태 변경 및 알림
setState(newState) {
this.state = newState;
this.notify();
}
// 구독자들에게 알림 전송
notify() {
this.observers.forEach(observer => observer.update(this.state));
}
}
과제에서 사용한 예시
export const createObserver = () => {
const observers = new Set();
const subscribe = (callback) => {
observers.add(callback);
};
const unsubscribe = (callback) => {
observers.delete(callback);
};
const notify = (...args) => {
observers.forEach((callback) => callback(...args));
};
return { subscribe, unsubscribe, notify };
};
import { createObserver } from "./createObserver.js";
export function createState(initialState) {
let state = { ...initialState };
const observer = createObserver();
const subscribe = (callback) => {
observer.subscribe(callback);
return () => observer.unsubscribe(callback);
};
const setState = (newState) => {
const prevState = { ...state };
state = { ...state, ...newState };
observer.notify(state, prevState);
};
const getState = () => ({ ...state });
return {
subscribe,
setState,
getState,
};
}
기존 목표 : 기본 과제 통과 (기본 기능 모두 구현하기)
변경 목표 : 기본 과제에서 최대한 많은 기능을 구현하기 (통과 여부 신경 X)
이번 과제를 하면서 가장 크게 느낀 점은, 혼자 고민하기보다 함께 문제를 해결해 나가는 과정 속에서 많은 도움을 받을 수 있었고, 그만큼 배움도 더 깊어졌다는 것이다.
이번 과제에는 심화 과제도 있었지만, 개념이 제대로 잡히지 않았던 나는 우선 기본 과제부터 완성하자는 마음으로 시작했다.
하지만 과제를 처음 시작할 때는 막막함이 컸고, 혼자 해결해보려다 보니 약 이틀 동안 거의 진행이 되지 않았다.
‘기본 과제조차 나 혼자 끝낼 수 있을까?’ 하는 걱정이 들기도 했다.
그래도 포기하지 않고 하나씩 해결해보기로 마음먹고, 다른 사람들에게 기능 구현에 필요한 개념이나 방법을 질문하면서 차근차근 과제를 진행해 나갔다.
진행 속도는 느렸지만, 그 과정에서 단순히 문제를 해결하는 것보다도 이전에 잘 몰랐던 개념들을 이해해가며 기능을 구현하는 경험 자체가 더 중요하다는 것을 느꼈다.
무작정 구현하기보다는, 개념을 정확히 이해하고 직접 적용해보는 과정이 훨씬 의미 있었다.
과제 제출일이 다가왔을 때는 "하나라도 더 구현해보자"는 마음으로 최대한 마무리를 지었다.
비록 모든 기능을 완성하지는 못했지만, 하나의 기능을 제대로 구현하기 위해 그 동작 원리를 이해하고 직접 개발해보는 과정 자체가 큰 배움의 시간이 되었다.
오.. 저도 이번 과제 하면서 개발 개념이 부족하다고 생각했었습니다... 2주차 과제 통과 기대할게요