오늘 배운 것

기존에 알림을 보내는 로직을 작업하면서, 요청이 들어왔을 때 해당 요청을 보낸 디바이스가 누군지 알아야 하는 이슈가 있었다. 그래서 이를 알기 위해서 request.auth의 속성 값으로 device_token 인자를 추가해주는 작업을 했었다. 

 

여기서 오류가 생겼다. 정확히는 테스트할 때 나는 오류였다.

현재는 해당되는 뷰(동기화용 알람이 필요한 뷰)의 맨 끝에다가 FCM 알림을 보내는 메소드 코드를 추가한 방식으로 구현했다. 그런데 이렇게 하면 테스트할 때도 해당 FCM 알림 로직을 지나게 된다.

 

여기서 두 가지의 이슈가 생긴다.

  1. 특정 뷰가 동작하는 것을 테스트할 때 FCM 알림이 보내지는 것까지 테스트하는 것은 불필요하다. 
  2. 테스트할 때 들어오는 request에는 별도로 fcm 디바이스 토큰을 넣어주지 않기 때문에 request.auth에 device token의 값이 없다. 그러므로 FCM 알림을 보내는 로직이 fail하게 된다. 

즉 뷰의 로직과 FCM 알림 로직을 분리해야 한다는 결론에 도달한다. 우회하는 방법도 있긴 하다. 가령 테스트할 때는 특정 파라미터의 값을 True로 바꿔 준 다음에, 해당 파라미터 값이 True이면 해당 알림 로직을 패스하는 방식으로 짤 수도 있다. 그러나 이는 일반적인 요청값 외에 추가로 파라미터를 넣어 줘야 하고, 결국 그 값 하나로 FCM 로직을 핸들링하는 것이기 때문에 적합하지 않다고 보았다. 

 

알고보니 pytest의 여러 기능 중에는 테스트하는 뷰 안의 특정 메소드가 호출되지 않도록 하는 기능도 있었다. 해당 기능을 사용해서 테스트 상황에서는 FCM 알림 관련 메소드를 호출하지 않도록 해 주면 되겠다.

 

근데 오늘은 자바 코테를 풀어야해서 내일 마저 해보겠다...!

 

 오늘 배운 것

개발서버가 고쳐졌다고 한다! 어제 작업한 다국어 기능에서 언어를 바꾸는 화면이 잘 동작하는지 확인해 보자. 

 

잘 동작한다. 다만 위에 나오는 'settingsLanguageView' 대신에 '언어 선택'이라고 나오도록 바꿔 보자. apps/_layout.tsx 파일(index.js와 같은 역할을 하는 루트 파일)에다가 다음과 같이 추가해 주었다. 

<Stack.Screen
  name="settingsLanguageView"
  options={{
  headerTitle: t('views.settingsView.language'),
  headerTitleAlign: 'center',
  }}
/>

 

그랬더니 잘 나오더라!

 

 궁금한 점

1. django mixins에 대해 궁금증이 생겼다. 발단은 팀원들과 React의 Compound Component 패턴에 대해서 얘기하면서부터였다. 가령 나는 이런 코드를 본 적이 있다. 

from rest_framework.mixins import ListModelMixin, CreateModelMixin
from rest_framework.generics import GenericAPIView


class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
	pass

 

여기서 GenericAPIView와 ListModelMixin, CreateModelMixin을 상속받아 APIView의 역할을 하면서도 ListView와 CreateView의 역할을 하는 View를 만들 수 있다고는 알고 있었다. 그런데 막상 Mixins가 구체적으로 왜, 어떻게 상속을 통해 GenericAPIView와 같이 동작할 수 있는지에 대해서는 구체적으로 생각하지 않은 것 같다. 다음에 이 부분에 대해서도 포스팅을 해봐야겠다. 

 

 오늘 배운 것

오늘은 설정에서 i18n 패키지를 통해 다국어를 바꿔주는 작업을 진행했다. '한국어'와 '영어' 옵션 중에 선택할 수 있도록 UI Kitten의 Menu 옵션을 사용해주었다. 

 

그리고 selectedIndex라는 메뉴의 옵션을 통해 현재 사용하고 있는 언어가 선택된 것으로 표기되도록 해 주었다. 

 

전체 코드는 다음과 같다. 

const SettingsLanguageView = () => {
  const { t, i18n } = useTranslation();
  const [selectedIndex, setSelectedIndex] = useState(new IndexPath(setIndex()));

  const handleKoreanPress = () => {
    i18n.changeLanguage('ko');
  };

  const handleEnglishPress = () => {
    i18n.changeLanguage('en');
  };

  const setIndex = () => {
    if (i18n.language === 'ko') {
      return 0;
    } else {
      return 1;
    }
  };

  return (
    <>
      <IconRegistry icons={EvaIconsPack} />
      <ApplicationProvider {...eva} theme={eva.light}>
        <SafeAreaView style={styles.container}>
          <Layout style={styles.layout} level="1">
            <Menu
              selectedIndex={selectedIndex}
              onSelect={index => setSelectedIndex(index)}
            >
              <MenuItem
                title={t('views.settingsLanguageView.korean')}
                onPress={handleKoreanPress}
              />
              <MenuItem
                title={t('views.settingsLanguageView.english')}
                onPress={handleEnglishPress}
              />
            </Menu>
          </Layout>
        </SafeAreaView>
      </ApplicationProvider>
    </>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  layout: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 16,
  },
  text: {
    textAlign: 'center',
  },
  link: {
    color: 'blue',
    textDecorationLine: 'underline',
  },
});

export default SettingsLanguageView;

 

이제 의도한 대로 다국어 변경 화면이 잘 나오는지를 테스트해보려고 했는데, 개발 서버에 오류가 있어서 소셜로그인이 현재는 안 되는 상황이라 결과는 내일 확인할 수 있겠다. 오늘 다른 팀원이 고쳐본다고 했었는데 내일 만나서 진행상황을 같이 봐야할 것 같다. 

 

 오늘 배운 것

어제의 포스트를 통해 다국어 지원이 잘 동작하는 것을 확인했다. 이제 남은 것은 손수 앱에 있는 모든 한국어/영어를 ko.json과 en.json 파일에 넣어 주는 것이다. 복잡하진 않지만 할 일이 많은 반복 작업만이 남았다. 

 

다행히 앱 페이지가 많지는 않으니 일단 해보자. 아래와 같이 ko.json과 en.json 파일을 만들어주고 어제와 같은 방법을 적용하니 다국어 지원은 잘 되었다. 

// ko.json
{
  "views": {
    "index": {
      "signIn": "구글 로그인"
    },
    "_layout": {
      "addCategory": "Add Category",
      "manageCategory": "Manage Category",
      "editCategory": "Edit Category",
      "settings": "Settings",
      "contact": "Contact"
    },
    "tabs/_layout": {
      "today": "투데이",
      "inbox": "인박스"
    },
    "settingsView": {
      "account": "계정",
      "language": "언어",
      "contact": "문의"
    }
  },
  "components": {
    "headerMenu": {
      "manageCategory": "카테고리 관리",
      "settings": "설정"
    }
  }
}
// en.json
{
  "views": {
    "index": {
      "signIn": "Sign in with Google"
    },
    "_layout": {
      "addCategory": "Add Category",
      "manageCategory": "Manage Category",
      "editCategory": "Edit Category",
      "settings": "Settings",
      "contact": "Contact"
    },
    "tabs/_layout": {
      "today": "Today",
      "inbox": "Inbox"
    },
    "settingsView": {
      "account": "Account",
      "language": "Language",
      "contact": "Contact"
    }
  },
  "components": {
    "headerMenu": {
      "manageCategory": "Manage Category",
      "settings": "Settings"
    }
  }
}

 

그런데 문제가 하나 있었다. 바로 달력(WeeklyCalendar)에 나타나는 기본 한글은 바뀌지 않는다는 점이었다. 예를 들면 지금은 '2024년 10월'이라고 나와 있는데, 영어 버전에서는 'October 2024'로 나와야 맞겠다. 이 부분은 아래와 같이 함수를 작성해서 구현하였다. 

const convertMonthAndYear = date => {
  if (i18n.language === 'ko') {
    return date.format('yyyy년 MM월');
  } else if (i18n.language === 'en') {
    const month = date.toString().split(' ')[1];
    const year = date.toString().split(' ')[3];
    return `${month} ${year}`;
  }
};

 

 

잘 나온다. 그런데 요일은 그대로라서 요일도 바꿔주자. 요일은 현재 '월 화 수 목 금 토 일'로 나와 있는데, 이를 'Mon Tue Wed Thu Fri Sat Sun'으로 바꿔 주어야 하겠다. 

 

처음에는 datetime format이니까 당연히 영어 요일로 바꾸는 뭔가가 있을 것이라고 생각했다. 그러나 의 방법을 참고했는데도 잘 되지 않아서 찾아보는 데 시간이 걸릴 것 같았다. 그래서 아래와 같이 구현했다. 

const convertDictionary = {
  월: 'Mon',
  화: 'Tue',
  수: 'Wed',
  목: 'Thu',
  금: 'Fri',
  토: 'Sat',
  일: 'Sun',
};

const convertWeekDates = date => {
  if (i18n.language === 'ko') {
    return date.format('ddd');
  } else if (i18n.language === 'en') {
    return convertDictionary[date.format('ddd')];
  }
};

 

이제 잘 나온다.

 

이제 언어를 바꾸는 기능도 추가해주자. 그러려면 화면도 바꿔 주어야겠다. 현재는 설정 화면에서 '언어' 버튼을 누르면 아무 작용도 하지 않는데, 화면을 하나 추가하면 되겠다. 우선 피그마에 관련해서 만들어 놓은 화면이 있는지를 확인해봤다. 

 

만들어 놓은 화면이 없다. 하지만 UI가 크게 중요한 화면은 아닌 만큼, 내가 사용하고 있는 다른 앱의 화면을 참고해서 만들어 보면 되겠다. 

 

Djangonaut에 합격하고 후기를 남겨본다. 

 

Djangonaut은 장고(Django)의 오픈소스 기여자를 만드는 프로그램이다. 이전부터 진행되어 왔던 프로그램인데, 이번에 좋은 기회로 이 프로그램을 알게 되어서 냉큼 지원했다. 

 

사실 합격 메일은 10월 1일에 왔는데 후기를 적는 걸 잊고 있다가 지금이라도 적어본다. 

 

요런 exciting한 메일이 온다. 같이 지원했던 팀원들은 아쉽게도 붙지 못했는데, 지원자가 제법 많았던 것 같았다. 이번 활동에 열심히 임해보고, 잘 기여해서 다음 지원 때의 팁도 잘 공유해야겠다. 

 

2024 토스 next developer 중 파이썬 개발자 포지션에 지원했었다. 내가 쭉 사용해 왔던 언어가 파이썬이기도 하고, 짧은 시간이지만 프로젝트나 직무에 사용하면서 파이썬이라는 언어 자체에 정이 들기도 했다. 또한 '언어는 결국 도구이고, 중요한 것은 문제를 해결하는 것'이라는 토스 사람들의 마인드가 멋지다고 생각해서 해당 팀에서 같이 일하고 싶은 마음도 컸다. 

 

그리고 어제(10월 5일) 2시경 과제 메일을 받았다. 

 

자세한 내용은 보안서약서 때문에 밝힐 수 없지만, 현업에서의 많은 고민과 생각이 담겨있는 과제라는 생각이 들었다. 과제의 맥락을 모르는 사람도 readme 파일을 읽으면 문제를 이해할 수 있게끔 가이드를 적어주셨다. 새삼 나의 코드는 이렇게 이해하기 쉬운지 돌아보게 되었고, 코드를 간결하게 작성하거나, 변수명을 상세히 작성하거나, 문서화를 잘 하는 것도 요즘은 개발자의 필수 스킬이라는 생각이 들었다. 

 

여튼 6시간 동안 작업한 뒤 최고의 결과는 아니지만 나름의 노력이 담긴 결과물을 제출했다. 비록 결과는 아직 아무도 모르는 것이긴 하지만, 테스트 케이스에서 많이 틀려서 면접까지는 갈 수 없겠다는 생각이 제일 먼저 들었다. 그리고 아직 더 발전이 필요하겠다는 생각도 많이 들었다. 

 

그래서 속상한 마음 반, 더 발전해야겠다는 마음 반을 담아 앞으로 어떻게 하면 좋을지에 대한 회고를 같이 작성해보려고 한다. 

 

Q1. 나는 왜, 무엇이 부족하다고 느꼈을까?

A1. 내 스스로 문제해결 과정에서 미흡함을 많이 느꼈다. 앞서 언급한 것처럼 현업에서의 고민이 많이 담긴 과제였기 때문에 단순 연산 문제처럼 명확한 정답이 있는 문제들은 아니었다고 느꼈다. 실제로 앞으로 내가 마주하게 될 코드들도 그럴 것이 분명했다. 그럴수록 '정확한 답'을 찾는 것보다 나는 무엇이 문제라고 생각하고, 왜 그렇게 생각했고, 그래서 어떤 해결방법들을 생각했는지를 한 걸음 떨어져서 생각하고 실천에 옮겨볼 수 있어야 하겠다. 막상 복잡한 현업의 문제 상황이 주어지니 문제 정의를 체계적으로 하기보다는 '어떻게 하면 테스트 케이스를 통과시키지?'에 집중해서 하는 모습을 발견했다. 그러니까, 문제를 해결하는 와중에도 '나는 현재 원인을 A라고 생각해서 B라는 방법으로 접근하고 있다'가 스스로도 좀 명확하지 않은 것 같았다. 

 

Q2. 그러면 어떻게 해야 할까? 

A2. 이 문제는 꾸준한 개발과 프로젝트(코딩)가 답이라고 생각했다. 그런데 그냥 아무 생각 없이 코딩만 하면 되는 건 아니고, 계속해서 '왜'를 질문하는 연습을 많이 해야겠다. 왜 이 기술을 썼는지, 왜 이 방법을 시도했는지에 대해서 설령 더 나은 방법이 있을지언정 내가 고민하고 노력한 흔적이 있는 것이 중요하다는 생각이 들었다. 이렇게 하다 보면 지금처럼 현업의 문제 상황이 과제로 주어졌을 때도 습관처럼 '왜'를 고민하면서 문제에 접근할 수 있을 것이고, 그러면 설령 지금과 비슷하게 테스트 케이스를 다 풀지 못하더라도 스스로가 조금 더 납득할 수 있는 결과로 이어질 것이다. 결국 더 실력이 좋은 개발자가 되려면 코딩을 많이 하는 수밖에 없구나 싶다. 취준 때문에 소홀해진 프로젝트에 다시 집중을 해보자..!

 

Q3. 너무 스스로를 비판만 한 것 같다. 그래도 잘 해나가고 있는 것이 있다면 어떤 것일까?

A3. 뭐가 문제였던 것인지를 안 것, 그리고 그걸 조금씩 고쳐나가고 있다는 점에서 방향은 잘 설정한 것 같다. 소마를 시작하기 전에는 개발을 잘 하는 사람들에 대해 막연한 오해나 환상이 있었다. 완벽한 답안이 있을 것이라고 생각했고, 문제를 빠르고 완벽하게 푸는 것이 개발을 잘 하는 것이라고 여겼고, 나는 그에 비하면 늘 많이 부족하다고 생각했었다(물론 계속 발전이 필요하긴 하다...!!). 그런데 팀원들과 소마를 하면서 정작 얻은 것은 완벽한 프로젝트가 아니라 완벽하지 않지만 동작은 하는, 고생의 서사가 담긴 프로젝트였다. 막상 현업에 종사하게 되어도 이는 변하지 않을 것이라는 생각이 들었고, 내가 잘못 생각하고 있었던 것을 소마에서 조금이나마 깨닫고 가는 것 같아서 다행이라는 생각이 많이 들었다. 

 

Q4. 그럼 앞으로 뭘 해야 할까?

A4. 멘토님이 늘 말씀하시는 것과 같다. 코딩과 꾸준한 회고, 그리고 멘탈을 위한 운동이다. 그런데 이렇게만 적으면 파워 J인 나의 적성에 차지 않는다. 코딩과 회고와 운동을 얼마나 해야 잘 한 것인지에 대해서 기준을 세워야 제대로 지킬 수 있다. 코딩은 매주 TIL을 최소 4개 이상 쓰는 것, 회고는 매주나 격주에 한 번씩, 운동은 최소 일주일에 세 번씩(20분 러닝이나 홈트 15분도 인정해 주자...) 하기로 결정했다. 

 

이렇게 다음 시즌까지 잘 버텨보자!

 

'회고' 카테고리의 다른 글

데브시스터즈 지원 후기  (0) 2024.10.10
Djangonaut 합격 후기  (1) 2024.10.07
20241004 TIL: day off 대신 쓰는 중간 회고  (0) 2024.10.04
20240901 TIL: day off 대신 쓰는 중간 회고  (3) 2024.09.01
20240830 회고  (4) 2024.08.30

 오늘 배운 것

오늘은 전날과 전전날 토스 과제와 회고로 미뤄두었던 다국어 처리 지원을 더 해보려고 한다. 저번에 i18-react, i18n 공식 라이브러리는 찾았었는데 여기서 안드로이드 전용 설정을 해주지는 않았었다. 그 설정을 마저 하고 다시 앱을 실행시켜서 잘 나오는지를 봐야 하겠다. 처음부터 따라해 보자. 

 

우선 npm을 이용해서 라이브러리를 설치해 준다. 

npm install react-native-i18n --save

 

글에 cocoapods라는 프로그램(?)을 이용해서 설치하는 방법도 있었는데 이게 설치되어있지 않아서 굳이 해야하나 싶었다. 나는 그 밑의 방법을 사용했다. 

 

그러다가 뭔가 이상한 점을 느꼈다. 분명 그때 봤던 블로그 글에서는 한 번에 다국어지원을 하고 있었는데 말이다. 다시 글을 순서대로 읽고 따라해 보았다. 

 

그랬더니 잘 되더라. 

 

 궁금한 점

  1. npm과 yarn의 차이는 무엇일까? 

 

+ Recent posts