Top Banner
10만 라인 26280시간 PYCON APAC 2016 Minyoung Jeong The Beatpacking Company
104

10만 라인, 26280시간의 이야기

Jan 25, 2017

Download

Technology

Minyoung Jeong
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 10만 라인, 26280시간의 이야기

10만 라인 26280시간

PYCON APAC 2016 Minyoung Jeong

The Beatpacking Company

Page 2: 10만 라인, 26280시간의 이야기

Minyoung Jeong

CTO, The Beatpacking Company

2014/2015 PyCON KR

Founder, AWSKRUG

AWS Community Hero

Love Python!

Page 3: 10만 라인, 26280시간의 이야기
Page 4: 10만 라인, 26280시간의 이야기
Page 5: 10만 라인, 26280시간의 이야기

2013. 04. 04

Page 6: 10만 라인, 26280시간의 이야기

9 changed files with 787 additions and 0 deletions

Page 7: 10만 라인, 26280시간의 이야기

.gitignore README.rst

beat/__init__.py docs/Makefile docs/beat.rst docs/conf.py

docs/make.bat setup.py

Page 8: 10만 라인, 26280시간의 이야기

.gitignore README.rst

beat/__init__.py docs/Makefile docs/beat.rst docs/conf.py

docs/make.bat setup.py

Page 9: 10만 라인, 26280시간의 이야기

.gitignore README.rst

beat/__init__.py docs/Makefile docs/beat.rst docs/conf.py

docs/make.bat setup.py

Page 10: 10만 라인, 26280시간의 이야기

2016. 08. 10

Page 11: 10만 라인, 26280시간의 이야기
Page 12: 10만 라인, 26280시간의 이야기
Page 13: 10만 라인, 26280시간의 이야기
Page 14: 10만 라인, 26280시간의 이야기
Page 15: 10만 라인, 26280시간의 이야기

• REST API Server

• CMS

• Backoffice

• Automation

• … Client 개발을 제외한 거의 전부

Page 16: 10만 라인, 26280시간의 이야기

Single monolithic repository

Page 17: 10만 라인, 26280시간의 이야기
Page 18: 10만 라인, 26280시간의 이야기

스타트업에서 개발을 한다는건…

Page 19: 10만 라인, 26280시간의 이야기
Page 20: 10만 라인, 26280시간의 이야기

철로가 준비되는 시간을 기다려 주지 않는다

Page 21: 10만 라인, 26280시간의 이야기

일정을 개발이 주도하기 어렵고 변수가 많다

Page 22: 10만 라인, 26280시간의 이야기

목표 최소한의 품질은 항상 달성하자

Page 23: 10만 라인, 26280시간의 이야기

극한 직업 비트 개발팀이 일하는 법

Page 24: 10만 라인, 26280시간의 이야기

1. Fork

2. Push

3. Pull Request 4. Review & Approval

5. CI & Lint & Codecov 6. Result hook

7. Merge

Page 25: 10만 라인, 26280시간의 이야기
Page 26: 10만 라인, 26280시간의 이야기

“Github_장애.jpg”

Page 27: 10만 라인, 26280시간의 이야기

과업(Task) 단위의 PR

Page 28: 10만 라인, 26280시간의 이야기

“출시 3일전에 실행한 ‘git merge upstream master’ 에서 1395개의 충돌을 발견한 프로그래머”

Page 29: 10만 라인, 26280시간의 이야기

가능하면 작은 단위로

Page 30: 10만 라인, 26280시간의 이야기
Page 31: 10만 라인, 26280시간의 이야기

Review

Page 32: 10만 라인, 26280시간의 이야기
Page 33: 10만 라인, 26280시간의 이야기

Review의 이유

• 해당 구현에 대한 팀원간 이해를 높인다.

• 좀 더 나은 구현에 대한 토론을 가능하게 한다.

• 심지어는 해당 구현이 필요한지에 대한 얘기 조차도 할 수 있다.

• 인수 인계를 하게 된다(!)

Page 34: 10만 라인, 26280시간의 이야기
Page 35: 10만 라인, 26280시간의 이야기

Merge 정책

Page 36: 10만 라인, 26280시간의 이야기
Page 37: 10만 라인, 26280시간의 이야기

http://homu.io

Page 38: 10만 라인, 26280시간의 이야기
Page 39: 10만 라인, 26280시간의 이야기
Page 40: 10만 라인, 26280시간의 이야기

안전한 MASTER

Page 41: 10만 라인, 26280시간의 이야기
Page 42: 10만 라인, 26280시간의 이야기
Page 43: 10만 라인, 26280시간의 이야기
Page 44: 10만 라인, 26280시간의 이야기

테스트

Page 45: 10만 라인, 26280시간의 이야기
Page 46: 10만 라인, 26280시간의 이야기

무엇을 점검할까?

• 사람은 항상 실수한다. 실수를 blame하지 말고 실수를 하지 못하게 하자.

• 프로젝트가 시간이 지나면 지날수록 코드의 가독성은 바로 생산성이 된다.

• 테스트는 외부에 노출되는 Endpoint를 주된 목표로 하자.

Page 47: 10만 라인, 26280시간의 이야기
Page 48: 10만 라인, 26280시간의 이야기

lint - 개발 권고 사항 강제

Page 49: 10만 라인, 26280시간의 이야기

lint - import 실수 예방

Page 50: 10만 라인, 26280시간의 이야기
Page 51: 10만 라인, 26280시간의 이야기

flake8 / autopep8

Page 52: 10만 라인, 26280시간의 이야기

E501,F401,E402,F841

Page 53: 10만 라인, 26280시간의 이야기
Page 54: 10만 라인, 26280시간의 이야기

왜 Endpoint 위주로 테스트를 할까?

Page 55: 10만 라인, 26280시간의 이야기

미성숙한 요구사항 API 위주의 개발

Page 56: 10만 라인, 26280시간의 이야기

API 명세 산출

개념 구현

안정 구현

테스트

Page 57: 10만 라인, 26280시간의 이야기

• REST Endpoint를 호출하여 의도된 결과와 의도된 실패를 점검한다.

• 자명한 것 ( 1+1 = 2)을 테스트 한다. Framework나 의존성의 업그레이드시 발생하는 Breaking Changes에 대응할 수 있다.

• 외부 I/O에 대한 상태를 관리할 수 있다면 Mock보다는 실제 서버를 이용한다. (버그를 피하거나, 버그를 전제로 하거나.)

• 테스트에서 놓쳤던 버그는 테스트를 꼭 만들어 넣어야. 자존감을 유지할 수 있다.

Page 58: 10만 라인, 26280시간의 이야기

빠른 테스트는 매우 중요

Page 59: 10만 라인, 26280시간의 이야기

테스트가 느리면 CI를 장애물로 여기게 된다

Page 60: 10만 라인, 26280시간의 이야기

test coverage

Page 61: 10만 라인, 26280시간의 이야기
Page 62: 10만 라인, 26280시간의 이야기

만든 테스트의 유효성

Page 63: 10만 라인, 26280시간의 이야기

이 PR의 CI 통과를 얼마나 신뢰할 수 있는가?

Page 64: 10만 라인, 26280시간의 이야기
Page 65: 10만 라인, 26280시간의 이야기

문서

Page 66: 10만 라인, 26280시간의 이야기

–Hong Minhee , creator of Wand

“실수로 문서화를 영어로 했었음”

Page 67: 10만 라인, 26280시간의 이야기
Page 68: 10만 라인, 26280시간의 이야기

Sphinx + httpdomain

Page 69: 10만 라인, 26280시간의 이야기
Page 70: 10만 라인, 26280시간의 이야기

코드에서 문서를 찾는 개발자들.jpg

Page 71: 10만 라인, 26280시간의 이야기
Page 72: 10만 라인, 26280시간의 이야기

문서화에 실패한 이유

• 내부 고객(클라이언트 개발자)과의 커뮤니케이션에 있어서 주요한 수단이 되지 못했다.

• 문서를 보는 사람이 없으니 갱신이 되질 않아 문서 자체의 효용이 사라짐.

• 문서 자체의 효용이 사라져 다시 주된 수단이 되기 어려워 지는 악순환의 반복.

Page 73: 10만 라인, 26280시간의 이야기
Page 74: 10만 라인, 26280시간의 이야기

사업을 위해 부채를 피할 수 없는 것 처럼….

Page 75: 10만 라인, 26280시간의 이야기

적절한 기술 부채는 꼭 필요하다

Page 76: 10만 라인, 26280시간의 이야기
Page 77: 10만 라인, 26280시간의 이야기

적정 기술

Page 78: 10만 라인, 26280시간의 이야기

기술을 적용함에 있어 적정한 시점과 비용에 대한

고민

Page 79: 10만 라인, 26280시간의 이야기

오늘도 기술부채를 늘린 개발자가 용서를 구하고 있다.jpg

Page 80: 10만 라인, 26280시간의 이야기

사례1. 비용 평가의 실패

Page 81: 10만 라인, 26280시간의 이야기

2013년

• async 좋은건 알지만….

• 도입하면 복잡도가 증가하고 (아직) 필요가 크지 않다.

• 나중에 필요하면 도입할 수 있지 않겠어….?

Page 82: 10만 라인, 26280시간의 이야기

그리고 도래한 2016년

Page 83: 10만 라인, 26280시간의 이야기

Async가 필요하다!

• 인스턴스당 처리 효율이 너무 떨어져 비용이 낭비된다.

• 외부 시스템 연동이 이제 너무 많아서 대부분 시간이 I/O

• gevent monkeypatch가 모든걸 해결해 주시겠지…?

Page 84: 10만 라인, 26280시간의 이야기

그때와 지금은 모든게 다르다

Page 85: 10만 라인, 26280시간의 이야기
Page 86: 10만 라인, 26280시간의 이야기

시점에 대한 후회• 2013년에 단 3줄로 처리 되었을 문제가….

• 2016년엔 2000줄의 수정과 31개의 파일 변경, 개발+테스트+머지까지 1달 이상의 기간을 필요로 했다.

• 이미 복잡도가 상승한 시스템에서 ‘monkey patch’같은 magic은 불가능.

• 개발 초기 단기의 복잡도 상승을 과대 평가하여 이후 막대한 비용을 지불.

Page 87: 10만 라인, 26280시간의 이야기

사례2

Page 88: 10만 라인, 26280시간의 이야기

Read The F*** Manual

Page 89: 10만 라인, 26280시간의 이야기

SQLAlchemy Transaction Management

Page 90: 10만 라인, 26280시간의 이야기
Page 91: 10만 라인, 26280시간의 이야기

“autocommit” mode should not be considered for general

use.

Page 92: 10만 라인, 26280시간의 이야기

Implicit vs Explicit

Page 93: 10만 라인, 26280시간의 이야기

Implicit Transaction• SQLAlchemy가 암시적 Transaction 관리를 수행

한다.

• 기본적으로 session이 생성되는 시점에 무조건 Transaction을 수행하고, commit 혹은 rollback 되어 종료되는 즉시 새로운 Transaction 생성.

• INSERT/UPDATE/DELETE같은 변경뿐 아니라 SELECT만 수행하는 경우에도 Transaction 문맥하에서 수행된다.

Page 94: 10만 라인, 26280시간의 이야기
Page 95: 10만 라인, 26280시간의 이야기

The Last “SPOF”• 대부분의 DBMS에서 Transaction과 Connection

비용은 클 수 밖에 없다.

• W:R Ratio가 9:1에 가까움에도 Transaction이 과다해 DB에 부하가 너무 크게 집중되는 현상의 반복.

• Connection pooling 같은 방법이 실질적으로 효과를 발휘할 수 없다.

Page 96: 10만 라인, 26280시간의 이야기

PEP 20 -- The Zen of Python

“Explicit is better than implicit”

Page 97: 10만 라인, 26280시간의 이야기

sessionmaker( bind=engine,

autocommit=True)

Page 98: 10만 라인, 26280시간의 이야기
Page 99: 10만 라인, 26280시간의 이야기

Python의 배신• PEP 249 — Python Database API Specification v2.0

• There isn’t even a way to explicitly start a transaction in the PEP 249 API; no begin() or similar. Instead, you are always in a transaction;

• psycopg2는 PEP249의 작동을 준수하고, SQLAlchemy+psycopg2 에서 autocommit mode의 설정은 작동에 영향을 주지 못한다.

• 대신 isolation_level=‘AUTOCOMMIT’ 으로 조정해야 한다.

Page 100: 10만 라인, 26280시간의 이야기

문서에 없는데….?

Page 101: 10만 라인, 26280시간의 이야기

신속하게, 그러나 신중하게

Page 102: 10만 라인, 26280시간의 이야기

• Session 관리는 가장 초창기에 들어간 코드 중에 하나지만, 전반적인 Scale-up에 있어 끝까지 발목을 붙잡았다.

• 일반적인 서비스에서 DB가 병목이면서 동시에 SPOF가 되는걸 충분히 이해하고 있음에도 해당 비용을 평가하지 않았다.

• 이미 복잡도가 상승한 시점에서 Session의 설정을 바꾸는건 무척이나 비용이 크고 조심스러운 작업이 되어 쉽게 시도하지 못했다.

• 충분히 예측 가능한 기본적인 부분들에 대해서는 조금 더 신중했어야.

Page 103: 10만 라인, 26280시간의 이야기

느슨하지만 엄격하게• 처음부터 완벽한 선택을 할 수는 없기에 거기에 너

무 매몰되어 적정 시점을 놓치는건 너무 뼈아프다.

• 하지만 신중해야 되는 부분에서는 신중할 필요가 있다.

• 이런 알면서 (잘)못하는 것을 어떻게 다루는지가 결국 장기적인 프로젝트 관리

• 목표는 엄격하지만, 단계는 느슨하게.

Page 104: 10만 라인, 26280시간의 이야기