인상적인 코딩 테스트 그리고 합격

9개월간 재택근무를 했으나 오히려 심신이 피로해짐을 깨닫고 다시 오피스로 컴백하려고 자리를 물색하던 중 우연치 않게 스타트업과 인연이 닿게 됐다. 그것도 출퇴근 때문에 기피하던 런던으로.

핀테크 스타트업은 아이디어도 좋고 브랜딩도 잘하고 있어서 눈에 띄는 회사였다. 호기심으로 시작한 인터뷰가 다섯 차례로 이어지고 마지막에는 반나절간 같이 앉아서 pair programming도 했다. 원래 스타트업에 들어가는 게 더 어려운건지는 잘 모르겠으나 합격 소식을 듣고는 그 동안 고생한게 있어 오퍼를 포기할 수 없었다.

기술력도 중요하지만 팀핏도 그만큼 중요하게 생각한다는데 이 나이든 개발자를 받아주니 감사할 따름이다. 개발자 이사와 함께 일하며 은행 또는 투자회사들과 트레이딩하는 플랫폼을 만들 예정이다.

코딩 테스트

개발자 인터뷰는 코딩 테스트가 필수다. 작년에 현대차 영국법인을 떠날 때와는 달리 지난 9개월간 현재 회사에서 익힌 경험이 많은 도움이 됐다. 면접자중 가장 좋은 코드를 보여줬다고 피드백을 받았고 그 덕에 부족한 영어를 극복할 수 있었던 것 같다.

인상적인 코딩 테스트를 위한 다섯 가지 

코드로 좋은 인상을 주려면 첫 번째로 테스트 코드를 잘 만들어야 한다. Unit Test와 Integration Test를 잘 구분해서 테스트 대상의 실행경로를 최대한 커버하면서 테스트의 목적이 분명히 읽히도록 작성해야 한다.

두번째로는 테스트시 발견되는 외부 종속성을 추상화 시켜야 한다. 예를 들어, csv 파일을 xml 파일로 변환하는 작업을 테스트한다면, 변환 로직은 Unit Test에 파일 핸들링은 Integration Test로 커버한다. 변환 로직은 Unit Test에서 검증하는데, 그 시작은 csv 파일의 내용을 읽는 것으로 시작할 것이다. 이 때, 파일 입력이 인터페이스로 추상화 되어 있어서 IFileReader.Read() 같은 메서드가 있다면 이 메서드가 호출되었는지 테스트하는 것이 Unit Test에서 해야할 일이다. 파일의 내용은 Mocking 툴을 사용하여 제공한다. 실제 파일의 내용을 읽는 것은 Integration Test 이다.

세번째는 종속성 주입(Dependency Injection)인데 테스트 가능한 코드를 작성하면 DI는 자연스럽게 이루어진다. DI를 간단하게 설명하면 상위 클래스가 하위 클래스의 변경에 영향을 받지 않아야 한다는 개념이다. 파일 변환의 예를 들어보면, 변환 로직은 IFileReader 인터페이스를 구현하는 CsvFileReader를 사용한다. 변환 로직은 상위 클래스고 CsvFileReader는 하위 클래스다. 이때, 변환 로직은 CsvFileReader를 직접 사용하지 않고 인터페이스(IFileReader)를 사용해야 한다. Code to interface, not implementation.

파일 입력방식이 CSV에서 XML로 변경된다면 이 때문에 상위 클래스인 변환 로직을 변경해야 할까? 그렇지 않아야 한다는 것이 DI의 개념(inversion of control)이다. IFileReader를 상속하는 XmlFileReader 클래스를 새로 작성해서 IoC 컨테이너에 CsvFileReader 대신 등록한다. IFileReader 가 사용되는 곳에서는 CsvFileReader를 사용했다가 아무런 코드 변경없이 XmlFileReader를 통해 데이터를 입력 받게 된다.

네번째는 도메인 중심의 사고다. 우리가 지난 20년간 사용했던 Data centric architecture는 생명체처럼 진화하는 소프트웨어를 원활히 지원할 정도로 유연하지 않다. 데이터베이스의 테이블 구조를 먼저 생각하는 사고 방식은 역동적으로 진화하는 소프트웨어에 적합하지 않다. 비즈니스 로직을 도메인 객체로 잘 표현하는 것은 어렵지만 장기적으로 복잡성을 최소화할 수 있는 수단이다.

현금이체를 예로 들어, Account 객체와 Transfer 객체가 있다고 하자. 1회 이체 금액은 얼마인지, 잔고가 일정 금액 이하면 통지해야 한다든지, 이런 로직은 어떤 객체에 구현해야 할까? Transfer는 커맨드 객체로 이체 요청을 받아 logging 하고 Account 같은 도메인 객체를 사용한 후 그 결과를 요청자에게 돌려주면 된다. 모든 비즈니스 로직은 Account에 구현하는 것이 Separate of concern을 지키는 방법이다. 이때, Account 객체의 상태 변화를 데이터베이스에 어떻게 저장하는지는 그리 중요한게 아니다. 데이터베이스는 그저 하나의 implementation detail 일 뿐이다.

다섯번째로, SOLID 로 대표되는 다섯가지 개념을 숙지하고 코드를 작성할 때, 그 원칙에 따르도록 노력해야 한다.

이 코드는 왜 이렇게 작성했냐는 질문을 받았을 때, 예를 들어, “Single Responsibility 원칙에 따라 한 가지 이유에서만 이 클래스를 수정할 수 있도록 디자인했다. Account 객체에서 잔고 부족시 Notification 까지 한다면, Notification 내용을 변경하고자 할 때, Account객체를 수정해야 하는 직접적인 목적이 아님에도 불구하고 손을 대야 한다. 그렇다면 이 객체는 지나치게 많은 일을 하고 유지보수를 복잡하게 만들고 있다. Notification 을 직접하는 대신 이벤트만 발생시켜 Account 를 사용하는 Transfer 객체가 처리하는 것이 맞다고 생각한다”라고 설명할 수 있어야 한다.

코드 예제

마지막으로...

우리 개발자들은 코드를 작성하기 보다 읽는데 더 많은 시간을 사용한다. 나도 좋고 남도 읽기 좋은 코드를 작성하는 것은 쉬운 일이 아니다. 우리가 개발 기술을 통해 사회에 기여하고 사용자로부터 좋은 피드백을 받으려면 개발자간의 소통이 무엇보다 중요하다. 개발자간의 소통이 무엇인가? 깨끗하고 읽기 쉬운 코드만큼 좋은 것은 없을 것이다. 이를 위해 많은 시니어들이 읽기 쉬운 코드를 작성하고, 후배들과 공유하고, 같이 토론하는 문화를 상상해본다.


Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.