코딩테스트는 실무에 도움이 된다 (회사 코드 리팩토링)

dodog·2023년 8월 12일
3

문제 해결 기록

목록 보기
2/3

최근 코딩 테스트를 많이 풀면서 기본적인 자료구조의 내장 메서드에 대한 이해도가 엄청 많이 올라갔다.
이 높아진 이해 덕분에 회사 코드를 리팩토링 하는데 엄청 많은 도움을 받을 수 있었다.
그래서 이를 리팩토링에 어떻게 잘 활용했는지 한번 기술해보려 한다.

1. 배열 내장 메서드인 reduce 활용

아래는 회사 코드를 변형하여 로직만 가져온 코드다

  const forwards = players.filter((player) => player.role === 'forward');
  const midfielders = players.filter((player) => player.role === 'midfielder');
  const defenders = players.filter((player) => player.role === 'defender');
  const goalkeepers = players.filter((player) => player.role === 'goalkeeper');

위의 코드처럼 같은 배열을 4번이나 반복하여 filter하는 것이 불편하게 느껴졌다.
한번만 반복문을 돌려서도 충분히 만들 수 있을 것 같았기 때문이다.

그러나 이 코드를 작성할 때는 마땅히 방법을 찾지 못하여 그냥 넘어갔었다.
하지만 이번에 다시 코드를 봤을 때는 reduce로 해결할 수 있겠다는 생각이 바로 들었다.

최근 코딩테스트를 자주 풀면서 reduce 메서드에 대한 이해가 깊어졌는데
기존에는 arr.reduce((a,b)=>a+b) 이렇게 밖에 사용할 줄 몰랐으나
이제 reduce의 acc, cur 그리고 초깃값의 개념에 대해서 완벽하게 이해를 하게 되었다.

그래서 초깃값을 잘 지정해두고 reduce 콜백 내부에서 switch 문으로 분기처리를 하면 될 것 같았다.

const { forwards, midfielders, defenders, goalkeepers } = players.reduce(
    (acc, player) => {
      switch (player.role) {
        case 'forward':
          acc.forwards.push(player);
          break;
        case 'midfielder':
          acc.midfielders.push(player);
          break;
        case 'defender':
          acc.defenders.push(player);
          break;
        case 'goalkeeper':
          acc.goalkeepers.push(player);
          break;
        default:
          acc.all_rounders.push(player);
          break;
      }
      return acc;
    },
    {
      forwards: [],
      midfielders: [],
      defenders: [],
      goalkeepers: [],
    } as Record<string, Player[]>,
  );

이렇게 초깃값을 key는 각 포지션으로 value는 빈 배열로 설정해두고
players 배열에 반복문을 돌면서 각 case에 맞는 배열에 push해주고 수정된 acc를 리턴했다.

기존 코드와 비교했을 때 같은 배열을 4번이나 반복하던 것을 단 한번으로 줄일 수 있었다.
코드가 길어졌다는 단점이 있으나 로직만 다른 파일로 분리하면 될 것 같아서 매우 만족스러웠다.

2. 객체 메서드를 활용하여 객체 반복문 돌리기

위 코드를 리팩토링 한 뒤에 같은 파일에서 또 다른 문제를 발견했다.

<h3>forwards</h3>
<ul className="list">
	{forwards.map((player) => <PlayerCard key={player.key} />))} 		
</ul>
<h3>midfielders</h3>
<ul className="list">
	{midfielders.map((player) => <PlayerCard key={player.key} />))} 		
</ul>
<h3>defenders</h3>
<ul className="list">
	{defenders.map((player) => <PlayerCard key={player.key} />))} 		
</ul>
<h3>goalkeepers</h3>
<ul className="list">
	{goalkeepers.map((player) => <PlayerCard key={player.key} />))} 		
</ul>
        

기존에도 나름 map반복문을 활용해서 코드를 작성해두긴 했지만 이것 역시 하나로 묶을 수 있을 것 같았다.
그러기 위해 일단 위에서 리팩토링 했던 코드를 수정했다.

const { forwards, midfielders, defenders, goalkeepers } = players.reduce(...생략)

이렇게 reduce의 반환 결과인 객체를 바로 구조분해할당으로 받아오는 구조에서

const playerPositionGroups = players.reduce(...생략)

이렇게 구조분해하지 않고 객체를 그대로 넘겨받도록 수정했다.

코딩테스트를 많이 풀면서 시간복잡도를 줄이기 위해 해시맵을 자주 사용하다보니
객체도 반복문을 돌릴 수 있다는 것을 알게 되었기 때문이다.
그래서 객체 메서드인 Object.entries를 활용해서 반복을 제거해보았다.

  {Object.entries(playerPositionGroups).map(([group, list]) => (
      <>
        <h3>{group}</h3>
        <ul className="list">
          {list.map((player) => <PlayerCard key={player.key} />)}
        </ul>
      </>
    ))}

기존에 12줄로 불필요하게 반복된 코드를 6줄로 깔끔하게 줄여서 매우 편안해졌다.
더 좋은 점은 이제 변경이 필요할 때 단 하나의 PlayerCard만 수정하면 된다는 점이다.

정말 훨씬 좋아졌다! 이번 리팩토링은 가독성에 문제가 있었다기보단
코드 성능, 기술적인 문제를 개선할 수 있었다.

이번 경험을 통해서 왜 자료구조 및 JS 기본기가 중요한지 새삼 느낄 수 있었고
조금이라도 좀 더 좋은 코드를 작성하는 개발자가 된 것 같아서 너무 재미있었다.

profile
심리학, 사회문제해결에 관심이 많은 프론트엔드 개발자

2개의 댓글

comment-user-thumbnail
2023년 8월 12일

정리가 잘 된 글이네요. 도움이 됐습니다.

1개의 답글