2021년 9월 2일 목요일

카카오 모빌리티에서 카오너 개발팀이 일하는 방식

개요

개발팀이 일하는 방식을 정리합니다.

개발팀에서 일을 더 잘하는 10가지 방법.

  1. 이끌거나, 따르거나, 떠나거나. 
  2. 실행은 수직적! 문화는 수평적.
  3. 잡담을 많이 나누는 것이 경쟁력이다.
  4. 개선 사항은 이슈화 한다. 설령 해결되지 않더라도.
  5. 보고는 팩트에 기반한다.
  6. 일의 목적, 기간, 결과, 공유자를 고민하며 일한다.
  7. 책임은 실행한 사람이 아닌 결정한 사람이 진다.

  8. 고민은 반나절만!, 주변에 항상 질문한다.
  9. 나의 성장은 조직의 성장이다.
  10. 개개인의 능력보다 조직력으로 승부한다.


일하는 방식

코드리뷰

코드리뷰는 필수다.

  • Approved는 최소 1인이다.
  • 코드리뷰어가 존재하지 않는 경우 상위 조직장, 그 상위 조직장이 없으면 팀장까지 리뷰어로 포함 시킨다.
  • 코드리뷰를 하지 않는 경우는 다음과 같다.
    1. 도메인에 대해 혼자 개발하는 경우.
    2. 코드 리뷰 요청 후 36시간 이상이 지나도록 아무도 보지 않는 경우. (주말 제외)
  • 모든 조직장은 API의 Request, Response, URI 스펙은 필수로 점검한다.
    1. 한번 나간 API는 회수가 불가능하기 때문.
  • PR에 대한 코드는 PR을 올린 사람이 리뷰어를 귀찮게 해서라도 코드리뷰를 하도록 한다.

PR Reject는 1회만 한다.

  • 어떠한 이유로 변경을 요청하기 위해 Reject를 하는 경우 수정 후 다시 Reject 하지 않는다. 
    • 코드 리뷰는 100% 완벽을 요구하는 것이 아니다. 
    • 다시 Reject을 해야 할 것 같은 상황이라면 페어코딩해라. PR에서 댓글로 논쟁을 벌이는건 얻는게 없다.
  • 코드의 스타일(conventions)으로 Reject을 하지 않는다.
    • 코드 스타일은 Linter를 이용해라.
    • 컨벤션을 맞추고 싶으면 PR건에서 이야기 할 것이 아니라 해당 프로젝트의 규칙을 잡는다.

Slack

  • Slack의 멘션은 필요한 경우 상대방을 고려하지 않고 맨션한다. (휴가 무관)
    • 맨션을 받고 싶지 않으면 Slack의 "알림 일시 중지"를 이용한다.
    • 메일로 일하지 않기 때문에 맨션을 하지 않으면 해당 업무에 대해 놓칠 수 있다. 
    • 멘션을 걸 때 멘션의 대상자가 업무를 파악 할 수도 못할 수 도 있다는 것을 기억 해야 한다. 
      • 휴가 or 휴식 or 알림 중지 등등 
  • 휴가를 가는 경우 Slack의 "휴가 중"을 꼭 설정한다.
    • 본인이 휴가를 간다는 것을 알리는 필수 수단이다.
    • 휴가에 방해를 받고 싶지 않으면 '알림 일시 중지'를 꼭 활용하자. 그리고 보지 말자.
      • 정말 크리티컬 한 경우 전화를 하게 되어 있다. (그러니 휴가를 간 사람에게 왠만한 크리티컬 한 이슈가 아닌 이상 휴가 복귀 후 업무를 F/U 하도록 멘션은 걸되 연락하진 말자.)

Release

지향점 > 빠른 배포, 빠른 롤백

  • 릴리즈 주기는 짧게(1주일에 최소 1번) 간다. 
    • QA가 있는 것 아닌 이상 짧게 간다. 
  • 릴리즈는 퇴근 시간 2시간 전, 그리고 금요일에 하지 않는다.

Hotfix

  • Hotfix를 할 때는 무조건적인 페어코딩 or PR 리뷰를 한다.
    • hotfix 때 side effect로 인한 장애가 더 많이 난다.
    • 그러니 일단 침착하고 그 누구든 옆에 본인의 코드를 검증 해줄 사람을 둔다.
    • 아무도 없으면 fennec에게 전화를 해서라도 hotfix 전에 코드를 검증 받는다.


마지막으로

탄탄한 조직은 굳이 Rule이 필요 없다. 서로의 신뢰로 모든게 동작하기 때문이다.


2021년 8월 12일 목요일

springboot 2.5 x & spring-cloud-starter-vault-config 오류 해결하기

 Springboot 2.5.x 버전은 spring-cloud-starter-vault-config 2.2.X 버전과 현재(2021.08.12)는 되지 않는다.


이런 오류가 난다.

Caused by: java.lang.IllegalStateException: Failed to introspect Class [org.springframework.cloud.context.properties.ConfigurationPropertiesBeans] from ClassLoader [sun.misc.Launcher$AppClassLoader@18b4aac2]
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481) ~[spring-core-5.3.8.jar:5.3.8]
at org.springframework.util.ReflectionUtils.doWithLocalMethods(ReflectionUtils.java:321) ~[spring-core-5.3.8.jar:5.3.8]
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.buildPersistenceMetadata(PersistenceAnnotationBeanPostProcessor.java:417) ~[spring-orm-5.3.8.jar:5.3.8]
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findPersistenceMetadata(PersistenceAnnotationBeanPostProcessor.java:388) ~[spring-orm-5.3.8.jar:5.3.8]
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(PersistenceAnnotationBeanPostProcessor.java:335) ~[spring-orm-5.3.8.jar:5.3.8]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:1098) ~[spring-beans-5.3.8.jar:5.3.8]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576) ~[spring-beans-5.3.8.jar:5.3.8]
... 30 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_252]
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_252]
at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_252]
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463) ~[spring-core-5.3.8.jar:5.3.8]
... 36 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_252]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_252]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) ~[na:1.8.0_252]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_252]
... 40 common frames omitted

대충 보면 ConfigurationBeanFactoryMetadata class를 못찾는다는 뜻이다.

이유는 Springboot와 Springcloud의 Release Train이 다르기 때문에 아직 의존성이 깔끔하게 해결되지 않아서다.

참조: https://spring.io/projects/spring-cloud#overview 

Adding Spring Cloud To An Existing Spring Boot Application

If you an existing Spring Boot app you want to add Spring Cloud to that app, the first step is to determine the version of Spring Cloud you should use. The version you use in your app will depend on the version of Spring Boot you are using.

The table below outlines which version of Spring Cloud maps to which version of Spring Boot.

Table 1. Release train Spring Boot compatibility
Release TrainBoot Version

2020.0.x aka Ilford

2.4.x, 2.5.x (Starting with 2020.0.3)

Hoxton

2.2.x, 2.3.x (Starting with SR5)

Greenwich

2.1.x

Finchley

2.0.x

Edgware

1.5.x

Dalston

1.5.x

Spring Cloud Dalston, Edgware, Finchley, and Greenwich have all reached end of life status and are no longer supported.

해서 이 둘을 연결하려면 gradle 설정이 좀 필요하다.

gradle 설정은 대충 다음처럼 하면 된다. (참고로 아래코드는 kotlin dsl을 이용했따)


ext {
set("springCloudVersion", "2020.0.3")
}
configure<io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension> {
imports(delegateClosureOf<io.spring.gradle.dependencymanagement.dsl.ImportsHandler> {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:2020.0.3")
})
}


그리고 한가지 더 

원래 vault config는 bootstrap.yml을 읽어서 vault config를 하게 되었는데 

springcloud bootstrap 2020.X 버전 부터는 기본적인 application.yml 안에서 vault 설정을 읽게 바뀌었다.