
토스 Frontend Fundamentals 모의고사 2회차, 예측 가능한 코드를 다시 생각하다

지난 1회차 모의고사에서 꽤 큰 자극을 받았습니다. 토스가 생각하는 “좋은 코드”를 직접 체험해볼 수 있었거든요. 그래서 2회차 소식을 듣자마자 망설임 없이 신청했습니다.
그런데 이번엔 결이 좀 달랐어요. 처음부터 구현하는 게 아니라, 이미 돌아가는 코드를 리팩토링하는 과제였거든요. 같은 원칙을 다른 맥락에서 다시 만나니, 1회차 때 머리로만 이해했던 것들이 훨씬 깊이 와닿더라고요.
이번 글에서는 2회차 모의고사를 통해 다시 한번 깨달은 것들을 정리해보려 합니다.
이번엔 리팩토링이었다
1회차는 적금 계산기를 처음부터 구현하는 과제였어요. 빈 화면에서 시작해서 설계부터 구현까지 전부 제 판단으로 만들어가는 경험이었죠.
2회차는 달랐습니다. 이미 동작하는 코드가 주어졌고, 그걸 더 나은 구조로 개선하는 게 과제였어요. 처음부터 만드는 것과 누군가의 코드를 읽고 개선하는 것은 완전히 다른 근육을 쓰더라고요.
해설도 더 풍성해졌습니다. 1회차에서는 한재엽님이 처음부터 과제를 함께 풀어주셨는데, 2회차에서는 한재엽님과 문동욱님 두 분이 각각 다른 관점에서 해설을 해주셨어요. 한재엽님은 UI를 먼저 이해하고 이상적인 인터페이스를 설계하는 관점, 문동욱님은 예측 가능한 코드를 작성하는 관점에서 풀어주셨습니다.
“사람은 코드를 읽는 게 아니라 예측한다”
문동욱님의 이 한마디가 2회차의 핵심이었다고 생각해요.
우리가 코드를 볼 때, 한 줄 한 줄 정독하지 않잖아요. 파일명을 보고 “아, 여기에 이런 로직이 있겠구나” 예측하고, 함수명을 보고 “이건 이런 동작을 하겠지” 짐작하면서 읽어나가거든요. 그런데 그 예측이 자꾸 틀리면? 매번 멈추고 다시 읽고, 맥락을 파악하느라 시간을 쓰게 됩니다.
쉽게 비유하면 이런 거예요. 처음 가는 건물에서 “화장실”이라고 적힌 문을 열었는데 회의실이 나오면 당황하잖아요. 코드도 마찬가지더라고요. 이름과 실제 동작이 다르거나, 예상치 못한 곳에 중요한 로직이 숨어 있으면 그때마다 개발자의 흐름이 끊기는 거죠.
그래서 1회차에서 배웠던 추상화, 캡슐화, 네이밍 같은 원칙들이 결국 하나로 수렴한다는 걸 느꼈습니다. 전부 예측 가능한 코드를 만들기 위한 거였어요. 추상화를 잘하면 세부 구현을 몰라도 동작을 예측할 수 있고, 네이밍이 명확하면 코드를 열어보기 전에 역할을 짐작할 수 있으니까요.
1회차 때는 이런 원칙들을 개별적으로 이해했는데, 2회차에서 “예측 가능성”이라는 하나의 축으로 연결되는 느낌을 받았습니다.
화면을 보면 코드가 보여야 한다
한재엽님이 1회차에서도 강조하셨던 원칙이에요. UI에 보이는 것과 코드 구조가 1:1로 매핑되어야 한다는 것.
1회차 때 처음 들었을 때는 “아, 컴포넌트를 화면 구조랑 맞추면 되는구나” 정도로 받아들였어요. 그런데 2회차에서 리팩토링을 하면서 이 원칙을 다시 만나니 체감이 달랐습니다.
이미 만들어진 코드를 개선해야 하니까, 먼저 화면을 이해하고 “이상적인 구조는 어떤 모습일까?”를 떠올린 다음, 현재 코드와의 간극을 좁혀가는 과정을 겪었거든요. 구현할 때는 자연스럽게 코드부터 쓰게 되는데, 리팩토링에서는 화면을 먼저 봐야 한다는 게 더 선명하게 다가왔어요.
한재엽님이 1회차에서 “지도의 축척을 바꾸듯이” 추상화 레벨을 조절하라고 비유해주셨는데요. 2회차에서 직접 리팩토링하면서 그 비유가 비로소 실감이 났습니다. 페이지 컴포넌트에서 전체 구조가 한눈에 보여야 하고, 세부 구현은 각 컴포넌트 안에서 확인할 수 있어야 해요. 세계 지도에서 아파트 호수까지 보이면 안 되는 것처럼요.
결국 이것도 예측의 문제더라고요. 화면과 코드가 닮아 있으면, 개발자가 화면을 보고 “이 부분은 코드에서 여기 있겠구나” 예측할 수 있으니까요.
리팩토링의 진짜 의미
1회차 때도 느꼈지만, 2회차에서 더 확실해진 게 있어요. 리팩토링은 파일을 나누는 게 아니라는 것.
한 파일에 코드가 많으면 본능적으로 쪼개고 싶어지잖아요. 저도 그랬거든요. “이 파일 너무 기니까 hooks 폴더 만들고, components 폴더 만들어서 분리하자.” 이런 식으로요.
그런데 해설을 들으면서 다시 생각하게 됐어요. 파일을 나누는 것 자체가 목적이 되면, 오히려 코드를 이해하기 더 어려워질 수 있다는 거예요. 연관된 로직이 여러 파일에 흩어져 있으면 하나의 기능을 파악하기 위해 이 파일 저 파일 돌아다녀야 하니까요.
정말 중요한 건 왜 나누는지였습니다. 책임이 명확하게 다른 것들을 분리하는 건 좋은 리팩토링이에요. 하지만 단순히 코드 줄 수가 많다는 이유만으로, 또는 폴더 구조가 깔끔해 보이기를 원해서 나누는 건 형식적인 분리에 불과하다는 걸 깨달았습니다.
1회차에서 “추출이 아닌 추상화를 하자”는 말씀을 들었을 때도 비슷한 느낌이었는데, 2회차에서 리팩토링이라는 맥락 위에서 다시 만나니 이 판단 기준이 더 선명해졌어요.
두 번의 모의고사를 거치며
1회차에서 처음 만난 원칙들 — UI-코드 1:1 매핑, 추상화와 추출의 차이, 적절한 캡슐화 — 은 당시에도 와닿았지만, 솔직히 머리로 이해한 수준이었던 것 같아요.
2회차에서 같은 원칙을 리팩토링이라는 다른 맥락에서 다시 만나니, 그때서야 진짜 체감이 되더라고요. 특히 문동욱님의 “예측 가능한 코드”라는 프레임이 생기면서, 흩어져 있던 원칙들이 하나의 축으로 연결되는 느낌이었습니다.
같은 말을 들어도 경험이 쌓이면 다르게 와닿는다는 걸 다시 한번 느꼈어요. 1회차 때 “UI와 코드를 1:1로 매핑하라”는 말이 2회차에서는 “그래야 개발자가 예측할 수 있으니까”로 이어졌고, “추출이 아닌 추상화를 하라”는 말이 “형식적인 분리가 아닌 책임 기반의 분리를 하라”로 더 구체화되었거든요.
마치며
두 번의 모의고사를 거치며 제가 얻은 가장 큰 배움은 단순합니다. 좋은 코드의 기준은 결국 예측 가능성이라는 것. 네이밍, 추상화, 컴포넌트 구조, 리팩토링 판단 기준까지 전부 “이 코드를 처음 보는 개발자가 예측할 수 있는가?”라는 질문으로 돌아온다는 거예요.
이 원칙 덕분에 적어도 판단의 기준은 하나 더 생겼습니다. 앞으로 코드를 작성하거나 리뷰할 때 “이걸 처음 보는 사람이 예측할 수 있을까?”를 먼저 떠올려보려고요.
혹시 다음에도 모의고사가 열린다면 꼭 참여해보세요. 매번 같은 원칙을 말하는 것 같아도, 다른 과제 위에서 만나면 전혀 다르게 느껴지거든요.
궁금하신 점이 있다면 아래 댓글로 남겨주세요!👇

