Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scenario Test: 인수 테스트 자동화로 자신감, 생산성 높이기 (Gopher...

JaewonKim
August 18, 2023

Scenario Test: 인수 테스트 자동화로 자신감, 생산성 높이기 (GopherCon 2023 발표)

- 성능, 강타입 언어 등의 이점을 누리기 위해 거대한 레거시 시스템을 Python에서 Go로 마이그레이션 했던 경험을 간단하게 소개합니다.
- 마이그레이션 검증 과정에서 큰 역할을 했던 자동화 테스트 도구 Scenario Tester를 Go로 개발하기 위해 사용했던 전략, 도구 등을 소개합니다.
- 그럼에도 불구하고 발생했던 장애 경험과 개선기를 공유합니다

JaewonKim

August 18, 2023
Tweet

Other Decks in Programming

Transcript

  1. GopherCon Korea 2023 Scenario Test 김재원 @ AB180 & Airbridge

    인수 테스트 자동화로 자신감, 생산성 높이기 GopherCon Korea 2023 Data Pipeline Team Lead [email protected] https://abit.ly/ab180-scenario-test
  2. GopherCon Korea 2023 Index • 배경 소개 • Scenario Test

    • Lessons Learned • What’s Next • Q&A
  3. GopherCon Korea 2023 Airbridge Data Pipeline 1) WAS 마이그레이션: Python

    -> Go 2) Worker 마이그레이션: Python -> Rust 3) DB 마이그레이션: DynamoDB -> ScyllaDB 4) 네트워크 비용 최적화 비용 최적화 액션 아이템
  4. GopherCon Korea 2023 Airbridge Data Pipeline 2) Worker 마이그레이션: Python

    -> Rust AS-IS: TO-BE: - 성능이 매우 중요한 부분에 Rust 도입 및 분리를 결정함 - Preprocessing 로직이 매우 복잡한데 - 이 복잡한 걸 Python, Rust로 둘 다 유지보수 해야하는 상황
  5. GopherCon Korea 2023 Airbridge Data Pipeline 2) Worker 마이그레이션: Python

    -> Rust TO-BE: - 성능이 매우 중요한 부분에 Rust 도입 및 분리를 결정함 - Preprocessing 로직이 매우 복잡한데 - 이 복잡한 걸 Python, Rust로 둘 다 유지보수 해야하는 상황
  6. GopherCon Korea 2023 Airbridge Data Pipeline 2) Worker 마이그레이션: Python

    -> Rust TO-BE1: TO-BE2: Preprocessor를 Golang으로 만들어서 전처리를 한 데이터를 따로 만들기로 결정!
  7. GopherCon Korea 2023 1. Touchpoint Worker는 성능이 매우x100 중요해서 Rust로

    결정 2. Preprocessor는 성능도 중요하긴 하지만 유지보수 가능 여부가 훨씬x100 중요해서 Golang으로 결정 Airbridge Data Pipeline 2) Worker 마이그레이션: Python -> Rust
  8. GopherCon Korea 2023 마이그레이션 검증은 어떻게? 1. 단위 테스트는 최대한

    옮긴다 2. 필요한 통합 테스트 또한 옮긴다 3. 인수 테스트는 전부+ 더 만들어서 옮긴다 - 기존 Python 코드로 일주일치 테스트 케이스를 만듦 - 확신을 매우 높여줌
  9. GopherCon Korea 2023 인수 테스트 (Acceptance Test) - Given: 어떤

    환경이 주어졌을 때 - When: 어떤 요청사항이 들어온다면 - Then: 이런 결과가 나오길 기대한다
  10. GopherCon Korea 2023 기존 인수 테스트의 문제 1. 매번 짜야하는

    코드가 많음 - 그래서 잘 안짜게 되거나 생산성이 떨어짐 - Framework이 없다면 각자 다른 스타일로 짜게 됨 - 규칙을 정할 순 있겠으나, 강제하기 어려움 2. 어떤 인수테스트가 있는지 한 눈에 보기 어려움 - 이 서비스에는 어떤 기능적인 요구사항을 만족하고 있을까? 3. 언어 변경을 하게 된다면 사람이 손으로 옮겨줘야 함 - 언어를 변경할 일은 잘 없으니 참을만 함
  11. GopherCon Korea 2023 Scenario Test 자동화된 인수 테스트 Scenario: “json

    형태”의 인수 테스트 케이스 하나 - (Given) Context: 이 데이터를 처리하기 위해 필요한 외부 데이터 (RDB 데이터, OS 환경변수 등) - (When) Input: 실제 Component의 Input - (Then) Output: 기대하는 Output (Kafka로 보내야하는 데이터, Cache에 써야하는 데이터 등) my_scenario.json
  12. GopherCon Korea 2023 Scenario Test 1. 기존 Python 코드로 일주일치

    Scenario를 만듦 - Kafka -> Generator(on ECS) -> Kafka 구조로 생성 - 100억 개가 넘는 케이스를 생성 - 장애 방지를 위해 Scenario Generator 전용 Infra를 다 새로 띄워 격리시킴 2. 만들어진 Scenario로 Golang 코드 검증 - Kafka -> Tester(on ECS) -> Kafka 구조로 테스트 - 실패한 케이스만 모아두고 로컬에서 검증 - 코드 다 고쳤으면 다시 검증 마이그레이션 과정에서의 활용
  13. GopherCon Korea 2023 Scenario Test 1. encoding/json 패키지에서 생긴 이슈

    - “<”와 “>”를 unicode escaping 해버림 단위 테스트로는 못잡았던 케이스 “>” 를 “\u003e”로 바꿔버리는 모습.. 🤦
  14. GopherCon Korea 2023 Scenario Test 1. encoding/json 패키지에서 생긴 이슈

    - “<”와 “>”를 unicode escaping 해버림 단위 테스트로는 못잡았던 케이스 Marshal을 이런 식으로 해서 해결 (별로 행복하진 않음)
  15. GopherCon Korea 2023 Scenario Test 1. encoding/json 패키지에서 생긴 이슈

    - “<”와 “>”를 unicode escaping 해버림 - json.Unmarshal을 할 때 case-insensitive하게 받음 단위 테스트로는 못잡았던 케이스 key를 “lowercase_key”로 정의했으나 “LOWERCASE_KEY”도 받아주는 모습.. 🤦
  16. GopherCon Korea 2023 Scenario Test 1. encoding/json 패키지에서 생긴 이슈

    - “<”와 “>”를 unicode escaping 해버림 - json.Unmarshal을 할 때 case-insensitive하게 받음 단위 테스트로는 못잡았던 케이스 <해결> A. Case Sensitivity가 중요하지 않은 struct(정해진 값만 들어오는 것이 확정)는 Known-issue로 처리 B. Case Sensitivity가 중요한 struct는 정해진 Key만 받도록 Unmarshal을 직접 구현 (별로 행복하지 않음... 😭 더 좋은 방법/라이브러리가 있다면 알려주세요)
  17. GopherCon Korea 2023 Scenario Test 1. encoding/json 패키지에서 생긴 이슈

    - “<”와 “>”를 unicode escaping 해버림 - json.Unmarshal을 할 때 case insensitive하게 받음 2. 그외 미처 생각도 못했던 곳에서 발생했던 실수 - Timestamp를 13자리(ms)로 기록해야하는데 10자리(sec)로 기록함 - 잘못된 hash 알고리즘으로 hashing을 함 단위 테스트로는 못잡았던 케이스 (기억은 다 안나지만, 이거 보다 훨씬 많은 케이스가 있었습니다)
  18. GopherCon Korea 2023 Scenario Test 1. Dependency Injection이 쉬운 구조로

    코드를 짜놔야 편하다 - Mock Infra로 쉽게 교체할 수 있어야 Generator/Tester를 만들기 편함 2. 활용한 도구 - https://github.com/yudai/gojsondiff - Diff가 생겼을 때 예쁘게 볼 수 있음 - https://pkg.go.dev/gorm.io/gorm/callbacks#AfterQuery - gorm AfterQuery Callback을 통해 Context를 capture할 수 있음 3. stdin, stdout(+ Makefile)을 잘 활용하면 쉽게 생성/테스트 할 수 있다 만들때 팁
  19. GopherCon Korea 2023 Scenario Test 만들때 팁 https://github.com/yudai/gojsondiff 어떤 테스트

    케이스에서 어떤 Diff가 생겼는지 시각화 해주어서 디버깅 하기 아주 좋음 👍 (빨간색은 원래 기대한 결과, 초록색은 현재 결과)
  20. GopherCon Korea 2023 Scenario Test 1. 개발 공수가 많이 든다

    - 고도화를 하다보니, 서비스 하나를 만드는 수준의 공수가 들었음 - 언어마다 다 각자 개발해줘야 함 (Python, Go, Rust) 2. Scenario Generator/Tester를 잘못 만들면 말짱 도루묵 - 일반적으로 짜는 테스트 코드 보다 복잡하기 때문에 실수하기 더 쉬움 단점
  21. GopherCon Korea 2023 Scenario Test - 기존 Python Scenario Generator에서

    Scenario를 잘못 만듦 - Input Data를 코드에서 다루다가 변경해버림 - A -> A’ 로 바뀐 상태로 Scenario가 저장됨 - A’를 Input으로 받는 코드를 작성해서 Golang으로 신나게 검증을 함 🥲 겪었던 장애 - Scenario를 잘못 만든 케이스 Input Data는 불변성을 보장할 수 있도록 장치 추가
  22. GopherCon Korea 2023 1. 한 번의 큰 장애 🥲 (및

    성장) 2. 15배 효율적인 이벤트 처리 (월 천 만원 이상의 비용 절감 효과 🤑) 3. Python -> Go - 강타입 언어라 유지보수 하기 훨씬 용이함 👍 - 훨씬 좋은 성능 👍 - 더 확장성 있는 구조로 변경됨 👍 마이그레이션 결과
  23. GopherCon Korea 2023 Lessons Learned • 마이그레이션을 하면서 겸사겸사 리팩토링을

    하면 오히려 안좋다 ◦ 매몰작업이 될 수 있더라도 미리 리팩토링을 하고, 같은 구조로 옮겨야 검증이 쉬움 • 일정은 더 넉넉히 잡아야 한다 (자기 자신을 과대평가 하지 말자) ◦ 처음에 2개월 정도 걸릴줄 알았으나 4개월 걸림 • 리팩토링을 이제 정말 자신있게 할 수 있게 되었다 ◦ 레거시를 다시 짜면서 성능 뿐만 아니라 오히려 생산성도 올라감 ◦ 하지만 이때 제일 조심해야됨
  24. GopherCon Korea 2023 What’s Next 1. 여러 컴포넌트에 걸친 테스트를

    할 수 있게 하기 - A Service의 Output을 B Service의 Input으로 씀 - 한 서비스의 시나리오 파일은 Downstream 서비스들에 다 포함돼야 함 2. 언어에 구애받지 않는 단일화된 Generator/Tester 만들기 - 현재는 언어마다 각자의 Generator/Tester가 있음 - 관리도 힘들고 사용법도 각자 조금씩 다름 - 잘 만들어서 Open Source화를 할 수 있으면 좋지 않을까 3. 비기능적 요구사항도 테스트