[flutter] 짧은 인턴생활을 마치고 🥳 (우수수료생+우수팀 2관왕 했다!!)

KoEunseo·2024년 2월 14일
1

인턴

목록 보기
13/13

우수함을 인정받는다는것 🎉

"이전에"

스팩 스페이스를 기업협업 프로젝트로 진행했을때 우수수료생으로 뽑혔었다.(헤헤) 내가 생각해도 열심히했고... 또 열심히 하는 모습이 꽤나 자연스럽게 기업에 어필되었던 것 같다. 나는 항상 어떤걸 하든 열심히 했는데, 학창시절 절대적으로 평가받던 이후로는 우수어쩌고 이런건 처음 됨. 그때 내가 우수수료생이 되었다는 사실을 전혀 몰랐어서 굉장히 놀랍기도 하고 역시 목소리가 커야 좀 알아주고 하는구나 하는 생각을 했었다...

내성적인 사람으로서 그런 점을 좀 억울해하기도 하고 했던 것 같은데, 지금은 사회생활도 해보고 나이도 먹을만큼 먹어보니 당연하다면 당연한거라는 생각이 들었다.

나 그래도 꽤 성실하고 열심히하고 괜찮은데 왜 성과가 안날까? 개발자가 되기로 결심하고 퇴사한 이후부터 줄곧 꽤 억울했던 것 같다. 나는 어딜가도 우수한 사람 축에 들었었기 때문에 인정받지 못하고 있는 상태가 길어지니 좀.. 힘들었다. 나한테 개발자가 맞는 직업일까? 그냥 계속 일했으면 어땠을까? 그만하고 다시 사무직 직장인으로 돌아갈 준비를 하는 게 더 좋을까?

그런데 이번 기회에 가벼운 우울에서 벗어나 다시 달려볼 용기가 생겼다.

쑥쓰럽다고 꽁꽁 숨어있는데 어떻게 열심히하는지 대충하는지 알 수 있겠어? 다 똑같은 시험을 보고 성적을 매겨서 줄을 세우는 게 아니라면 말이다. '나 여기있어요' 어필하는 몇명, 몇가지만 살피는 것만도 사실 정말 많은 품이 든다.

좋은 협업과 책임감

주도적으로 하지 못하더라도 열심히 따라가기만 해도 좋은 결과를 얻을 수 있다. 주도적이지 못하다라는 의미가 아무런 의견도 내지 못하고 입을 다물고 있는 태도를 말하는 것은 절대 아니다. 구성원으로서 책임감을 가져야한다. 개발자로서 협업 프로젝트를 많이 해보면서 더더욱 책임감의 중요성을 깨닫게 된다.

요즘 사회는 리더십을 가장 쳐주지만 모든 사람이 리더가 될 수 있는건 아니다. 사회가 원하는 리더십은 다만 내것처럼 열심히 할 수 있는 태도를 말하는 것이 아닌가 싶다. 즉 주도적 + 책임감인 것이다.

나는 정말 리더가 되고싶어하지 않는 사람이지만 리더가 되면 정말 열심히 하는 사람이긴 하다. (다만 리더로서는 너무 많은 걸 혼자 짊어지려고 하다가 오히려 역량을 못내는 편인 것 같다. 😂) 리더가 아니더라도 구성원으로서도 열심히 팔로우하는 사람이기도 하다. 리더를 잘 보조(?)하려고 하고 좋은 분위기를 유지하기 위해 노력한다.

왜냐면...

내 경험상 직장에서 "팀의 분위기는 생산성과 직결된다. "

이전 직장에서 리더와 팀원들의 불화가 있었다. 나도 불화를 겪기도 했다. 물론 인간관계에서 불화가 없을 수는 없다. 그런데 이게 공사가 분리되고 각자 역할에 책임을 다해야 회사가 잘 굴러갈텐데 그러기가 쉽지 않다. 여기서 내가 가장 크게 깨달은 점은 일은 회사가 하는 게 아니라 사람이 한다는 점이었다.

나는 내가 할 수 있는 최대한 리더와 다른 팀원들 사이에서 문제가 생기지 않도록 조율했다. 리더에게 불만이 생기자 팀원이 태업을 했기 때문이다... 리더는 문제가 생기지 않게 하기 위해 본인의 몸을 갈아 일했고 병원신세를 져야했다. 스트레스는 말할것도 없다.

이번에 성과발표회 끝나고 플러터 개발자들끼리 저녁식사를 했는데, 다른팀에서 이탈자가 발생했고 분위기가 꽤 험악했던 것 같았다. 자연히 생산성은 낮아지고 결과물이 다소 미숙해 보일 수 밖에 없었을 것이다.

개발자로서의 협업도 마찬가지다.

스팩 스페이스 프로젝트를 할 때, 다들 마음이 붕 뜬 적이 있었다. 나는 그때 프로젝트를 마무리하기위해 정말 미움받을 용기를 내면서 팀원을 채찍질하고 그랬었다. 분위기를 잡기 위해서 '우리팀 분위기 기강 잡아~' 장난식으로 얘기했지만 찐으로도 굳이굳이 불러서 옆에 앉혀놓고 같이 코딩했다. 성과 발표회 전날도 모여서 코딩하고 밤늦게 집에 들어갔다. 우수수료생은 생각 못했고 그냥 마무리를 끝까지 잘 하고 싶었고 프로젝트가 제일 중요하다고 생각했다. 꽤 잘 마무리했다고 생각했는데 우수팀은 하지 못해서 아쉬웠다. 그래도 지금까지 다들 연락하고 지내고, 프로젝트 계속 할 생각이다.

이번 스팩로그 프로젝트 진행할때는 회사에 어필할만한 건이 없었다. 오프라인에 참석도 못했고, 인원도 디자이너들과 함께있다보니 너무 많았고, 기업과 컨택하는 자리 자체가 많지 않았음. 그래서 전혀 기대하지 않았다. 그런데 또 우수수료생으로 선발되었다. 우리팀에 디자이너 포함 셋이나 우수수료생이 되어서 너무 기뻤다. 그리고 더 기뻤던 건 우수팀이 된 거였다.

나 혼자의 성취보다 팀의 성취가 더 기쁜 건 왜일까?

프로젝트에 책임감을 갖고 열심히 했기 때문이라고 생각한다. 또 이건 결과물이 잘 나왔다는 의미기도 하니까. 우수수료생 2관왕은.. 기쁘지만 그걸 성취하기 위해 노력한 건 아니었고 그냥 단지 하다보니 얻어걸린(?) 느낌이랄까.

사실 이번 프로젝트를 하면서 더 자신감이 떨어졌던 게, db나 서버 지식이 부족해서 팀에 기여한 바가 적기 때문이었다. 우리 팀에는 공대생이 둘에 백엔드 교육 수료한사람이 하나, 그리고 프론트만 판 나 이렇게 넷이었는데 백엔드 공부한 이력이 있으신 분이 db설계를 다 하셨다. 포켓베이스 쓰려면 설계가 우선적으로 필요하다..

나는 auth랑 main 파트를 맡았는데 auth를 하면서 생각보다 거기에 시간을 많이 써서 쳐낸 파트가 많다. 디테일하게 신경쓰지 못한 부분도 많고... 하다 막혀서 다른분들께 SOS를 꽤 치기도 했고. issue를 발행해서 오늘안에 해내야지! 했는데 그러지 못한 부분들도 많았다ㅠㅠ
어려운 부분이나 중요한 부분을 맡아서 열심히 했다던가 시간 내에 결과를 냈다던가 했으면 기분이 훨씬 좋았을 것 같은데, 그러지 못해서 아쉬움이 컸다.

그와중에 성과발표회 발표자가 되었고, 열심히 발표자료를 준비했고, 일찍 가서 디자이너랑 발표 준비도 했고, 결과적으로 우수팀으로 선정되었다. 발표점수가 20점은 됐던 것 같은데 내가 또 거기에 기여를 좀 하지 않았을까?? 😁 팀원분들께 계속 프로젝트 하자는 말을 은근 흘렸으나 하겠다고 하신 분은 한분이었고... 다른 한분은 확답은 안주셨는데 아마... 팀장하신 분과 나 이렇게 둘이서 진행하지 않을까 싶다. 😂

두번째 프로젝트: sfaclog

개인적으로 신경쓰며 작업한 요소들

| 1. MVVM

안그래도 어려운 부분이니 폴더구조를 직관적으로 만들었다. 데이터소스 폴더는 pocketbase(서버데이터), Model 폴더는 데이터 타입을 정의하고 가공하는 직렬화, View 폴더는 페이지와 위젯을, ViewModel을 riverpod으로 로컬 데이터를 가지고 있도록 했다.

Datasource: auth store

ViewModel: auth state

ViewModel: auth notifier

이게 가능했던 건 상태관리 툴을 사용했기 때문이다. riverpod을 사용함으로 인해 데이터를 필요할 때만 가져오고, 필요한 곳에서만 사용할 수 있었다. 따라서 책임소재가 명확한, 관심사가 분리된 코드를 작성할 수 있었다. 내가 이렇게 최대한 기능별로 분리하려고 했던 건 실제로 에러가 발생했을때 어디서 발생했는지 찾기 훨씬 수월하기 때문이다. 나는 '책임분리'라는 말을 알게 된 이후로는 꼭 이 지점을 지키려고 노력한다. 문제가 발생할 수 있는 요인이 아주 다양하고 많기 때문에 이정도만이라도 세분화하면 정말로 훨~씬 도움이 된다.

다만 좀 헷깔렸던 부분이랄까 아직도 어떻게 하는 게 좋은지 모르겠는 부분이 있는데, 바로 시리얼라이제이션이다. 직렬화를 어디서 하는 게 좋을까?? 리액트를 하던 버릇(?)으로 서버 데이터는 가공하지 않고 보관만 하고 riverpod에서 로컬 데이터화 할때 직렬화를 하는 방향으로 진행했는데, 좋은 방향이 맞을까? 더 좋은 방법이 있지 않을까?? 로컬상태(유저의 인풋) 또한 riverpod 상태로 관리를 하니 이게 분리가 안되고 혼합된 느낌이라 찝찝함을 이루 말할 수가 없었다...ㅜㅜ

| 2. 개발자를 위한 코드

이번 프로젝트에 앞서서 기업에서 요구받았던 것 중 하나가 공통 컴포넌트를 따로 개발할 것 이었다. 그러니까 그걸... 디자인킷이라고 하더라고. 우리는 monorepo를 선택했고 HEXAGOINAN(육각형) 폴더 내에 sfaclog, sfaclog_widgets 이렇게 두개의 폴더를 만들어서 sfaclog_widgets 내에 공통 컴포넌트를 만들었다.
프로젝트 내에서 같이 컴포넌트와 로직이 섞여있는 상태가 많았는데 이렇게 작업하니까 마치 커스터마이징한 플러터 위젯 패키지를 쓰는 것 같은 느낌이었다. 리액트를 하면서 아토믹 디자인 시스템을 적용해서 프로젝트 구성을 많이 했었는데 이때도 여러 외부 요소들이 잘 분리되지 못했다. 클릭된 '상태' 라던지 콜백 함수라던지...
그런데 이렇게 작업해보니 그런 요소들을 잘 생각해서 잘 '추상화'할 것들에 대해 생각해보게 됐다. 우리 프로젝트에서 명확하게 디자인 시스템이 구성되지 못해서, 다소 자유도가 높을 수밖에 없었지만...(컬러라던가 패딩같은 수치가 제각각이었다) 많이 배웠다.
required는 꼭 필요한 속성에만 부여했고, optional 매개변수와 default값을 적극적으로 사용했다. 그리고 enum을 활용해서 필요한 정보만 쉽게 노출하고 컨트롤하도록 했다. 내가 만든 컴포넌트를 개발자가 편리하게 사용하고 확장할 수 있도록!!

예시: TextFormField : SLInput


가장 위에 있는 형태가 기본적인 형태에 hintText만 설정한 것이다.
팀원들이 잘 사용할 수 있도록 pr도 열심히 작성하고,

이런 식으로 example도 하단에 작성했다.

이 코드는 위의 SLInput 위젯을 확장해서 validate type을 입력받아 hint text와 label을 리턴해주는 컴포넌트다. 용도에 따라 hint를 또 따로 적어주는게 귀찮(...) 아니 관리가 힘들 것 같아 따로 sfaclog_widget으로 뽑아주었다.

class ValidateInputExample extends StatelessWidget {
  const ValidateInputExample({super.key});

  
  Widget build(BuildContext context) {
    TextEditingController controller = TextEditingController();
    final formKey = GlobalKey<FormState>();

    return Form(
      key: formKey,
      child: ValidateInput(
        type: ValidateInputType.passwordConfirm,
        controller: controller,
        validator: (value) {
          if (value == null || value.length < 8) {
            return '현재 비밀번호를 다시 입력해주세요.';
          }
          return null;
        },
      ),
    );
  }
}

| 3. 문서화

issue 티켓 발급

pr 작성


클릭시 해당 pr으로 이동합니다.

issue와 pr의 용도를 확실하게 하려고 노력했다.
이전에는 둘이 뭐가 다른지 잘 모르겠고 그냥 내 맘대로 했었는데 이전 기업 협업 프로젝트에서 피드백을 통해 이제 좀 확실히 알게 됐고 이번 프로젝트에서 제대로 하려고 노력했다.. issue는 진행사항을 정리하고 컨트롤하기 위해(todo list 랄까), pr은 팀원에게 설명하고 알려주기 위해 썼다.

그 외에 배운것

자바스크립트를 할 때는 배우긴 했지만 잘 모르겠었던 class를 dart하면서 이해하게 됐다. 실제로 리액트 프로젝트할 때 한번도 써본적 없었는데 dart에서는 밥먹듯 함. 특히 model 작성을 위해서! 점점 큰 그림을 보면서 구조화된 코드를 작성할 수 있게 된 것 같아 기쁘다.

결과물(시연화면)

| 회원가입 + 온보딩



회원가입 과정에 온보딩이 포함되어있어 auth state, onboarding state를 결합하여 기능을 구현했습니다.
한 페이지에서 IndexedStack을 활용해 5개의 페이지를 이동하는 것 같은 효과를 주었습니다.
각 섹션에서 유저의 입력을 받고 버튼을 누르면 다음 섹션으로 이동하며 입력값을 Riverpod에 업로드합니다.
Onboarding값을 모두 입력받으면 최종적으로 pb 서버에 유저의 정보가 업로드됩니다.

| splash + 로그인



Form 위젯을 사용해 여러 validation이 필요한 TextFormField 값을 핸들링 합니다.
validation통과 여부에 따라 isActive bool 값이 달라지고, 이 값이 true를 반환하면 버튼이 활성화되고,
동시에 onTap에 전달되는 콜백함수가 null에서 로그인 함수로 바뀌게 됩니다.
유저가 로그인함과 동시에 유저 정보를 세팅하게 됩니다.

| 메인


앞서 보여드린 스플래시 페이지에서 메인 페이지에 필요한 데이터를 초기화하고, 각 섹션에서 상태를 구독하도록 해 메인페이지에서 빠르게 화면을 볼 수 있도록 했습니다.

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

0개의 댓글