2020년 1월 14일 화요일

Man of Month를 마치며

벌써 2020년 1월 14일이다.

19년의 마지막 달에 Man of Month라는 팀의 제도를 시작한다고 했었는데, 12월이 지나고 그 다음 달도 거의 절반이 흐른 것이다.

MoM을 시작하면서 하겠다고 계획했던 것들도 실제 한 것들과 비교해보니 많이 달라졌다.

먼저, 날마다 블로그에 글을 쓰겠다고 했는데 앞에 몇 개 올리긴 했지만 그 뒤로는 글을 올리지 못했다. 변명부터 해보자면, 글을 써보니 생각보다 시간이 오래 걸려서 이러다 글을 쓰고 남은 시간에 일을 하겠구나 생각이 들었다. 또 일을 진행하다 보니 절대적으로 시간이 많이 소모되는 작업들이 많아지고 있어서, 글을 쓰는 건 한 번에 하자는 생각이 들기도 했다.

새로운 공부를 하나씩 해보고 정리를 하는 게 기존 계획이었다. 하지만 그동안 시간이나 여유가 없어서 진행하지 못했던 것들을 해보는 시간이 되었다. 그래서 원래는 코드 베이스에 커밋을 거의 하지 않을 계획이었는데, 그 어느 때보다 많은 양의 변경을 진행하게 되었다.


201912 MoM을 시간대 별로 정리해보면 아래와 같다.

1주차

파트 On Call

파트 On Call 업무를 했다. 원래 MoM을 하게 되면 On Call 업무를 하지 않는 것으로 계획했었기 때문에 다른 누군가와 바꿀까 했지만, MoM을 하면서 On Call을 진행하게 되면 하는데 문제가 없을지를 체크해보는 관점에서 그냥 병행해보았다. 

참고로 라인에서 On Call 이란 일정한 기간 동안(보통 한 주 정도) 팀에서 담당하는 시스템의 안정성을 모니터링하고 문제가 발생하면 초동대처를 하며, slack 등의 대화 채널에서 문의에 답변하고, 라이브러리 업그레이드, 로그 추가/제거, E2E 테스트 안정성 확보 등의 다양한 작업들을 진행하는 제도이다. 

팀마다 작업의 범위가 좀 다르긴 하지만 대체적으로 해당 기간에는 다른 작업을 하기 어렵다고 생각하고 있었는데, 막상 MoM과 같이 해보니 예상대로 같이 하기는 힘들다고 판단 내릴 수 있었다. 따라서 On Call을 마치고 진행하는 On Call 공유 회의에서 이런 의견을 공유했고, 앞으로는 MoM과 On Call을 병행하지 않도록 내부 정리를 마쳤다.

JDK11 Upgrade

유일하게 조금이라도 블로그에 정리를 했던 작업이다. 국내에서 큰 규모로 자바를 사용하고 있는 회사들은 아마도 대부분 비슷한 상황일 거라 생각하는데, 과거에는 프로젝트의 의존성을 대규모로 업그레이드하는 작업 금기시되었다. 위험한 작업이라고 생각하기 때문이다. 오래된 라이브러리들을 업그레이드한다고 하면 말리는 분위기였다. 문제가 발생하면 누가 책임지느냐는 말을 듣기도 일쑤였다.

라이브러리를 업그레이드하는 문제가 그럴진대 Java Runtime을 바꾸는 문제는 얼마나 보수적이었을까?

당연하게도 훨씬 어려운 문제라고 생각했기 때문에 Java 버전이 그렇게 천천히 올라가던 시절에도, 다음 버전 혹은 다다음 버전이 나온 지 한참 지난 후에야 겨우 업그레이드를 고려하거나 아예 고려하지 않은 경우도 적지 않았다.

지금도 국내 업계 전반에서 볼 수 있는 최신 자바 버전은 8인 경우가 대부분이며 6도 종종 보이는 이유가 이 때문이라고 볼 수 있을 것이다.

하지만 최근에는 이런 분위기가 바뀌고 있다. 많은 Open Source 라이브러리들이 자체적인 의존성을 최신으로 유지하는데 많은 관심을 가지고 있고, 신규 Java 버전의 기능들도 좀 더 적극적으로 사용하고 있는 경향이 있다. 주류로 사용되는 Spring Framework 등에서도 신규 Java 지원이 빠르게 이루어지고 있기 때문에 예전처럼 각종 Framework가 의존성 업그레이드의 걸림돌이 되는 시기는 지났다고 생각된다.

무엇보다 Java의 버전 업그레이드나 변화의 수용 속도가 빨라지면서 버전 업그레이드로 인한 개별 편의성의 향상이나 성능의 이점이 점점 커지고 있다. 업그레이드에 소모되는 시간과 노력의 비용을 지불할 가치가 있다고 판단하는 경우가 많아지도 있는 것은 이런 환경의 변화 때문이 아닐까 생각된다.

LINE의 핵심적인 Back-End 시스템들을 대부분 자바로 되어 있다. 따라서 이러한 변화들을 잘 느끼고 있으며 실제로 많은 팀들이 의존성을 최신화하면서도 안정성을 확보할 수 있도록 다양한 보완책들을 추가해둔 상태이다. 

우리 팀에서도 비슷한 작업들을 하고 있었다. 최근 2년에 걸쳐서 중요한 라이브러리들을 업그레이드하고 좀 더 최근의 코드 스타일을 적용하는데 많은 노력을 들여서 이제 Java 업그레이드를 제외한 대부분의 작업을 마무리했다고 판단했다. 그래서 내가 MoM 기간이 이 작업을 시작하게 된 것이다.

막상 해보니 생각보다 크게 변경할 일은 없었다. 일단 Java11이 Java8에 대해서 어느 정도 수준의 하위 호환을 가지고 있었기 때문이다.  버전 업그레이드에 문제가 되는 라이브러리나 코드를 수정한 후 며칠 만에   Java11을 기반으로 프로젝트를 구동할 수 있었다. 향후 인프라팀과 협의해서 운영 서버들에 테스트하는 작업들과 실제 배포하는 작업들이 남았지만 계획을 세워서 진행하면 문제가 없을거라 생각되었다. 

사실, 더 큰 작업은 실제 Java11이 운영 시스템에 올라간 이후에 코드 베이스에 최신의 코드 트렌드를 적용하는 부분이다. Java8로 업그레이드했을 때도 팀이 새로운 개발 방식에 적응하고 이를 코드에 제대로 반영하는데 꽤 오랜 시간이 걸렸던 기억이 있기 때문에 Java11으로 Runtime을 변경하는 사전 작업이 끝난 후에도 코드 베이스를 변경하는 사후 작업에는 많은 시간과 노력이 필요할 것이라고 판단하고 있다.

2~3주차

JUnit5 Upgrade

위에서 Java 업그레이드를 위해서 대부분의 라이브러리 업그레이드 작업을 마쳤다고 이야기했지만 손도 못 댔던 부분이 하나 있었다. 바로 JUnit5로 업그레이드하는 것이다. Java 업그레이드는 앞으로 문제가 될 상황에 미리 대응하는 관점에서 진행하는 것이었다. 하지만 JUnit5 업그레이드는 프로젝트의 의존성들을 최신으로 유지하기 위해서는 지금이라도 꼭 해야 할 작업이라고 판단해서 진행하는 작업이었다. 벌써 최신 Spring Framework에서는 JUnit5를 기본으로 사용하고 있었고 이로 인한 문제가 확인되고 있는 상황이었다.

필요성은 꽤 오래전부터 논의되었고 이슈로도 생성해서 관리했는데 작업이 소용되는 시간과 노력이 많은 것으로 예상되고 코드 변경도 꽤 있을 것이라 엄두가 나지 않던 작업이었다. 하지만 다행히도 12월 중순 이후로 신년 대응의 일환으로 코드 프리징이 진행되고 있어서 몇 주간 릴리스가 없을 예정이었다. MoM 때 하기에는 적당하는 생각이 들었다.

먼저 간단하게 프로젝트 간 의존성이 가장 적은 모듈을 골라서 작업을 진행했다. 다행히 JUnit5는 Vintage Engine이라는 JUnit4 기반의 코드를 사용할 수 있게 해주는 모듈을 제공하기 때문에 단순한 테스트 코드는 문제없이 동작하는 걸 확인할 수 있었다. 하지만 @Rule 등의 annotation이나 JUnit에 적용된 assertThrows나 Parametized 등의 기능의 사용을 위해서는 테스트 코드 변경이 불가피한 상황이었기 때문에 이번 기회에 모든 테스트 코드를 JUnit5 기반으로 변경하기로 결정했다.

PowerMock, JUnitParams 등의 의존성을 제거하고 필요한 Extension 등을 만들거나 찾아서 사용하고 최신 버전의 Mockito 사용으로 인해서 발생하는 문제들을 제거하고, JUnit5 기반으로 코드 베이스를 변경하는데 상당한 시간이 걸렸다. 우여곡절 끝에 Develop에는 머지 할 수 있었고, 얼마 뒤 Master에도 머지 할 수 있었다.


4~5주차

Checkstyle 적용

JUnit5 적용 작업을 하면서 곁다리로 간단하게 적용해보려고 했던 checkstyle 적용 작업이 JUnit5보다 더 많은 변경을 만들게 되었다.

사내에 공통 Coding Convention이 있고, IntelliJ 용으로도 Code Style과 Indent 파일이 있기 때문에 이를 사용하고 있었지만, 시스템에 코드의 스타일과 관련된 부분을 강제는 checkstyle을 사용하지 않았다. 몇몇 팀들은 쓰고 있었지만 우리는 사용하지 않고 있었다.

최근에 여러 이유로 팀에 사람도 많아지고 다른 부서에서도 PR이 종종 등록되고 있는 상황이라서 checkstyle 적용의 필요성을 느끼고 있었는데, JUnit5 업그레이드를 하기 때문에 어차피 코드 변경이 많을 테니 이때 하는 게 좋겠다는 생각으로 시작하게 되었다.

사내의 다른 팀들이 사용하는 checkstyle을 사용하려고 했으나 오래된 버전이라 사내 오픈소스 프로젝트인 Armeria에서 사용하는 checkstyle을 우리 기준을 반영하여 조금 수정 후 사용하는 것으로 최종 결론을 내렸다.

적용은 크게 두 가지로 나누어서 진행하였다.

첫 번째는 환경 구성이다. checkstyle 설정을 기존의 indent나 code style에 맞춰서 수정하고, IntelliJ 플러그인 설정,  Jenkins에 PR 용 checkstyle 작업을 생성해서 Github PR Hook에 등록 등이 이에 해당한다.

두 번째는 코드를 수정하는 작업이다. 간단하게는 Copyright를 추가하거나 unused import를 제거하는 작업에서 JavaDoc의 빠진 구성요소를 추가하는 작업이나 변수나 메서드의 Access Modifier를 적절하게 변경하는 작업까지 프로젝트의 모든 파일을 기준에 맞춰서 작업해야 했다.

두 번째 작업은 혼자서 하기에는 일이 많고, 어차피 팀원 모두가 익숙해져야 하는 부분이라 생각되어서 팀원들 중에 가능한 사람들은 모두 함께 변경 작업을 진행하기로 했다. 모듈 단위로 Jira Issue에 sub-task를 만들어서 등록했으며 각자 여러 개씩 맡아서 변경을 진행했다. 모두의 힘으로 생각보다 빠른 시간 안에 checkstyle 기준으로 통과하는 PR을 만들 수 있었다.



 MoM을 마치며

개발을 하면서 처음으로 키보드를 칠 때 손가락이 저릿한 느낌을 받았다. 아마도 checkstyle 작업을 하던 날이었다. 그날 마침 일찍 출근하는 날이라 아침 7시에 와서 작업을 시작했는데, 아이를 픽업할 필요가 없어져서 밤 10시까지 일을 했던 날로 기억한다. 코드 변경 작업이 단순하기는 한데, 나름 재미있어서 집중해서 아침부터 저녁까지 계속 키보드를 쳤던 것으로 기억한다. 처음으로 손가락 끝이 저릿저릿 한 느낌을 받을 수 있었다. 

MoM 기간을 대표하는 경험이었다. 너무 깊은 고민 없이 주어진 문제들을 처리하는 시간을 가져볼 수 있었다. 문제는 명확했고, 해결책도 단순했다. 문제를 해결하면 그 결과를 바로 확인할 수 있었고 일을 나누면 통합의 부담 없이 협업이 가능했다. 결과물이 측정 가능하고 직관적으로도 확인할 수 있었기 때문에 일에 대한 성취감을 바로바로 느낄 수 있었다. 손가락이 저릿할 정도로 타이핑을 하고도 그만둘 줄 몰랐던 게 그런 이유가 아니었나 생각한다. 

좋은 경험이었고 앞으로의 일에도 적용할 만한 교훈을 얻을 수 있었다.


댓글 없음:

댓글 쓰기

Man of Month를 마치며

벌써 2020년 1월 14일이다. 19년의 마지막 달에 Man of Month라는 팀의 제도를 시작한다고 했었는데, 12월이 지나고 그 다음 달도 거의 절반이 흐른 것이다. MoM을 시작하면서 하겠다고 계획했던 것들도 실제 한 것들과 비교해보니...