[Refactoring] 다른사람의 코드를 수정하면서 느낀 것에 대해서

KoEunseo·2024년 3월 11일
0

project

목록 보기
37/37

그간 적지않은 팀프로젝트를 해왔다. 리액트로도, 플러터로도.

리액트를 할 때에는 같이 하는 사람들 실력이 고만고만했고 내꺼하느라 바빠서 다른사람 코드를 자세히 본 적이 딱히 없다. 그리고 다들 취업을 위해 프로젝트를 하다보니 손댈 생각도 못했다.

플러터를 하게 되면서는 상황이 많이 달라졌다. 내가 리액트를 어느정도 숙달되게 할 수 있게 되면서 관심사도 크게 늘어났고, 코드를 짜는 방식도 꽤 많이 달라졌다.

최근 플러터로 인턴십을 하게 되어서 개발자 넷, 디자이너 7~8명이 협업을 하게 되었다. 개발자 중 한명은 자바(백엔드)를 했던 분이고 한명은 현업에서 개발 일을 하던 분이었다. 그리고 한분은 대학생으로 전공자였다.

어찌저찌 각자 화면은 다 개발이 되었고, 커뮤니티 파트를 맡았던 분은 서버와 연동하는 것에 실패했다. get도 안돼서 제가 해봐도 될까요? 양해를 구했었으나... 마감이 닥치면 역시 여기저기서 문제가 발생하는법ㅎ 손도 못댔다.

그리고 성과발표회가 끝나고 아마 나 혼자 리팩토링을 하고 있는데, 커뮤니티를 손보고 있다. 아직 진행중이긴 하지만... 작업하면서 꽤 놀란 부분도 많고, 느낀 부분도 많아서 블로그에 적어놓으려고 한다.

1. 시멘틱 시멘틱 하는 이유

나는 블럭 단위로 뷰를 쌓는다. 의미있는 단위로 묶는다. 거기에 확장성을 생각해서 열어둘 건 열어두고, 사용성을 위해 가릴 건 가린다.
원래 서버와 데이터만 연동하려 했으나... 도저히 안되겠어서 내가 UI 리팩토링을 하게 된 이유중 하나다. 내가 가장 경악했던 그 코드는 지금 없으니, 대략 느낌만 내 보자면...

Row(
  children: [
    Text('답변 0'), //1
    AssetImage('assets/images/2.png'), //2
    Text('60'), //3
    AssetImage('assets/images/Rectangle 1 (2).png'), //4
    Text('80'), //5
    SizedBox(width: 150), //6
    Text('조회 100'), //7
  ]
)

구조따위 버리고 UI가 디자인대로 나오기만 하면 된다고 코드가 외치고있다....ㅠㅠ
거기에 이미지 이름까지 별 의미가 없어 코드만 봤을 때 어디 부분인지 알수가 없다.
나는 2번줄과 3번줄을 Row로 묶고, 4번줄과 5번줄 또한 Row로 묶었다. 그리고 1, 2-3, 4-5번 줄을 하나의 Row로 또 묶었다. 이제 SizedBox는 지우고 가장 상단의 Row에 MainAxisAlignment.spaceBetween 값을 주었다.

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Row(
      Text('답변 0'),
      Row(
        SvgPicture.asset('assets/icons/heart.svg'),
        Text(),
      ),
      Row(
        SvgPicture.asset('assets/icons/bookmark.svg'),
        Text(),
      ),
    ),
    Text('조회 100'),
  ]
)

덤으로 이미지도 바꿨다. png나 jpg는 깨지니 아이콘인 경우에는 가급적 svg를 쓰고있다. 그리고 아이콘 이름이든 이미지 이름이든 의미에 따라 폴더정리, 이름정리가 꼭 되어야한다고 생각한다. 이름을 저따구로 하면 하나하나 클릭해봐야하는수밖에 없다. 어떤건 아직 정리도 안되고 해서 아직 저따구의 assets들을 그냥 둔 부분도 있는데... 사실 보면서 너무 킹받았다....

2. 이름 짓기가 쉬우면 안되는 이유

앞에서 assets 이름에서 봤듯이 이름은 너무 중요하다. 당연히 중요하다는 이야기를 많이 들었고 나도 신경써서 짓는 편이지만 잘 짓는다고 생각하지는 않는다. 그런데 음... 이런 이름이 있어서 그렇게들 강조를 하시는건가 싶었다.

넘버링

card1.dart : card1 이런식으로 넘버링을 하면 써보기 전에는 어떤 카드인지 알 수가 없다.

파일이름과 클래스이름

log_label.dart -> class reviselabel : 파일이름은 log_label인데 내부에 있는 컴포넌트 이름은 완전 다르다. 이러면 코드를 뜯어보거나 써봐야 어떤건지 알 수 있다. 심지어 이 컴포넌트는 버튼으로 쓰이고있다...

참고로 폴더이름이랑 내부 클래스 이름이 다른 거 진짜 열받는다. 컴포넌트가 여러개인 게 아니라면 통일하자. 여러개라면 의미있게 이름을 짓자. 이름만 알아도 컴포넌트를 쓸 수 있어야하는데 파일이름이랑 컴포넌트 이름이 다르면 안그래도 이름지을것도 많고 알아야할 것도 많은데 하나하나 확인하면서 써야한다..

줄임말, 접두사

com-side-* : 줄임말은 되도록 쓰지 말자. btn과 같이 너무 통용되는 거 아니면. com-side-어쩌고 파일을 보고 뭔지 알 수가 없었다. 커뮤니티의 사이드프로젝트의 어쩌고 위젯, 어쩌고 페이지를 의미하는 거였다. 타자치기 귀찮아도... 좀 쳐주자. 그리고 이 경우에는 community 폴더 내에 있는 파일이니 com이든 community든 접두사가 필요 없다고 생각해 파일이름을 바꾸었다. 파일 이름과 내용에 혼동이 오는 경우가 많아서 이게 어디부분이지? 한참 봐야 알 수 있는 경우도 많았다. 그래서 파일이름까지는 건드리지 않으려 했지만... 바꿔버렸다.

일관성

이건 내가 잘 못하는 건데... 일관성있게 이름을 짓는 것이다. 공통 컴포넌트를 만들 때 처음에는 안그랬지만 나중에는 일정한 접두사를 붙여서 썼었다. 내가 만들었지만 어떤건 접두사가 있고 어떤건 없어서 쓸때 참 헷깔린다.

추상화

코드도 그렇고 파일 이름도 그렇고 추상화가 되어야한다. 어떤 역할을 하는 어떤 부분인지 전달할 수 있도록 하자. 이름 지을 때 가장 힘든 부분이다. 정말 어떻게 지어야할지 생각이 안나면 최후의 수단으로 어디서 이 코드를 쓰는지로 이름을 짓는다. 그런데 이건 참 위험한 부분이다. 마이페이지에서만 쓸 줄 알았지만 나중에는 메인페이지나 커뮤니티에서 쓸 수도 있기 때문이다. 그렇기에 나는 역할이나 생김새를 표현하는 식을 주로 사용한다.
예를 들면 이런 식이다. 버튼이 있는데 동그란 모양이고 특정 아이콘이 들어간다. circle_icon_button.dart 이렇게 이름지으면 동그란 모양이고 아이콘이 있는 버튼이구나. 알 수 있다. 이때 특정 아이콘이 주로 들어가지만 확장성을 위해 default값으로 특정 아이콘을 주고, optional 속성으로 아이콘을 주입받을 수 있도록 한다.

class CircleIconButton extends StatelessWidget {
  const CircleIconButton({
    super.key,
    this.onTap,
    this.width = 56,
    this.height = 56,
    this.color,
    this.icon,
    this.assetSvgIcon = 'assets/icons/pencil.svg', //디폴트 아이콘
    this.image,
  });

  final double? width;
  final double? height;
  final void Function()? onTap;
  final Color? color;
  final Icon? icon;
  final String? assetSvgIcon;
  final String? image;

  
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        width: width,
        height: height,
        clipBehavior: Clip.antiAlias,
        decoration: BoxDecoration(
          color: color ?? SLColor.primary.shade90,
          shape: BoxShape.circle,
        ),
        child: _buildChild(),
      ),
    );
  }

  Widget _buildChild() {
    if (icon != null) {
      return icon!;
    }
    if (image != null) {
      return Image.asset(
        image!,
        fit: BoxFit.contain,
      );
    }
    return SvgPicture.asset(
      assetSvgIcon!,
      fit: BoxFit.scaleDown,
    );
  }
}

결국 모든 것은 가독성으로 통한다

내가 깨달은 건 위와 같다. 모든 가르침들이 다 가독성을 위한 것이라는 사실. 사람이 하는 일이다보니 파악을 빨리 할 수 있어야 하고 빨리 사용할 수 있어야한다. 관심사가 분리되고 하나의 책임만을 가져야 한다는 것도 가독성때문이다. 어느 부분에서 에러가 났는지 바로 알 수 있다. 시멘틱하게 하는 이유도 가독성 때문이다. 이름짓기가 어렵고 중요한 이유도 가독성때문이다. 깃허브 이슈, pr을 작성하는 이유도 commit 메시지를 남기는 이유도 가독성 때문이다.

귀찮아하지 말고 같이 일할 다른 사람의 입장에서, 몇달 뒤의 나를 위해서 가독성 좋은 코드를 짜자. 미흡한 것 같다면 pr을 통해 자세하게 설명을 하자. 아니면 코드에 example을 같이 작성해두자.

내가 여러 협업을 진행하면서 알게모르게 이미 깨달은 것들이다. 이번에 다른사람 코드를 아예 속속들이 리팩토링하고 고치면서 더 적나라하게 느꼈을 뿐이다.

profile
주니어 플러터 개발자의 고군분투기

0개의 댓글