
“분명 똑같이 코딩을 했는데, 왜 내 화면에만 에러가 뜨지…?”
아마 많은 주니어 개발자분들이 겪어보셨을 겁니다.
그 이유는 React의 '사용법'은 익혔지만, 그 '동작 원리'는 건너뛰었기 때문입니다. 원리 없는 사용법은 에러 앞에서 방향성을 잃어버리기 쉽습니다. 그렇기에 AI에게 '어떻게' 고치는지를 물을 때,'왜' 이런 일이 일어났는지 근본을 파악할 수 있어야 하죠.
AI에게 명령만 내리는 시도가 아닌, 문제의 근원을 파고드는 힘을 기르는 것. 그것이 바로 우리가 지향해야는 시니어 개발자의 모습일 겁니다. 이 글은 '어떻게'를 넘어 '왜'를 이해하는 힘을 기르기 위해, 그리고 그 첫걸음으로, 지식의 뿌리가 되는 핵심 '용어'들부터 정복해보려고 합니다.
회의에서 "이건 서버 문제가 아니라 클라이언트 단에서 해결해야 할 문제 같아요."라는 말을 들어보셨을 겁니다. 여기서 “클라이언트(Client)”란 쉽게 비유하자면 식당(서버)에 가서 음식을 주문하는 '손님'과 같습니다. 프론트엔드 세계에서 이 손님은 바로 사용자가 보고 있는 웹 브라우저(크롬, 사파리 등)를 의미하죠.
클라이언트는 사용자의 클릭이나 입력을 서버에 전달하고, 서버로부터 받은 HTML, CSS, JS 같은 데이터를 해석해서 우리 눈에 보이는 화면으로 그려주는 역할을 합니다. 프론트엔드 개발자의 주된 업무 공간인 셈입니다. 그래서 실제 대화에서 "사용자 정보를 클라이언트에 저장하면 보안에 취약하니, 서버에서 관리하는 게 맞습니다." 와 같이, 사용자 브라우저 환경을 지칭할 때 이 용어를 사용합니다.
이때, 클라이언트(브라우저)는 서버로부터 코드를 받아오지만, 코드를 그대로 이해하진 못합니다. 대신 자신만의 방식으로 구조를 파악하고 설계도를 만드는데, 그것이 바로 DOM입니다.

"리액트는 가상 DOM을 사용해서 실제 DOM 조작을 최소화합니다." 브라우저가 HTML 코드를 읽고, 각 태그를 조작 가능한 '객체' 형태로 펼쳐놓은 설계도입니다. JavaScript는 이 설계도를 보고 특정 부분을 찾아서 내용을 바꾸거나(조종 스틱), 새로운 것을 추가할 수 있습니다.
"문서(Document)를 객체(Object) 형태로 만든 모델(Model)"이라는 뜻 그대로입니다. document.getElementById() 같은 명령어로 HTML 요소를 제어할 수 있는 이유가 바로 브라우저가 이 DOM 구조를 만들어두었기 때문입니다. DOM을 직접 자주 바꾸는 건 비용이 많이 드는(느린) 작업이라, 요즘 라이브러리들은 이를 효율적으로 처리할 수 있도록 다양하게 나오고 있습니다.

"이 버튼은 컴포넌트 재사용을 하는 것이 좋겠어요."라는 대화를 들어보신 적이 있을 겁니다. “컴포넌트(Component)”는 DOM이라는 거대한 성을 만들기 위해 미리 기능별로 만들어두는 하나의 '블록'과 같습니다. 버튼, 검색창, 프로필 사진 등을 독립된 부품으로 만들어두고 필요할 때마다 조립해 페이지를 완성하는 아주 중요한 개념 중 하나입니다.
하나의 컴포넌트에는 보통 HTML, CSS, JavaScript 기능이 하나로 묶여 있어, 복잡한 웹 페이지도 체계적으로 관리할 수 있습니다. 따라서 "이 페이지는 너무 많은 기능을 한 컴포넌트에 담고 있어요. 여러 개의 작은 컴포넌트로 분리하는 리팩토링이 필요해 보입니다."와 같이 코드 개선 방향을 제안할 때 유용하게 사용됩니다.
개발 중 "상태는 바뀌었는데 화면이 다시 렌더링되지 않아요." 와 같은 문제가 발생하는 경우가 있습니다. “렌더링(Rendering)”이란, 앞서 만든 컴포넌트들을 조합하여 브라우저가 사용자 눈에 보이는 실제 픽셀로 그려내는 모든 과정을 뜻합니다. 마치 설계도를 보고 실제 건물을 짓는 것과 같죠. 렌더링은 페이지를 처음 표시할 때만 일어나는 것이 아니라, 사용자의 행동으로 상태가 바뀌었을 때 변경된 부분을 다시 그려주는 '리렌더링(Re-rendering)'을 포함합니다.
이 렌더링 과정을 얼마나 효율적으로 관리하느냐가 프론트엔드 성능의 핵심이기에, "불필요한 렌더링이 너무 자주 일어나서 성능이 느려지네요. 최적화 작업이 필요합니다." 와 같이 성능 문제를 진단할 때 핵심적인 용어로 사용됩니다.
CSR (Client-Side Rendering, 클라이언트 사이드 렌더링)은 최초 요청 시, 브라우저가 화면 렌더링에 필요한 로직이 담긴 JavaScript 파일과 최소한의 HTML을 받아오는 방식입니다. 이후 모든 렌더링은 브라우저(클라이언트)가 JavaScript를 직접 실행하여 동적으로 DOM을 생성하고 화면을 그려냅니다.
이 방식은 첫 페이지 로딩 시 관련 스크립트를 모두 내려받아야 하므로 초기 로딩 속도가 느릴 수 있지만, 로딩이 완료된 후에는 필요한 데이터만 서버에 요청하며 화면을 빠르게 전환할 수 있다는 장점이 있습니다.
반면, SSR (Server-Side Rendering, 서버 사이드 렌더링)은 사용자가 페이지를 요청할 때마다 서버에서 해당 페이지를 즉시 렌더링할 수 있는 '완성된 HTML' 파일을 만들어 브라우저로 보내주는 방식입니다. 브라우저는 완성된 HTML을 바로 표시할 수 있으므로, 사용자가 콘텐츠를 매우 빠르게 볼 수 있습니다.
프론트엔드 개발자라면 백엔드 개발자와 소통할 수 있어야 합니다. 이 때 제일 중요한 개념은 “API(Application Programming Interface)”로, API는 화면을 그리는 클라이언트와 데이터를 가진 서버 사이의 공식적인 '소통 창구'와 같습니다. 우리는 API 명세서라는 메뉴판을 보고 정해진 방식으로 데이터를 요청하고, 서버는 그 결과를 응답으로 보내주죠.
덕분에 프론트엔드 개발자는 서버의 복잡한 내부를 몰라도 필요한 데이터를 받아와 화면에 표시할 수 있습니다. 그렇기 때문에 "이 API는 응답 속도가 너무 느린데, 백엔드에 성능 개선을 요청해야겠어요." 와 같이 협업의 기준으로 삼는 중요한 용어입니다.

비동기란, 코드가 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 것, 즉 병렬적으로 Task를 수행하는 방식을 의미합니다. 만약 동기(Synchronous) 방식으로 처리한다면, 서버에서 데이터가 올 때까지 웹사이트 전체가 '먹통'이 되겠죠.
비동기 처리는 이처럼 시간이 걸리는 작업을 기다리는 동안에도 다른 작업을 멈추지 않게 하여 쾌적한 사용자 경험을 만드는 기술입니다. 요청을 보낸 후에는 응답 여부와 무관하게 Task가 동작되므로 실행이 되는 시간 동안에 다른 Task를 할 수 있어 효율적으로 사용이 가능합니다. 그러나 비동기 처리에 콜백 패턴을 사용하게 되면 콜백 함수가 중첩되면서 “콜백 헬“이라는 단점이 발생합니다.
이때 콜백(Callback)은 이름 그대로 '나중에 호출(Call Back)되는 함수'를 의미합니다. 조금 더 정확히는, 다른 함수의 인자(Argument)로 전달되어, 그 함수의 내부에서 특정 작업이 끝난 후에 실행되는 함수를 말합니다.
이때 Promise를 사용하는데요, Promise는 비동기적으로 실행하는 코드의 결과물을 알려주는 객체입니다. Promise는 생성자 함수처럼 객체를 만들 수 있습니다.
"데스크탑에서는 잘 보이는데, 모바일 화면에서는 레이아웃이 다 깨지네요. 반응형 처리가 필요해요." 이 말은 접속하는 기기의 화면 크기에 따라 웹 페이지의 레이아웃과 디자인이 최적화 되지 않았기 때문입니다. “반응형 웹”은 기기의 화면 크기에 따라 웹 페이지의 레이아웃과 디자인이 최적화된 형태로 변하는 웹사이트를 말합니다.
과거처럼 PC와 모바일용 웹사이트를 따로 만들 필요 없이, 하나의 소스 코드로 CSS 미디어 쿼리 등을 사용해 다양한 화면 크기에 대응하는 것이죠. 이는 유지보수 효율과 사용자 경험 모두를 잡는 효율적인 방안입니다. 그렇기에 디자이너와 "이 부분은 모바일로 볼 때 가로 스크롤이 생기지 않도록 반응형 시안을 다시 한번 확인해주실 수 있나요?"와 같이 소통하며 완성도를 높여야 합니다.
누구에게나 처음인 순간은 있습니다. 글을 작성해보면서 제가 놓쳤던 부분을 다시한번 깨닫게 되는 것 같네요. 제가 글을 작성하면서 공부가 되었던 것처럼 다른 분들도 처음 용어를 접근하는 데 있어 조금이나마 도움이 되었으면 합니다.
시니어 개발자가 되는 그날까지 모두 화이팅하십쇼!