글이 매우 복잡하고 깁니다. 양해 부탁드립니다.

틀린 정보나 이해가 가지 않는 부분은 댓글 남겨주시면 참고하겠습니다.

HandlerMapping의 역할

Spring MVC에 대해서 공부하던 중, HandlerMapping이 request를 처리하기에 적절한 handler를 찾아온다는 설명을 들었다.
좀 더 찾아보니 HandlerMappingrequest의 URL과 매칭되는 handler를 선택하는 역할을 수행한다 는 것을 보았다.

request의 URL만 보고 어떻게 찾아온다는 것일까? 그리고 찾아진 handler는 method인데 어떠한 방식으로 가져온다는 것일까?

한가지만 기억하고 가자.
HandlerMapping은 원하는 handler를 찾아오는 역할을 수행한다.

Spring MVC Request flow

HandlerMapping의 역할에 대해서 살펴보기 전에 Spring MVC에서 request가 어떠한 순서로 처리되는지 먼저 보아야 한다.

처리 순서

  1. 먼저 front-controller의 역할을 하는 DispatcherServlet이 request를 받는다.
  2. DispatcherServlet은 적절한 controller를 선택하는 일을 HandlerMapping에게 요청한다.
  3. HandlerMapping은 적합한 controller를 선택한다.
  4. DispatcherServlet은 선택된 controller의 비즈니스 로직 실행 작업을 HandlerAdapter에게 위임한다.
  5. HandlerAdpater가 controller의 비즈니스 로직을 호출하고 결과를 ModelAndView 객체에 담아서 DispatcherServlet이 에게 return한다.
  6. DispatcherServletViewResolver를 이용하여 결과를 보여줄 View를 가져온다.
  7. View 객체에게 DispatcherServlet이 응답 결과 생성을 요청한다.

이 긴 과정 속에서 이 글에서 살펴볼 과정은 2,3번이다.
Request flow 순서대로 HandlerMapping에 대해서 알아볼 것이다.

DispatcherServlet

먼저 DispatcherServlet에서 부터 출발해야한다. 상속구조부터 보면,

public class DispatcherServlet extends FrameworkServlet
            ↓
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
            ↓
public abstract class HttpServletBean extends HttpServlet
            ↓
public abstract class HttpServlet extends GenericServlet

이렇게 상속구조를 통해 DispatcherServlet은 결국 HttpServlet을 상속함을 알 수 있다.
그렇기 때문에 DispatcherServletServlet의 생명주기와 비슷하게 흘러감을 알 수 있다. (init(),doGet(),doPost(),service() 등등)

실제로 디버깅을 해보면, doService가 호출된다.
그 후 DispatcherServletfront-controller 역할을 하기 때문에 doDispatch를 호출한다.

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
...
    try {
    doDispatch(request, response);
    }
...
...
}

doDispatch의 javadoc을 보면 Servlet의 HandlerMapping을 순서대로 처리하여 handler를 가져온다고 되어있다.

Process the actual dispatching to the handler. The handler will be obtained by applying the servlet's HandlerMappings in order. The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters to find the first that supports the handler class.

doDispatch의 실제 코드를 보면 아래처럼 request에 대해서 handler를 가져오는 getHandler 함수를 호출하고 있다.

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
...
    try {
    ...
        // Determine handler for the current request.
    mappedHandler = getHandler(processedRequest);
    ...
...
...

getHandler 함수는 DispatcherServlet의 method로 아래와 같다.
이게 실제로 적절한 handler를 가져오는 방식인데 전혀 감이 안온다. 하나하나 풀이해보자.

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  if (this.handlerMappings != null) {
    for (HandlerMapping mapping : this.handlerMappings) {
      HandlerExecutionChain handler = mapping.getHandler(request);
      if (handler != null) {
        return handler;
      }
    }
  }
  return null;
}

DispathcerServlet은 처음 init되는 과정에서 여러가지 handlerMapping들을 등록하고 List를 통해 handlerMappings라는 이름으로 관리하고 있다. handelrMappings안에는 여러가지 handlerMapping들이 등록되어 있는 것이다.

그러므로 아래 코드는 DispatcherServlet 안에 handlerMapping들이 등록되었다면 이라는 뜻이다.

if(this.handlerMappings!=null)

등록되어있는 HandlerMapping들을 loop 하면서

for(HandlerMapping mapping : this.handlerMappings){

HandlerMapping들에게 request에 맞는 handler를 가져오게하고, 가져왔다면 그 handler를 return하는것이다.

  HandlerExecutionChain handler=mapping.getHandler(request);
  if (handler!=null)
    return handler;

핵심 부분은 HandlerMapping에게 request에 맞는 handler를 가져오는 부분이다. 이게 궁금해서 이 먼 길을 돌아온 것이다.

DispatcherServlet부분의 내용을 정리하자면,

  1. doService이 호출된다.
  2. doService내에서 doDispatch가 호출된다.
  3. doDispatch내에서 getHandler가 호출된다.
  4. getHandler내에서 등록된 HandlerMapping 중에서 request에 걸맞는 handler를 가져온다.

이제 거의 다왔다.

HandlerMapping이 handler를 가져오는 과정

HandlerMappinginterface로 함수의 선언부만 가지고 있다.

public interface HandlerMapping {
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

실제로 handler를 가져오는 getHandler는 추상 클래스인 AbstractHandlerMapping에 정의되어 있다.

우리가 흔히 아는 RequestMappingHandlerMapping,SimpleUrlHandlerMapping 같은 것들의 부모(바로 윗단계는 아니지만)가 AbstratHandlerMapping이다.

아래는 AbstractHandlerMappinggetHandler 코드이다.
getHandlerInternal을 통해서 handler을 찾아오고, HandlerExecutionChain을 return하는데,
우리가 원하는건 handler를 찾아오는 방식이므로 getHandlerInternal을 봐야겠다.

HandlerExecutionChain은 간단하게 handler와 handler interceptor들을 모아놓은 것이다.
Handler execution chain, consisting of handler object and any handler interceptors.

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  Object handler = getHandlerInternal(request);
  ...
  HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
  ...
  return executionChain;
}

getHandlerInternalAbstractHandlerMapping을 상속한 AbstractHandlerMethodMapping에 정의되어 있다.
AbstractHandlerMethodMapping은 복잡하지만 이런 구조를 가지고 있다.

아래는 getHandlerInternal의 코드다. 이번에도 차근차근 살펴보자.

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
...
...
// Look up a handler method for the given request.
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
  this.mappingRegistry.acquireReadLock();
  try {
    HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
    return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
  finally {
    this.mappingRegistry.releaseReadLock();
  }
}
...
...
}

먼저 javadoc을 보면 주어진 request에 대한 handler method를 찾습니다. 라고 되어있다.
동작원리의 핵심적인 부분인것이다.

Look up a handler method for the given request.

lookupPath는 현재 servlet mapping 안에서의 검색경로인데, request 요청을 분석해서 얻을 수 있다.
그리고 mappingRegistry에 대한 ReadLock을 가져오고 있다.

String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();

lookupPath를 바탕으로 lookupHandlerMethod를 통해서 적절한 handlerMethod를 가져온 후 return 한다.

handlerMethod가 바로 우리가 직접 Controller 안에 정의한 함수인것이다.

try {
  HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
  return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}

정리해보자면, DispatcherServlet 함수 안에서 handlerMapping이 여러 과정을 거쳐서 적절한 handlerMethod 를 가져온다는것은 알 수 있다.

그러나 궁금증이 더 남아있다.

url에 해당하는 적절한 method를 구별하는 방법과, method를 가져오는 것이 여전히 궁금하다.
각각 MappingRegistryReflection이 답이다.

나머지 궁금증은 2편에서 마저 다루도록 한다.

출처

Interceptor 사용법 : Request flow에 대해서 잘 정리되어 있었다.
AbstractHandlerMethodMapping javadoc
MappingReigstry javadoc
LinkedMultiValueMap javadoc

본 글은 Strategy Design Pattern with in Spring Boot application.을 번역한 글입니다.

잘 쓰여진 글을 정리 하는 겸 한글로 공유하고 싶어서 번역했습니다.

전략 디자인 패턴은 실행 중에 알고리즘을 선택하게 해주는 행동 디자인 패턴이다.

전략 디자인 패턴의 의도는 다음과 같다 :
"알고리즘 집합을 선언하고, 각각을 캡슐화하며 그것들을 교체가 가능하게 만든다. 전략 패턴은 알고리즘을 사용하는 유저와는 독립적으로 알고리즘을 다양하게끔 한다."

UML Class와 sequence diagram

전략 패턴의 다이어그램
전략 디자인 패턴을 설명하고 다양한 언어로 그것을 구현하는 많은 글들이 시중에 있다.
이 글의 목적은 스프링 부트 어플리케이션에서 전략 패턴을 어떻게 구현하는지 알려주는 것이다.

스프링 부트

스프링 부트는 Java microservice 개발의 실질적 표준이 되었다. 스프링 부트 어플리케이션에서 자주 쓰이는 디자인 패턴들을 어떻게 구현하는지 아는 것은 유용할 것이다.

스프링은 의존성 주입을 위해 @Autowired annotation을 도입했다. 모든 스프링 구성요소는 주입이 가능하다. 구성요소에는 components, configurations, services, bean들이 있다.

이 글에서 우리는 의존성 주입에 전략 디자인 패턴을 구현할 것이다.

첫번째로, 우리는 전략 패턴에 필요한 알고리즘 집합을 구현하면서 시작한다.
아래가 전략 패턴을 위한 인터페이스다. 그리고 enum으로 정의된 StrategyName을 이용해서 각각의 전략을 구분한다.

public interface Strategy{
    void doStuff();

    StrategyName getStrategyName();
}

public enum StrategyName{
    StrategyA,
    StrategyB,
    StrategyC
}

아래는 전략 패턴을 위한 세가지 알고리즘이다. 각각의 알고리즘은 StrategyName을 기준으로 구분된다. 전략들을 구분하는데 있어서 String보다는 enum을 사용하는 것이 더 좋다.

@Component
public class StrategyA implements Strategy{

    @Override
    public void doStuff(){
        // 알고리즘 A 구현하기
    }

    @Override
    public StrategyName getStrategyName(){
        return StrategyName.StrategyA;
    }
}

@Component
public class StrategyB implements Strategy{

    @Override
    public void doStuff(){
        // 알고리즘 B 구현하기
    }

    @Override
    public StrategyName getStrategyName(){
        return StrategyName.StrategyB;
    }
}

@Component
public class StrategyC implements Strategy{

    @Override
    public void doStuff(){
        // 알고리즘 C 구현하기
    }

    @Override
    public StrategyName getStrategyName(){
        return StrategyName.StrategyC;
    }
}

이제 우리는 StrategyFactory를 다른 스프링 bean으로 만들고, 모든 전략을 factory에 주입한다. 여기서 StrategyFactory를 구성할 때 전략들을 Map을 이용해서 저장하는데, 이건 전략들을 lookup하는데 $$O(1)$$이 걸리게끔 한다.

@Component
public class StrategyFactory {
  private Map<StrategyName, Strategy> strategies;

  @Autowired
  public StrategyFactory(Set<Strategy> strategySet) {
     createStrategy(strategySet);
  }

  public Strategy findStrategy(StrategyName strategyName) {
     return strategies.get(strategyName);
  }
  private void createStrategy(Set<Strategy> strategySet) {
      strategies = new HashMap<StrategyName, Strategy>();
      strategySet.forEach( 
   strategy ->strategies.put(strategy.getStrategyName(), strategy));
  }
}

이제 StrategyFactory@Autowired를 이용해서 주입받을 수 있게 되었다. 아래가 StrategyFactory를 사용한 예제 코드다.

@Service
public class SomeService {
    @Autowired
    private StrategyFactory strategyFactory;

    public void findSome(){
    // 이름을 전달해서 전략을 가져올 수 있다.
    Strategy strategy = strategyFactory.findStrategy(StrategyName.StrategyA);

    // 이제 전략에 정의된 메소드를 호출할 수 있다.
    strategy.doStuff();
    }
}

결론

지금까지 스프링 부트 어플리케이션에서 의존성 주입을 전략 패턴을 이용해서 하는 방법을 살펴보았다.

더 많은 정보는 The Strategy design pattern에서..

첫 번역글인데 영문 어체를 한국어로 어색하지 않게 전달하는게 쉽지 않네요.

전략 패턴을 사용하면 실행 중에 알고리즘을 교체할 수 있는데 원글에서 그런 부분 설명이 빠진점이 아쉽습니다.


"합격후기" 라는 제목의 글을 작성하는 것이 이렇게나 빨리 올 줄 몰랐습니다.
기대해왔던 회사였으며, 또 역설적으로 전혀 기대하지 않았던 회사였습니다.

 

이제 막 학교를 졸업하는 쌩신입 개발자로써 토스 NEXT 개발자 챌린지 '서버' 부문에 합격한 후기와 아주 간략한 준비과정등을 많은 분들에게 공유하고 싶어서 글을 적습니다.

들어가며

저는 제 삶을 시트콤이라고 많이 말을 합니다.
항상 무언가 기억나는, 그리고 동시에 다른 사람들이 쉽게 겪어보지 못하는 에피소드들로 가득차 있고, 대다수의 사람들이 겪는 일반적인 루트와는 다른 루트를 경험하곤 합니다.

또 시트콤

전역하자마자 3학년의 신분으로써 카카오 공채의 최종 탈락도 경험해보았고,
이번에는 취준을 시작하자마자, 그리고 개강하자마자 첫날에 좋은 소식을 받게 되었습니다.

취준생의 마인드

남들보다는 조금 일찍 개발자 공채의 프로세스를 겪으면서, 아주 좋은 마인드셋을 장착하게 되었습니다.


바로 "이대로가다는 진짜 큰일 나겠다" 의 마인드였습니다.
카카오 공채 프로세스를 겪기 전에는 코딩테스트는 적당히 1~2달이면 될 줄 알았으며, 개발에 필요한 스택들은 4학년이 되면 얼추 다 알겠거니 하는 아주 naive한 마인드를 가지고 있었습니다.

 

그랬던 제가 공채를 겪고나니 정말 이대로는 안되겠다 싶어서 기존의 알고리즘 스터디를 리비젼하고, CS 스터디를 직접 모으고, 'Real MySQL' 과 같은 책으로 저만의 엣지포인트도 빡세게 준비를 했습니다.

 

그럼에도 부족한게 있었습니다.

부족한 점

다들 아시겠지만, 대부분의 빅테크 기업의 서버개발자들은 높은 확률로 Java+Spring 기반의 개발을 진행합니다. 따라서 신입 개발자를 뽑는 공고의 JD여도 Java+Spring에 대한 언급이 있더라구요.

요즘엔 Kotlin+Spring으로 보입니다.

물론, 큰 기업이기에 필수 자격요건이 아닌 회사들이 더 많지만, 최소한 우대조건에는 무조건 들어가곤 했습니다.

토스에서도 아래와 같이 기술스택을 명시하고 있습니다. 다만, 아래 기술에 대한 경험이 없어도 괜찮아요. 라는 말이 달려 있기는 합니다.

그런데, 저는 위의 기술들 중 경험해본걸 찾는게 더 빠를 정도로 할 수 있는게 없었습니다.
Spring에 대해서 아주 기초적인 부분만 알고 실제로 사용해보지는 않았거든요.

 

거기다, 일반적으로 많은 개발자들이 갖추는 알찬 프로젝트(심지어 토이도!)의 존재가 저는 없습니다.
정확히는 최근 1~2년간 했던 프로젝트라곤, 현장실습에서 진행한 프로젝트가 전부였습니다.

 

또, 저와 같은 취준생들이 가장 무시무시하게 여기는 존재, "중고신입" 들은 저런 기술을 어느정도 익히고 오기 때문에 토스 NEXT 전형에 대한 기대를 전혀 하지 않았습니다.

 

요약하자면, 쌩신입이어서 실무 경험X + 자프링 할줄 모름 + 프로젝트 없음 의 노답 3형제였습니다.

동년배들은,,,이 짤,,,다 안다,,

과정

그래도, 지원은 공짜이고, 자소서와 같은 것들을 바로 요구하지 않기 때문에 바로 지원해보았습니다.
또 지인 중에 토스에 재직하는 사람이 있어 밥도 얻어 먹으면서 "제발 지원해봐라" 라는 말을 수차례 들었기에 밥값은 해야지 하면서 지원했습니다.

상상이상의 코딩테스트(근데 서술형이 찐보스)


첫 관문은 코딩테스트 입니다.

토스의 코딩테스트 중 서버 파트는 알고리즘문제와 서술형으로 구성되어 있고
알고리즘 7문제를 1시간 30분, 서술형 5문제를 30분 동안 풀이하는 것이였습니다.

 

알고리즘 7문제에 1시간 30분이니까 매우 난이도 낮은걸 예상할 수 있었고, 서술형 5문제에 30분이니 기초적인 CS 문제라고 예상했습니다.

 

그러니까 제 생각에는 "아~ 코테는 그냥 다 붙이고 면접 왕창 보려나보다!" 라고 안일한 생각을 했습니다.

그런데, 혹시 여러분 이런거 아시나요?

최종흑막은 항상 예상치 못한 인물인것처럼, 서술형 문제가 가장 어려웠습니다.


자세하게는 말할 수 없지만, 서술형 문제는 실제 개발을 해보면서, 혹은 경험해보진 않았더라도 충분히 있을법한 상황들의 문제들로 구성이 되어 있었습니다.

 

단순 CS 문제가 아니라, 서버 개발자로써의 아주 근본적인 자질과 논리적인 사고력을 요구하는 문제들이였습니다.

특히, 신입 개발자들은 아마 이 서술형문제에서 많이 헤맸을것 같습니다. 학부생 수준의 프로젝트에서는 쉽게 겪어보지 못할 상황들이니까요.

저는 다행히 평소에 관심가지는 토픽들에 기반한 지식과 모르겠다면, 기초에 입각해서 최대한 풀려고 노력했습니다.

개발은 잘 못하지만, 여기저기 관심 가지는 저같은 유형도 이럴데는 꽤 쓸모가 있더라구요.

그래서 알고리즘 문제는 6/7문제, 서술형 문제는 5문제 중 4문제 정도는 정답에 꽤 가깝게 적었다고 생각하고, 1문제는 긴가민가 했습니다.

실제로 알고리즘 문제를 다 푸셨더라도, 서술형 문제에서 헤매신분들이 많이 떨어진것으로 보아 서술형을 꽤 비중있게 채점했다고 생각합니다.

참고로 한 문제당 정말 아무리 오래 걸려도 20분안에는 풀 수 있을법한 문제였습니다.

자괴감의 경력기술서

주변에 말은 최대한 아끼고 있었지만, 서술형을 잘 보았다는 생각을 하고 있어서 어느 정도는 예상했습니다.

흔히 말하는 연막작전이였습니다. 괜히 말했다가 떨어지면 부끄럽잖아요

토스는 어떤 특정한 포맷이 있거나, 고정적인 문항이 있는 자소서가 아닌 본인의 기술적 역량을 가장 잘 표현할 수 있는 경력기술서 형태의 이력서를 제출합니다.

 

여기서 또 난관에 봉착합니다.

위에서 언급한 대로 3무(경력없음,자프링할줄모름,개인프로젝트없음) 의 노답지원자에게는 이 과정이 정말 고통스러웠습니다.

 

그래서 마음을 비우고 딱 하나의 대전제만 세우고 접근했습니다.

  • 진짜 설명할 자신 있는것만 적고, 나머지는 적지말자.

가장 최근에 한 현장실습에서 했던 프로젝트 중에서, 자신있게 설명할 수 있는 몇가지 업무들만 적되, 수치로써 표현하자라는 마음가짐으로 작성했습니다.

개인적인 생각으로 개발자 이력서의 바이블이라고 생각하는 워니님의 개발자 이력서 작성하기를 많이 참고했습니다.

숨막히는 1차면접


기술면접은 지옥입니다. 왜냐면, 꼬리에 꼬리를 무는 질문들로 구성되니까요.


3~4단계의 꼬리질문이 이어지고, 그 과정에서 본인이 잘 모르면 솔직하게 모른다고 답하는게 좋다고 할 정도로 빡셉니다.

제가 적은 프로젝트에서 물어볼법한 예상 질문들을 약 40개정도 정리했고, 그 질문들만은 최선을 다해서 완벽하게 준비했습니다.

예를 들어서 A라는 기술을 이용해서 기존 시스템의 B라는 문제점을 파악하고 해결해 00%만큼의 수치 개선이 있었다. 라고 해봅시다.

  1. 그러면, A가 뭔지?
  2. A말고 다른 선택지는 없었는지?
  3. B가 왜 문제점이라고 생각하는지? 기준은 뭔지?
  4. 그 A라는 해결책이 어떠한 특정한 상황(예를 들면 확장시)에도 유리한지?
  5. 저 00%라는 수치는 어떻게 해서 나왔다고 생각하는지? 등등...

그냥 단순하게 적은 한 문장에서 순식간에 5개의 질문이 나올 수 있고, 각각의 질문들이 또 다른 질문으로 이어지기도 합니다.

그래서 기존의 CS 정리한 파트(PDF로 치면 거의 20-30장 이상은 나오는 분량인)와 제 프로젝트에 대한 질문들을 계속 보면서 면접을 준비했습니다.

 

코딩테스트의 서술형 문제들 역시 복기하면서 제 기존 답변들에 대한 추가적인 문제점은 없는지도 매우 깊게 고민했습니다.

이때 가장 도움이 된 책이 "가상 면접 사례로 배우는 대규모 시스템 설계 기초"라는 책인데, 이 책을 추천해주신 SK 브로드밴드의 김정모님에게 감사를 바칩니다.

대망의 면접날이 되었고 기술면접은 약 1시간 30분 정도로 진행되었습니다.

 

처음에는 땀이 줄줄나는 시간이였지만 그 후부터는 긴장이 어느정도 풀려 제가 알고 있는 지식을 테스트하는 시간이 아닌, 기술적인 의견을 나누는 시간이였습니다.

물론 그 과정에서 날카로운 질문들이 들어오기도 했습니다. 진짜 날카로웠습니다.

다만, 그 과정에서 제가 몇가지 질문들에 대해서 완벽하게 답변을 못했고 울고 싶어졌습니다.

사실 그 질문들은 매우 기초적인것들이였고, 심지어 제가 그 주제들로 발표를 한적도 있는 주제여서 더 슬펐습니다.

대략 15-20분 정도의 역질문 시간이 있었는데, 이때 저는 기술적 궁금증과 더불어서 토스의 현직자들은 어떠한 생각을 가지고 일에 임하는지 등에 대한 질문을 했습니다.


또 제 면접에 대한 짧은 피드백도 요청드렸고, 감사하게도 솔직하게 말씀해주셨습니다.

 

이 글을 보시는 취준생분들은 꼭 이 역질문 시간을 잘 활용하셔서 본인의 수준에 대한 지표와 기술적 궁금증을 꼭 해결하셨으면 좋겠습니다.

고요의 2차면접


1차 면접을 보고, 개인적인 약속이 있어 외출을 하고 왔는데, 전화로 1차 합격여부를 전달받았습니다.너무 벙쪄서, 제가 아무말도 안하니 리크루터분이 오히려 당황하셨는데, 조금 죄송스러웟습니다ㅎㅎ...

 

아무튼 2차 면접을 준비하게 되었습니다.

 

토스의 2차면접은 컬쳐핏 면접으로 구성이 되는데, "이 지원자가 출중한가? 기술적으로 검증된 사람인가?" 가 아니라, "이 지원자가 우리 회사에 적합한 사람인가?" 를 가리는 면접이라고 알고 있었기에 크게 준비할 것이 없었습니다.

 

다만, 반대로 준비할것이 없었기에 더 막막했습니다.

 

그래도 어느정도는 해야했기에 토스피드와 토스유튜브를 봤는데, 제 생각에 변화가 좀 생겼습니다.

기존에는 "도대체 얼마나 높은 work-ethic을 원할까" 였는데, 토스의 문화를 소개하는 영상을 보니
"이게 진짜 회사에서 가능한 일이야?" 라고 생각하게 되었고, "이런곳에서 일하는 사람들이 매우 궁금하다" 로 생각이 바뀌게 되었습니다.

인턴을 제외하고 회사 경험이 전무한 저에게는 뭔가가 신기했습니다.

그래서 기존의 잡스럽게 준비하던 문항들을 다 치우고, 그냥 토스의 문화만 구경하면서 시간을 보냈습니다.

2차 면접은 1:1으로 진행되었고, 저녁쯤에 1시간 40분정도 진행했습니다.


끝나고나서 드는 생각은 "역시 나는 무리다" 라는 생각이 들었습니다.

토스의 현직자 지인은 컬쳐핏을 1시간 40분 진행했다는 말을 듣고 합격을 직감했다고 합니다.

왜냐하면, 제가 실무 경험이 부족한 사람으로써의 안 좋은 특징들을 많이 보여줬다고 생각했기 때문이었습니다.

그런데...

개강첫째날 엘리베이터에서

저는 아직 1학기가 남아있기에 9월 1일 첫 수업을 가기위해서 학교 건물 엘리베이터를 탔는데, 리크루터분에게 전화가 오게 되었고, 최종합격이라는 소식을 듣게 되었습니다.

 

취준이 시작되는 4-2학기의 개강 첫날의 첫 수업 시간에 합격소식을 듣게 되었습니다.

믿기지 않는 결과지만,그리고 제가 왜 합격했는지 여전히 알수가 없지만 어쨌든 핀테크 분야의 최고회사에 합격하게 되었더라구요.

 

뭔가 허무하지만 이게 끝입니다. ㅋㅋㅋ

후기

이렇게 3무의 개발취준생은 토스로 가게 되었습니다.

쌩신입이어서 실무 경험X + 자프링 할줄 모름 + 개인 프로젝트 없음

아무것도 없는 제가 합격할 수 있었던 이유를 찬찬히 생각해보았을때 이런것 같습니다.

  • 단순히 작동여부보다는 그 내면의 동작원리에 대해서 너무나 심취해있고
  • 제가 했던 것을 남들한테 설명해줄때 가장 신나는 사람이였고
  • 컴퓨터공학을 활용한 기술적 성장을 좋아하는 사람

"토스라면 경력직만을 좋아하겠지", "3년 이하의 중고신입들이랑 쌩신입인 내가?" 라는 생각이였기에 전혀 기대하지 않았습니다.

그럼에도 그냥 기초에 입각해서 하게 되니 좋은 결과를 얻을 수 있었네요.

 

작년 이맘때쯤에 카카오 공채에 실패해서 슬퍼했는데, 올해는 행복한 한해 마무리가 될 것 같습니다.

끝으로 제 취준에 동참해주신 스터디원 3명에게 무한한 감사를......

자세한 내용은 많이 생략했으니, 저를 개인적으로 아시는 분들 중에 연락주시면 문제가 되지 않는 선에서 도와드릴 수 있습니다!!

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

3학년의 2022 카카오 블라인드 공채 도전기  (0) 2022.04.08

+ Recent posts