수년간 쌓인 대형 PHP 서비스에 합류했다. 파일이 수만 개고 아는 사람은 각자 자기 영역만 아는 상태였다.
처음에 디렉터리 구조부터 훑었는데 며칠을 쓰고도 Controller 와 Model 의 관계조차 안 잡혔다.
Table of contents
Open Table of contents
요청 하나를 끝까지 따라갔다
디렉터리 이름만 봐서는 그 안의 코드가 언제 불리는지를 알 수 없었다. 그래서 화면 하나를 골라 요청부터 응답까지 따라가는 쪽으로 방법을 바꿨다.
브라우저 요청
→ 웹서버 설정 (어느 앱으로 가나)
→ 라우팅 (어느 컨트롤러인가)
→ 컨트롤러 (무엇을 부르나)
→ 모델·쿼리 (어디서 데이터가 오나)
→ 뷰 (어떻게 그려지나)
각 단계에서 파일 경로를 적었고 그것이 그대로 지도가 됐다. 한 요청을 끝까지 따라가니 계층과 관례가 한꺼번에 나왔다.
Controller 를 어디 두는지와 Model 의 쿼리가 어디 있는지가 그 한 번에 드러났다. 반나절이면 끝나는 분량인데 며칠 훑어서 못 얻은 것을 여기서 얻었다.
디렉터리를 훑는 것과는 성격이 다르다. 훑으면 폴더가 있다는 것만 알고 따라가면 역할을 안다.
두 번째 요청에서 관례가 보인다
같은 것을 성격이 다른 화면으로 한 번 더 했다. 한 번만으로는 서비스의 방식인지 그 화면의 사정인지 구분이 안 된다.
두 번째에서 공통점과 차이가 갈렸는데 두 번 다 같은 방식인 부분이 관례이고 다른 부분이 각자의 사정이다.
세 번째쯤 되면 새 화면을 봐도 어느 Controller 를 열지 안다. 관례를 알면 모르는 코드에서도 짐작할 자리가 생긴다.
판단 기준 — 예외를 먼저 묻기
관례를 파악한 뒤에 아는 사람에게 이 관례를 안 따르는 곳이 어디인지를 물었다.
큰 코드베이스에는 반드시 예외가 있는데 급하게 만든 것과 이식한 것과 아직 안 옮긴 옛 구조가 그렇다.
그 목록을 먼저 아는 것이 크다. 모르면 예외를 관례로 착각해 따라 하거나 예외 지역에서 관례대로 하려다 안 된다.
어디가 예외인지를 아는 사람은 있는데 아무도 적어 두지 않아서 물어보지 않으면 안 넘어온다.
데이터부터 봤다
코드를 읽다 막히면 MySQL 에서 자료를 봤다. 표 하나를 골라 실제 행 몇 개를 뽑아 본다.
SELECT * FROM some_table ORDER BY id DESC LIMIT 5;
SELECT 한 번이 코드 읽기보다 빠를 때가 많았다. 상태 컬럼에 어떤 값이 있는지와 어떤 필드가 늘 비어 있는지가 바로 보인다.
특히 늘 비어 있는 컬럼이 힌트인데 쓰다가 만 기능이거나 다른 경로로 대체된 것이라 그쪽은 안 읽어도 된다.
SELECT DISTINCT 가 한 줄만 내놓는 컬럼도 같은 신호다. 분기용 값인데 한 갈래만 도는 것이다.
검증 — 안 쓰는 코드 가리기
파일이 많으면 그중 상당수가 안 쓰이는데 그것을 모르고 읽으면 시간을 버린다.
셋으로 걸러 냈는데 첫째는 부르는 곳이 없는 함수라 grep 으로 정의 말고 호출이 있는지 본다.
둘째는 오래 안 바뀐 파일이다. svn log 를 보면 몇 해째 그대로인 것이 있는데 안정된 것일 수도 죽은 것일 수도 있다.
셋째가 가장 확실했는데 access_log 를 켜고 실제 요청에서 그 코드가 타는지를 본다.
앞의 둘은 짐작이고 셋째는 관측이라 셋이 다 걸리면 안 쓰는 코드로 보고 읽지 않았다.
조치 — 고칠 때는 뒤에서
파악은 요청 방향으로 했는데 고칠 때는 반대로 가서 동작이 나오는 마지막 지점부터 거슬러 올라간다.
화면에 잘못 나오는 값이 있으면 .tpl 에서 시작해 위로 올라간다. 앞에서부터 내려오면 어디서 갈라지는지 몰라 헤맨다.
뒤에서 올라가면 한 갈래인데 그 값을 만든 자리가 하나이므로 갈림길이 없다.
방향 하나 바꾼 것인데 Model 까지 거슬러 가는 시간이 크게 줄었다.
참고 자료 — 남긴 지도
파악한 것을 문서로 남겼는데 나만 보려고 쓴 것을 나중에 다른 사람이 들어올 때 그대로 썼다.
[상품 목록 화면]
라우팅 routes/product.php:45
컨트롤러 Controller/Product.php::list()
쿼리 Model/Product.php::search() ← 여기가 느림
뷰 views/product/list.tpl
주의: 검색 조건이 세 곳에서 조립된다 (컨트롤러/모델/뷰 각각)
routes/product.php:45 처럼 줄 번호까지 적으니 찾는 시간이 없어졌다. 그런데 가장 쓸모 있었던 것은 주의 줄이었다.
관례를 벗어나는 부분과 함정을 주의 에 적었는데 경로만 있으면 찾아가도 무엇을 조심할지는 모른다.
정리
- 디렉터리를 훑지 말고 요청 하나를 끝까지 따라가면 계층과 관례가 나온다
- 훑으면 폴더가 있다는 것만 알고 따라가면 그 폴더의 역할을 안다
- 두 번째 요청에서 공통점과 차이가 갈려 관례와 사정이 구분된다
- 아는 사람에게 관례를 안 따르는 곳을 먼저 묻는다
- 그 정보는 있는데 아무도 안 적어 두므로 물어야 넘어온다
- 코드가 막히면
SELECT로 실제 행을 뽑고 늘 빈 컬럼을 힌트로 삼는다 - 안 쓰는 코드는
grep과svn log와access_log셋으로 가린다 - 앞의 둘은 짐작이고
access_log만이 관측이다 - 파악은 앞에서 하고 고칠 때는 뒤에서 거슬러 올라가면 한 갈래다
- 지도에 경로만 적지 말고 함정을 적는
주의줄을 넣는다