엄청나게 빠른 버그 감지, 디버그, 코드 배포 share
어제 있었던 일이다. 저녁에 있을 모임에 나가기 위해 하던 일을 슬슬 정리하려던 차였다. 그런데, 슬랙으로 날아온 버그 메시지. 버그를 감지하고 바로 고친후 프로덕션에 배포했는데, 이 모든 과정이 딱 10분 걸렸다. 어떻게 가능했을까?
이 포스트는
- 라라벨1 프레임워크의 우수성을 알린다.
- 가난한 개발자가 자신의 서비스를 지키는 방법과 몇가지 개발 도구를 소개한다.
라는 목적을 가진다. (이 블로그의 포스트들의 방문자가 갑자기 많아졌다. 그래서 웃고 운다.)
이 포스트의 대상이 되는 프로젝트는 내가 쓴 라라벨 5 온라인 강좌임을 미리 밝힌다. 해당 강좌를 통해 개발한 최종 결과물은 현재 아마존웹서비스(AWS)에서 올려 라이브데모라며 서비스하는데, 이 포스트는 라이브데모의 방문자 중 한분이 겪은 문제에 대한 해결 이력이다. 그런데 불편함을 겪었던 그 분은 ‘그냥 안되네~’라며 페이지를 떠나신 것 같다. 내 메일 주소를 찾아 가면서 문제점을 기술(description)하면서 고쳐달라고 말하는 친절을 베풀지는 않았지만, 버그를 만들어 주셨으니 나한테는 고마운 분이다.
이 포스트의 내용과는 조금은 다른 관점인데.. 서비스에 문제가 생겼을 때 사용자가 별 노력 없이도 문제점을 개발자에게 알릴 수 있는 사용자인터페이스(UI)나 장치를 만드는 것도, 서비스의 품질을 높일 수 있는 좋은 방법이다. 이런 옵트인(opt-in) 방식의 리포팅은 팝업 형태로 표시되어 사용자의 동의를 받아 전송하는 것이 일반적이다.
가능한 모든 경우의 수를 따져서 개발자는 프로그래밍하고 테스트를 하려고 하지만, 세상에 ‘완벽’이란 단어는 없다. 구현이 조금 부족하고 테스트가 덜 됐을 수 있지만, 버그를 리포팅하는 장치를 프로그램에 심어서 배포하고, 리포트된 버그를 분석하고 코드를 고쳐서 빠르게 안정화하며, 초기 사용자의 반응을 관찰하는 것이 더 낫다는 것이 나의 생각이다. 완벽주의 개발자들로 포진된 스타트업들이 오버 엔지니어링을 하다가 실기(失期)하는 사례를 여러번 봤다.
Bug Detection
아래는 어제 오후 5시 16분에 라이브데모 사이트에서 발생한 예외를 라라벨의 전역 예외처리기가 캐치하고, 스택트레이스(stack trace)를 슬랙(Slack)으로 보내온 것이다. Call to undifined method Lararacasts\Flash\FlashNotifier::errors()
. 없는 메서드를 호출했단다. 얼마나 자세(informative)한가?
아래는 라라벨 프로젝트의 전역 예외처리기에 정의된 버그 리포트 부분이다. 프로덕션 환경일 때만, \App\Reporters\ErrorReport::send()
를 이용해서 Exception $e
를 리포팅한다.
<?php // app/Exceptions/Handler.php
// ...
class Handler extends ExceptionHandler
{
public function report(Exception $e)
{
if ($this->shouldReport($e) and app()->environment('production')) {
app(\App\Reporters\ErrorReport::class, [$e])->send();
}
return parent::report($e);
}
public function render($request, Exception $e)
{
// Custom exception rendering logic ...
return parent::render($request, $e);
}
}
Debugging
어려운 버그였다면 10분은 거짓말이었을텐데, 다행히 쉬운 버그였다. 코드에디터 열어서 errors()
에서 error()
로 오타 수정하는 정도였으니까..
코드 수정과 테스트가 끝나면 그 다음은 완전 기계적인 프로세스다. 수정된 코드를 버전관리시스템에 반영하고, 깃허브에 올리는 일이다.
$ git add .
$ git commit -m 'fix bug of BadMethodCall @PasswordController'
$ git push
Code Deploy
로컬컴퓨터에서 아래 콘솔 명령 한줄이면 배포 끝! 내 프로젝트가 의존하는 패키지를 내려받아 설치하는 것까지 포함해서, 프로덕션 서버에 코드 배포 과정은 길어도 2분 정도다.
$ envoy run release
여기까지 10분!!! 하는 김에, 그간에 독자분들에 지적한 변경 필요 내용들도 반영했다.
Conclusion
Bug Detection
많은 프로그래머들이 PHP 프로그래밍언어의 단점으로 ‘예측 가능하지 않다’는 점과 ‘신뢰성이 떨어진다’는 점을 든다. 실수로 코드를 잘못짰을 때, 그 프로그램이 실행을 멈추고 뭔가 엄청난 에러메시지를 뿜어 내는 것이 보통의 개발자들이 기대하는 바이다.
$id = $_GET['id']; if ($id == 0) {...}
를 예로 들자. 브라우저에서 id
쿼리 요청이 항상 있다는 보장은 없다. 이때도 PHP 엔진은 Undefined index:id
라는 경고 메시지를 ‘조용히’ 로그에 기록한 후, 그냥 다음 코드를 실행한다. 이건 앞서 말한 개발자의 기대와 다르다. 이 코드는 개발자의 실수였거나, 나쁜 코딩 습관의 산물이거나, 아니면 괜찮은 코드를 짜는 방법을 몰라서 생긴 결과일 수 있다. 개발자 본인이 테스트할 때 문제가 없어 보일 수 있지만, 다른 사용자가 이용할 때는 완전히 다른 결과를 낼 개연성이 있는 잘못된 코드이다.
이가 없으면 잇몸이라 했던가? PHP 프로그래밍 언어가 가진 문제점을 라라벨 프레임워크 커버해 준다. 어떻게???
라라벨 프레임워크는 이런 경우에 무조건 예외를 던진다. 그리고, (특별한 예외처리 로직을 구현하지 않았더라도) 전역 예외처리기에서 캐치한다. 이 전역 예외처리기는 render()
메서드로 사용자에게 안내 메시지를 표시하거나, report()
메서드로 로그 기록이나 외부로 메시지를 보내는 등, 캐치한 예외의 타입에 따라 적절한 방식으로 예외를 소비한다. 프레임워크를 사용함으로써 입문자는 이런 문제를 회피할 수 있고, 고수는 시간을 절약할 수 있다.
잡설이 길었는데 라라벨의 ‘예측가능성’과 ‘신뢰성’에 대한 철학, 그리고 그 철학의 구현체는 훌륭하다. 내가 이 프레임워크에 머물러 있는 이유다.
Debugging
디버깅에서 중요한 것은 첫째, 자신만의 디버깅 프로세스와, 둘째, 좋은 도구이다. 서드파티 콤포넌트의 메서드 이름을 어떻게 기억하겠는가? 다행히 phpStorm2과 같은 도구는 객체나 메서드 이름 위에 커서를 놓고 Cmd + 클릭으로 메서드로 이동할 수 있다. 해서, 없는 메서드라는 것을 쉽게 확인할 수 있다.
Code Deploy
엔보이(envoy)3와 깃허브(Github)를 이용해서 코드 배포를 자동화하는 방법은 아래 링크들에 설명해 두었다.
@findstar님이 번역한 엔보이-라라벨 5.2 한글 매뉴얼도 좋은 참고자료이다.
나는 깃허브라는 서비스를 개발과 프로덕션의 사이를 잇는 허브(hub)로 사용한다. 깃허브에 개발코드를 올리고, 프로덕션에서 $ git clone
을 하니까 말이다.