Published on

프론트엔드 개발자로서 1년이 된 2024년 4L's 회고

Authors
  • avatar
    Name
    윤영서
    Twitter

시작하며

올해는 느리다면 느리고, 빠르다면 빠르게 지나간 해였다. 하루하루로 생각하면 느리게 지나갔던 것 같은데, 내가 입사한지 벌써 1년이 되었다 생각하니 정말 시간이 빠른 것 같다. 작년에는 월별로 어떤 성취를 이뤘고 어떤 것들을 느꼈는지에 대해서 회고했는데, 이번에는 4L's 회고를 통해 돌아보려 한다.

4L's 회고는 네 가지 관점에서 한 해를 되돌아보는 방법이다.

Liked (좋았던 점): 프로젝트나 작업에서 성공적으로 진행된 부분이나 긍정적인 경험

Learned (배운 점): 새로운 지식, 기술, 또는 팀원 간의 협력에서 얻은 교훈

Lacked (부족했던 점): 부족한 자원, 정보, 또는 기술 등을 파악하고 개선할 수 있는 방안

Long For (바라는 점): 미래에 개선되었으면 하는 부분이나 바라는 상황을 나누고, 그에 따른 목표를 설정

이제 이 네 가지 관점을 통해 나의 첫 해를 돌아보려 한다.

What I Liked

일과 일상의 분리

2023년 회고에서는 일과 일상을 분리하고 싶다고 이야기했다. 그때는 회사에서 슬랙 알림이 올때마다 핸드폰을 보고, 퇴근 후에도 코드를 작성했다. 기한을 맞추지 못할까봐 걱정되고, 더 나은 코드를 작성하기 위해 노력했지만 그로 인해 일과 일상의 경계가 모호해졌다.

그러나 팀장님과 진행한 1 on 1에서 팀장님께서 나에게 책임감도 크고 혼자 압박을 많이 느끼는 스타일 같아서 번아웃이 올까봐 걱정된다. 주말엔 일 생각을 하지 않고 쉬면 좋겠다.라는 말씀을 하셨다. 그 이야기를 듣고 주말에는 쉬려고 노력했고 이전보다 일과 일상을 분리하게 되었다.

퇴근 후에는 슬랙 알림을 끄고, 주말에는 가능한 한 회사 일은 생각하지 않으려 노력했다. 처음에는 이렇게 하면 업무 효율이 떨어질까 걱정했지만, 충분한 휴식 덕분에 평일에 더 집중해서 일할 수 있었고 업무 시간 내에 최선을 다하는 습관이 생겼다.

앞으로도 좀 더 지속 가능한 개발을 위해 노력하려 한다.

회사생활의 순조로운 적응

첫 회사생활이라 그런지, 초반엔 눈치도 많이 보고 내가 이 팀에 필요한 존재인가에 대한 고민도 많았다. 인간관계도 어색하고 서툴렀지만, 그렇게 서로 어색한 순간들을 지나다 보니 어느새 팀원들과 많이 편해지고 팀의 일원이 되었다는 기분이 든다.

지금까지 두 번의 1 on 1을 두 분의 팀장, 그룹장님과 진행했는데 그럴때마다 나에 대한 좋은 평가가 들려왔다. 매번 부족하다는 생각에 긴장을 했었는데, 그럴때마다 잘하고 있다는 이야기를 들으니 내가 잘 적응하고 있구나 깨달았다.

가장 좋았던 말씀은 능동적으로 일을 찾아 해결해줘서 높게 평가했다., 상태를 매번 잘 보고해줘서 신뢰가 가는 팀원이라고 생각한다.는 말씀이었다.

1주년에 팀장님이 주신 선물

물론 아직도 내가 좋은 팀원인가에 대한 의문은 가지고 있지만, 그런 의문들을 채찍으로 삼아 더 나은 팀원이 되기 위해 노력하고 있다.

훌륭한 동료, 팀장님은 최고의 복지다

회사를 다니면서 항상 감사한 것은 좋은 팀장님과 팀원들이 있다는 것이다. 나의 부족함을 느끼게 해준 당사자들이자, 나를 더 나은 개발자로 성장시켜주는 존재들이다. 다른 사람의 코드를 보고 리뷰를 하는 것이 얼마나 에너지를 많이 소모하는 일인지 잘 알고 있고, 또 그것이 프로젝트 진행 중인 더 바쁜 상황에서는 더더욱 힘든 일이라는 것을 알고 있다. 그럼에도 불구하고 팀원들은 항상 꼼꼼하게 코드 리뷰를 해주었고, 더 나은 방향을 제시해주었다. 이런 피드백들이 쌓여 내가 한 단계 더 성장할 수 있는 밑거름이 되었다.

팀장님께서는 바쁘신 와중에도 내가 성장할 수 있는 기회를 만들어주셨다. 코드 관련해서나 업무적인 고민이 있을 때 여쭤보면 항상 친절하게 답변해주셨다. 며칠전 운영 이슈를 다루면서 컨텍스트 스위칭이 굉장히 많이 일어나는 일을 겪었다. 팀장님의 업무의 10분의 1정도만 겪었는데도 리소스 소모가 크게 느껴졌는데, 팀장님께서는 이런 상황을 일상적으로 다루고 계시면서도 늘 꼼꼼하게 코드 리뷰를 해주시고 팀원들의 질문에 답변해주시는 모습에 더욱 감사함을 느꼈다.

또 같은 팀의 사수분과 동기는 나에게 개발적으로 자극을 주는 존재들이다. 얼마 전 동기가 내게 준 코드 리뷰는 특히 기억에 남는다. 공통 아이템 컴포넌트에 대한 리뷰였는데, 기존 컴포넌트는 default와 성공 케이스만 다루고 있었고 여기에 에러 케이스를 추가해야 했다. 당시 나는 이런 방식으로 구현했다.

type ItemProps = {
  item: ItemType;
  hasError: (item: ItemType) => boolean;
};

const CommonItem = ({ item, hasError }: ItemProps) => {
  return (
    <div>
      {hasError(item) && <ErrorIcon />}
      <span>{item.name}</span>
    </div>
  );
};

동기는 이 코드를 보고 "hasError를 함수로 받는 대신, item 객체 자체에 포함시키면 어떨까요?"라는 리뷰를 남겼다. 에러 판별 함수를 props로 받는 대신, 데이터 자체에 에러 상태를 포함시키자는 제안이었다. 리뷰를 받고 생각해보니, 만약 error 뿐만 아니라 각 아이템의 warning 상태 등이 추가된다면? 그럴 때마다 새로운 판별 함수를 props로 전달하는 것은 좋지 않은 패턴이 될 수 있다는 생각이 들었다. 대신 이렇게 수정했다.

type ItemType = {
  id: number;
  name: string;
  hasError: boolean;
};

const CommonItem = ({ item }: { item: ItemType }) => {
  return (
    <div>
      {item.hasError && <ErrorIcon />}
      <span>{item.name}</span>
    </div>
  );
};

이처럼 동료들과의 코드 리뷰는 단순히 코드를 수정하는 것을 넘어서, 더 나은 설계와 구현 방법을 고민하게 만드는 소중한 기회가 되고 있다.

이런 팀에 속해있어서 정말 감사하다는 생각이 들고, 1인분하는 개발자가 되기 위해 더더욱 노력해야겠다고 생각했다.

What I Learned

누군가는 해야하는 일

개발자로 일하다 보면 긴급하게 처리해야 할 업무나, 우선순위에 따라 인력이 조정되는 프로젝트들을 마주하게 된다.

입사 후 처음으로 맡은 온전한 기능 개발은 B2G 사업의 기능을 구현하는 일이었다. 우리 팀의 주력은 B2B 사업이었기에 B2G 프로젝트는 다소 부차적으로 여겨졌고 팀원들이 모두 B2B 신규 서비스 개발에 집중되는 동안, 나는 혼자서 이 프로젝트를 맡게 되었다.

B2B 신규 서비스가 매우 특수하고 갑작스럽게 진행된 건이었기 때문에 신입인 내게 코드리뷰를 제대로 해줄 수 있는 인원이 없었고 그로 인해 내가 짜고 있는 코드가 올바르게 가고있는 코드인지에 대해 계속해서 의문을 가지며 진행했다. 스크럼을 진행할 때도 나 혼자서만 학습 게시판을 진행하는 상황이 되었고 엎친데 덮친격으로, 약 한달정도 기간동안 B2G 기능 개발이 중단되는 상황이 발생했다.

그때 나에게 할당되는 이슈가 없었는데, 나는 끊임없이 그룹장님께 '내가 맡고 있는 일이 없다'는 것을 어필했다. 내가 한 어필로 인해서 그룹장님께 할당되어있던 운영 이슈들을 내가 맡게 되었고, 다른 팀의 vue2, vue3, next.js app router 등 우리 팀의 기술 스택과는 다른 이슈까지 접할 수 있었다.

일이 없다는 어필때문에 회사 동료분들이 칠판에 장난스럽게 써준 낙서

물론 힘든 상황이었지만, 덕분에 다른 팀의 기술 스택을 경험할 수 있는 기회가 되었다. 또한 직접 할당받은 업무가 아니더라도 능동적으로 일을 찾아 해결하는 방법을 배울 수 있었다. 가장 크게 얻은 것은, 내가 겪었던 일이 누군가는 반드시 해야 했던 일이라는 깨달음이다. 내가 아니더라도 누군가는 B2G 기능 개발을 했을 것이고, 누군가는 중요도가 낮다고 판단되는 일을 하게 되었을 것이다. 작은 일이라도 그것이 팀에 기여하는 의미 있는 일이라는 것을 배웠다. 이는 앞으로도 어떤 업무를 맡게 되더라도 그 가치를 인정하고 책임감 있게 임해야겠다는 다짐을 하게 된 계기가 되었다.

이후 진행했던 그룹장님과의 1 on 1 면담에서 신입임에도 불구하고 주어진 상황에서 최선을 다했고, 능동적으로 일을 찾아 해결하려 했다는 긍정적인 피드백을 받을 수 있었다. 나에겐 위기로 느껴졌던 그 상황이 오히려 나에게 기회가 되었던 시점이었다.

유지보수, 이렇게 하면 어렵다!

코드를 작성하고 리팩토링하면서 느낀 것은, 코드를 처음부터 작성하는 것은 쉽지만 이미 짜여진 코드를 유지보수하는 일은 결코 쉽지 않다는 것이다. 단순한 프로젝트라면 코드만 읽어도 흐름을 파악할 수 있지만, 실제로 마주한 코드들은 도메인 지식이 묻어 있기 때문에 히스토리를 모르니 그렇게 단순하지만은 않았다. 이렇게 도메인의 특수성이 반영된 코드의 경우, 단순히 깔끔한 코드를 작성하는 것을 넘어서 왜 이런 방식으로 구현되었는지를 설명하는 주석이 필요하다는 것을 깨달았다.

이런 주석은 아니다

공통 컴포넌트를 만들어보면서 재사용성과 유지보수성에 대해 많이 고민하게 되었다. 특히 공통 컴포넌트는 제어 컴포넌트(Controlled Component)로 설계하여 상태 관리의 주도권을 부모 컴포넌트에 두어야 한다는 것을 배웠다. 이를 통해 컴포넌트의 동작을 외부에서 더 유연하게 제어할 수 있고, 다양한 상황에서 재사용하기 쉬워진다는 것을 경험했다.

또한 쿼리 팩토리의 필요성을 느꼈다. 현재 우리 레포지토리의 코드는 쿼리키를 상수로 관리하고 있고, queryKey는 policy에 queryFn은 api 함수에 분리되어 있어 이를 관리하기 위해서는 파일을 넘나들며 관리해야 하는 불편함이 있었다. 게다가 쿼리를 래핑한 커스텀 훅을 사용하고 있었는데, 만약 해당 쿼리와 동일한 api와 비슷한 쿼리 옵션을 가진 쿼리를 추가하고 싶다면 커스텀 훅을 추가해야 하는 불편함이 있었고 이는 재사용성에 대한 의문을 가지게 했다.

// policy.ts
export const 쿼리키 = {
  강의_리스트: () => ['강의'],
  강의_상세: (강의_아이디: number) => ['강의', 강의_아이디],
};

// api.ts
export const 강의를_가져오는_함수 = async () => {
  return await apiClient.get(`/lectures`);
};

// use_강의_Query.ts
export const use_강의_Query = () => {
  return useQuery(쿼리키.강의_리스트, 강의를_가져오는_함수);
};

이런 구조로 인해 query invalidation을 해야 할 때는 쿼리키를 일일이 찾아가며 처리해야 했다. 예를 들어 강의를 수정한 후에 강의 목록과 상세 정보를 모두 갱신해야 하는 경우, policy 파일에서 관련된 쿼리키들을 찾아 각각 invalidate 해주어야 했다. 이는 코드의 유지보수성을 떨어뜨리고 실수의 여지를 만들었다.

// 강의 수정 후 invalidation
queryClient.invalidateQueries(쿼리키.강의_리스트());
queryClient.invalidateQueries(쿼리키.강의_상세(강의_아이디));

이후에도 언급하겠지만, 2025년 상반기에는 이러한 문제들을 해결하기 위해 쿼리 팩토리 도입을 진행할 예정이다. 쿼리키, API 함수, 옵션들을 하나의 팩토리 함수로 통합하여 관리함으로써 코드의 재사용성과 유지보수성을 높일 수 있을 것으로 기대된다.

What I Lacked

기술적 성장

지난해 입사 후 2023년 회고를 작성했을 때는 개발자 경험(DX)을 개선해보고 싶다는 포부가 있었다. 하지만 2024년은 우리 팀이 굉장히 바쁜 해였다. 조직이 개편되면서 새로운 프로젝트들이 들어오고, 업무의 방향도 조금씩 다르게 바뀌었다. 그러다 보니 운영 이슈와 새로운 프로젝트들을 처리하느라 리팩토링이나 새로운 기술 도입을 시도하기 어려웠다.

다행히도 팀장님께서 내후년 로드맵에 리팩토링과 새로운 기술 도입 계획을 포함시키고 계시다고 말씀해 주셨다. 실제로 남아있던 any 타입을 점진적으로 제거하고 있고, 앞서 말했듯 앞으로 쿼리 팩토리 도입도 계획하고 있다. 비록 당장은 큰 변화를 주도하지는 못했지만, 차근차근 개선해 나갈 수 있다는 희망을 보았다.

다른 한편으로는 내가 작성하는 코드의 구현력과 클린코드 측면에서 아직 부족함을 많이 느꼈다. 동료의 코드를 보면서 이렇게 작성할 수 있구나라는 깨달음을 자주 얻었고, 코드 리뷰를 받을 때마다 왜 이런 생각을 못했을까?하는 아쉬움이 들었다. 하지만 이런 경험들이 오히려 성장의 기회가 되었다. 내가 부족하다는 것을 인정하고, 더 나은 코드를 작성하기 위해 노력하는 계기가 되었다. 코드 리뷰와 동료들의 코드에서 배운 것들을 기록하기 위해 9월부터 TIL을 작성하기 시작했다.

9월부터 시작된 TIL

아직은 많이 부족하지만, 이런 작은 노력들이 언젠가는 큰 성장으로 이어지길 바라본다.

What I Long For

소통 소통 소통!

정리를 해서 이야기하는 일이란 항상 어렵다. 코드의 맥락을 알고있는 같은 개발자에게도, 개발자 용어에 대해 익숙하지 않은 기획자, 디자이너, 사업부 사람들에겐 더더욱 어렵다.

운영 이슈를 해결하면서 특히나 어려움을 겪었다. 맞다 그르다를 정확하게 파악하고 전달하는 것도, 내가 파악한 상황을 코드가 아니라 서로 이해 가능한 말로 전달하는 것도 어려웠다.

그러나 운영 이슈를 해결하면서 점점 더 나은 소통을 위해 노력하고 있다. 먼저 문제 상황을 설명할 때는 기술적인 용어를 최소화하고, 실제 사용자 입장에서 어떤 현상이 일어나는지 설명하려 한다. 또한 해결 방안을 제시할 때는 각 이해관계자의 관점에서 어떤 영향이 있을지 함께 고려하여 전달한다.

특히 슬랙으로 소통할 때는 더욱 신중을 기하고 있다. 문제 상황, 원인, 해결 방안을 명확하게 구분하여 작성하고, 필요한 경우 스크린샷이나 동영상을 첨부하여 이해를 돕는다.

아직은 운영 이슈를 처리하는 것이 어렵고 두렵기도 하지만 2025년에는 더 나은 소통 능력을 가질 수 있길 바라본다.

마치며

1년이라는 시간은 길다면 길고, 짧다면 짧은 시간이었다. 첫 회사, 첫 동료들과 함께한 이 시간 동안 기술적으로도, 인간적으로도 많이 성장할 수 있었다. 때로는 자신감이 부족했지만, 좋은 팀원들 덕분에 한 걸음 한 걸음 나아갈 수 있었다.

앞으로도 많은 어려움과 도전이 있겠지만, 올해의 경험들을 발판 삼아 더 나은 개발자로 성장해 나가고 싶다. 더 깊이 있는 기술력을 쌓고, 더 원활한 소통을 하며, 팀에 더 많은 기여를 할 수 있는 개발자가 되는 것이 나의 목표다.

마지막으로, 한 해 동안 나의 성장을 위해 아낌없는 지원과 조언을 해주신 팀장님과 동료들에게 감사의 말씀을 전하고 싶다. 이런 좋은 팀에서 일할 수 있다는 것이 얼마나 큰 행운인지 다시 한 번 깨닫는다.

2025년에는 어떤 성장과 도전이 기다리고 있을지 기대된다.

2024년 안녕!