어느덧 실무 연차로 치면 7년차 개발자가 되었다. 첫 회사에서 처음 1년은 프론트엔드 개발을 했었으니, 백엔드 개발은 6년 정도 됐구나. 그동안 함께 일했거나 마주쳤던 서버 개발자들과 실무 커리어 그리고 기술 스택 면에서 조금 다른 점이 있었는데, 첫 서버 개발 시작을 Scala 언어와 Netty 프로젝트를 사용한 점이다. 언어와 프레임워크를 사용해보고 싶어서 선택한 건 아니었고, 빈 자리를 채워야 해서 해보겠다고 손들고 시작하게 되었다. 그렇게 첫 회사에서 1년이 지난 이후에 처음 보는 언어와 처음 사용해보는 프레임워크를 혼자서 끙끙대며 서버 개발을 시작했었는데, 그 때 학습했던 내용들이나 코드 작성 경험이 지금도 알게 모르게 많은 영향을 주고 있는거 같다.

Scala 라는 언어 이름이 Scalable Language에서 유래되었듯, 다른 프로그래밍 언어에 비해서 언어가 가져다 주는 자유로움이 높다보니 어떻게 쓰느냐에 따라서 좋은 점도 많고 학습면에서는 어려운 점이 많았었다. Currying, Immutable, Lazy Evaluation, Pattern Matching, Algebraic data type, Variance 등 함수형 프로그래밍에 대한 이해가 필요했고, Netty로 WebSocket과 HTTP 웹서버도 만들어야 해서 TCP, NIO, EventLoop 등 네트워크와 관련된 지식들도 필요했다. 학습하고 배운걸 적용하는 과정에서 밤도 많이 새고 삽질도 엄청 했었는데 이 때 폭풍?압축? 성장했던거 같기도 하다. 여행 가는 당일까지도 밤새서 개발했던 기억이… 힘든 부분도 있었을텐데 지금은 재밌었던 기억만 남아 있다. 시간이 많이 지났고 기억이 미화되어서 그런가…

그렇게 6개월? 1년정도 Scala와 Netty로 서버 개발을 하다가 문뜩 이런 생각이 들었다. ‘한국에서 계속 일 할거면 자바는 해봐야 하지 않을까.’, ‘다들 객체지향, 객체지향 하는데 객체지향이 뭘까?’ 왜냐하면 당시 주위에 많은 사람 그리고 회사들에서 자바 개발자를 선호한다고 생각했었다. 물론 당시에 Scala & Play Framework 조합이 상당히 유행해서 관련 기술을 사용하는 회사도 눈에 보였는데, JVM 환경에서 개발을 하면 자바는 왠지 해봐야 할 거 같았고 Scala 같은 언어에 비해서 불편한 점이 많다는데 왜 그런지 직접 경험 해봐야 안다고 생각했었다. 특정 언어나 플랫폼에 대해 알아보고 싶은 생각은 Spring Framework에 대해서도 마찬가지였다. 그래서 좀 더 욕심을 내서 회사에서 필요한 메시징 플랫폼을 자바로 개발하기로 했고, 시간이 좀 더 지나서는 Spring Boot 기반으로 웹 애플리케이션도 개발할 수 있게 되었다.

그런데 지금 생각해보면 Spring Boot 기반으로 웹 앱을 개발할 때 아무것도 모른 채로 무작정 시작했던거 같다. 지금 인터넷에 검색해보니까 Spring Framework의 3대 요소가 IoC/DI, AOP, PSA 라는데 이런 개념들 조차 모르는 상태에서 개발을 했었다. 그 전에는 DI를 직접 만들어서 사용하거나 Google Guice를 이용해서 사용하다보니 Spring에서 제공해주는 DI, AOP 등의 추상화된 기능들은 베일에 쌓여있는 것처럼 느껴졌다. 그리고 함께 일했던 동료분들의 영향이라 생각하는데, 특정 언어나 프레임워크에 의존적인 개발자가 되고 싶지 않았다. 그래서 프레임워크만을 위해 시간을 투자하고 공부한다는게 불필요하다고 생각했었다. 하지만 시간이 지날수록 느꼈던건데, 잘 알고 사용하면 정말 좋고 편한 기능들이고 아무것도 모르는 상태에서 무작정 따라하려고 하니 문제가 생겼을때 추적하고 해결하기가 정말 어려웠었다.

지금도 Spring Boot 기반으로 프러덕트를 만들고 있는데, 최근까지도 스프링에 대해서 제대로 공부를 한 적이 없었다. 이것저것 개발을 많이 해보면서 아름아름 터득한 것들을 쌓았었고 ‘이게 이거였구나’ 하며 부족한 부분들을 채워나갔던거 같다. 그동안 엄청난 시행착오를 겪어서 그런지.. 요즘엔 스프링 프레임워크 아래서 개발하는게 큰 어려움으로 느껴지지는 않는다. 그런데 언제부터였을까? 신입 개발자분들의 이력서도 그렇고 동료 개발자들의 얘기도 많이 들어 보니, 많은 분들이 전문적인 개발 강의나 부트캠프를 통해서 프레임워크에 대한 전문적인 지식들을 쌓고 있었다. 그리고 스스로 많은 생각이 들었다. 나는 내가 사용하고 있는 프레임워크에 대해서 잘 알고 있을까? 얼마나 알고 있을까? 한편으론, 강의에서 어떤 것들을 다루고 내가 뭘 배울 수 있을지도 엄청 궁금해졌다.

어떤걸 들어볼까 고민하다가 김영한님의 스프링 핵심 원리 - 고급편이 눈에 들어왔다. 주위에 수강하신 분들에게 물어보니 AOP에 대한 설명이 대부분이라고 해서 AOP를 알고 있으면 다른 강의를 추천한다고 얘기해주었다. 회사에서도 그렇고 사이드프로젝트를 할 때에도 AOP에 대해서 많이 접한다고 생각했는데 내가 정말 잘 알고 있는지 궁금했고 김영한님에 대해서도 궁금한 점이 있어서 이 강의를 들어보기로 했다.

인프런 사이트에도 잘 나와 있는데, 강의 전체 목차는 이러하다. 강의 후반부에 AOP에 대한 설명을 하는데, 전반과 중반부는 AOP를 더 잘 이해하기 위해서 필요한 개념들에 대한 설명을 담고 있다.

  • 스프링 핵심 디자인 패턴: 템플릿 메서드 패턴, 전략 패턴, 템플릿 콜백 패턴, 프록시 패턴, 데코레이터 패턴
  • 쓰레드 로컬: 동시성 문제, 멀티쓰레드, 쓰레드 로컬
  • 스프링 AOP: 개념, 동작 원리, 실전 예제, 주의 사항
  • 기타: 빈 후처리기, 다양한 실무 팁

강의 후반부에는 실무에 필요한 내용들을 알려주었는데, 정말 나도 마주쳤던 내용들이라서 신기했다. 당시에는 이게 왜 안되지 했었는데 당연한 내용이었고 강의를 일찍 들었으면 좋았겠다라는 생각이 들었다. 😇

AOP를 적용하면 스프링은 대상 객체 대신에 프록시를 스프링 빈으로 등록한다. 따라서 스프링은 의존관계 주입시에 항상 프록시 객체를 주입한다. 프록시 객체가 주입되기 때문에 대상 객체를 직접 호출하는 문제는 일반적으로 발생하지 않는다. 하지만 대상 객체의 내부에서 메서드 호출이 발생하면 프록시를 거치지 않고 대상 객체를 직접 호출하는 문제가 발생한다. 실무에서 반드시 한번은 만나서 고생하는 문제이기 때문에 꼭 이해하고 넘어가자.

이전에 Feature Toggle 150% 활용하기 포스팅에서 Annotation 기반의 피쳐 플래깅 이야기를 공유했었는데, 이 Annotation 동작도 마찬가지로 Spring Aspect를 통해서 동작하기 때문에 프록시로 동작한다. 그래서 객체의 내부에서 메서드 호출이 발생하면 프록시를 거치지 않기 때문에 피쳐 토글이 정상적으로 동작하지 않는다.

class MyFeatureToggleProvider {
    // 객체의 내부에서 호출이 일어나기 때문에 프록시를 거치지 않고 항상 newCoolFeature이 수행된다.
    fun execute(userId: Long) {
        if (newCoolFeature() == "NewCoolFeature") {
            ...
        } else {
            ...
        }
        
    }

    @FeatureToggle(key = "NEW_COOL_FEATURE", fallbackMethod = "oldFeature")
    fun newCoolFeature(): String {
        return "NewCoolFeature"
    }

    @FeatureToggleFallback
    fun oldFeature(): String {
        return "OldFeature"
    }
}

강의에서도 얘기해주는데 @Transactional Annotation도 마찬가지다. 클래스 내부에서 @Transactional annotation이 추가된 메서드를 호출하면 의도한대로 동작하지 않을 수 있다. 이걸 위해서 몇가지 방법들을 알려주는데, setter를 통해서 자기 자신을 주입하는 방식을 보고 이런 방법도 있겠구나 싶었다(이렇게 쓰지는 않을듯;;).

AOP 개념을 설명하기 위해 강의 절반 이상을 기반이 되는 기술 개념들에 대해서 소개하고 있는데, 그만큼 후반부에 접어들면 AOP가 어떻게 동작하는지 잘 이해할 수 있고, 앞부분에서 배웠던 개념들이 실제로는 어떻게 사용될 수 있는지 구체적인 사례로도 도움이 되어서 나에게는 기초 개념도 다시 살펴볼 수 있고 AOP가 어떻게 동작하고, 실무에서 주의할 점은 무엇인지 다시 한 번 살펴볼 수 있는 값진 강의였다.

inflearn-cert

강의 맨 마지막은 <다음으로>라는 제목의 35분 영상. 강의 전체적인 목차를 다시 한 번 훑어보면서 어떤 것들을 학습했는지 회고해보고 그 다음 스텝을 위한 로드맵도 살펴보았다. 그리고 김영한님이 개발자들에게 하고 싶은 이야기를 전해주는데, 그 주제는 기술적 겸손함이다. 기술적 겸손함이란 뭘까? 그냥 겸손함이라 표현해도 좋겠다. 개발자에게 겸손함이란 뭘까? 사람마다 생각이 다르겠지만, 나는 ‘가지고 있는 어떤 기술들을 통해서 사용자가 겪고 있는 문제를 해결할 수 있는 직군’을 개발자라고 정의하고 싶다. 여기서 ‘사용자’, ‘문제’가 매 순간 달라진다. 내가 1A라는 문제를 해결할 수 있는 A 기술만 가지고 있다면 1B라는 문제를 겪고 있는 사용자에게 도움을 줄 수 없다. 새로운 문제를 해결하려면 학습을 통해 ‘가지고 있는 어떤 기술’을 더해야한다. 그래서 배움에 열려 있고 정체를 지양하며 힘들더라도 앞으로 조금씩 나아가기를 멈추지 말아야 하는게 아닐까? 계속해서 기술적 겸손함을 가진 개발자가 되고 싶다.