PHP: 잘못된 디자인의 프랙탈

서문

저는 까칠한 사람입니다. 주위의 많은 것에 불평합니다. 세상에는 제가 좋아하지 않는 기술들이 많이 있는데, 그것은 당연한 것입니다. 프로그래밍은 우스울 정도로 역사가 짧은 학문이고 우리 중 누구도 우리가 지금 무엇을 하고 있는지조차 갈피를 잡지 못합니다. 스터전의 법칙을 감안하면 주변에 불평할 것들이 평생에 걸쳐서 널려 있습니다.

모든 것이 같지는 않습니다. PHP는 그저 쓰기 어색하다거나 제가 원하는 부분과 맞지 않다거나 차선책이라거나 신념에 맞지 않는 것이 아닙니다. 저는 일반적으로 좋은 방식이라고 여겨지는 것 중에 제가 싫어하는 것들과 나쁜 방식이라고 여겨지는 것 중에 좋아하는 것들을 말씀드릴 수 있습니다. 자, 질문하세요! 이런 주제로 흥미로운 대화를 나눠 볼수도 있을 겁니다.

PHP는 유일한 예외입니다. 실질적으로 PHP의 모든 부분은 어딘가 잘못되어 있습니다. 언어, 프레임워크, 생태계 모두 그냥 개판입니다. 단 하나만 콕 집어서 얘기할 수도 없는 것이 아닙니다. 이 모든 폐해는 시스템 전반에 걸쳐 있기 때문입니다. 매번 PHP의 불만을 정리할 때마다 한번 쭉 훑은 상태에서도 자꾸만 트리비아가 질릴 정도로 발견되어서 이내 막혀버리고 맙니다. (그래서 프랙탈)

PHP는 나의 기술을 망치는 골칫거리입니다. PHP는 완전 개판이지만 아직 다른 것들을 배워보지도 않은 (권력이 있는) 아마추어들이 칭찬을 해대는 통에 미치겠습니다. 결점을 상쇄시킬만한 장점은 쥐꼬리만하고 저는 이 언어의 존재 자체를 잊어버리라고 권하고 싶습니다.

하지만 일단 모든 것을 정리해야 할 것 같군요. 자 갑니다, 이게 마지막이예요.

비유

저는 막 Mel에게 저의 좌절감을 내뱉었고 그녀는 여기에 (그것에 대해) 써 보길 권했습니다.

심지어 저는 PHP의 뭐가 잘못되었는지조차 말할 수가 없어요. 왜냐 하면... 음.... 공구상자가 있다고 해 봐요. 각종 공구가 들어있는. 뭐 그런대로 괜찮아 보이겠죠. 표준적인 것들이 들어 있을거구요.

그런데 거기서 드라이버를 꺼냈는데 끝이 이상한 삼각형 모양인 거예요. 뭐 좋아, 나한테 유용하진 않겠지만 언젠간 쓸만할 때도 있겠지.

이제 망치를 꺼냈는데 경악스럽게도 양쪽 끝에 못뽑이가 달려 있네요. 뭐 어쨌든 쓸 수야 있겠죠. 옆으로 잡고 망치의 가운데 부분으로 못을 박는다거나 하는 식으로.

이제 펜치를 꺼냈는데 톱니 무늬가 없어요. 평평하고 매끈하네요. 유용하진 않지만 어쨌든 볼트를 돌릴 수야 있을테니 뭐 어때요.

그리고 계속 봅시다. 공구상자 안의 모든 것들이 괴상하지만 완전히 쓸모없진 않을 거예요. 그리고 전체적으로 보면 문제가 아니예요. 왜냐하면 일단 공구가 있긴 하니까.

이제 그 공구상자를 쓰면서 "이봐 대체 이 공구상자에 무슨 문제가 있다고? 난 지금까지 이것들을 써 왔고 이것들은 쓸만하다고!"라고 하는 말하는 수백만명의 목수들을 보게 됩니다. 그리고 목수들이 자기가 지은 집을 보여주는데, 방들은 죄다 오각형 모양이고 지붕은 거꾸로 뒤집혀 있군요. 그리고 정문을 두드리면 집이 폭삭 무너져 내리고 안에서 그 사람들이 왜 문을 부수냐고 소리를 지릅니다.

이게 PHP의 문제점이예요.

입장

저는 아래의 요소들이 프로그래밍 언어를 생산적이고 가치있게 만드는 데 중요한 요소라고 주장하지만 PHP는 이 모든 것들을 심각하게 위반합니다. 만약 이것들이 중요하다는 것에 동의하지 않는다면 대체 어떤 것에 동의하실지 짐작할 수 없군요.

제 입장은 이렇습니다.

저는 매 문제 하나하나마다 왜 이것이 이 범주에 들어가는지 따로 부연설명을 하지 않을 겁니다. 한다면 아마 끝이 없겠지요. 아마 독자 여러분들이 스스로 생각하실 수 있을 거라고 믿습니다.

노 코멘트

저는 PHP 논쟁을 많이 벌였습니다. 그럴 때마다 논의를 중단시키려는 목적 말고 없는 뻔한 반론들을 엄청나게 봐 왔습니다. 여기서 제발 저한테 이런 소리는 들이밀지 말아주세요. :(

여기서 사족, 저는 Python을 무척 좋아합니다. 원하신다면 저야 기쁘게 불평불만을 쏟아낼 수 있습니다. 저는 이게 완벽한 언어라고 말하지 않았습니다. 다만 저는 장점과 단점을 저울질해서 이것이 제가 쓰기에 가장 적합한 언어라는 결론을 내렸을 뿐입니다.

그리고 저는 PHP로 똑같은 걸 할 수 있는 개발자를 만나본 적이 없습니다. 하지만 이내 패배를 인정하고 사과하는 개발자들은 많이 봤습니다. 이런 사고방식은 대단합니다.

PHP

핵심 언어

CPAN은 "Perl의 표준 라이브러리"로 불려 왔습니다. 그게 Perl의 표준 라이브러리에 대해서 많은 것을 이야기하는 건 아니지만 탄탄한 기반에서는 많은 대단한 것들을 만들어낼 수 있다는 점을 내포하고 있습니다.

철학

저는 PHP 인터프리터나 그것의 개발자들에 대해 수많은 멋진 이야기를 들었습니다. 그런 이야기들은 PHP 코어디버깅된 PHP 코어, 코어 개발자와 소통해본 사람들에게서 왔습니다. 하지만 그 중 칭찬의 말은 단 하나도 없었습니다.

저는 그래서 여기서 결론을 내립니다. 왜냐 하면 자꾸 반복되는 얘기라서요. PHP는 아마추어들의 커뮤니티입니다. PHP를 디자인하고 작업하고 코드를 짜는 사람들 중에 자기가 뭘 하는지 제대로 아는 것 같은 사람들은 극히 드뭅니다. (아 이것 참, 독자 여러분들은 물론 드문 예외죠!) 그리고 문제의 실마리를 잡을 수 있는 사람들은 다른 플랫폼으로 가 버리게 됨으로서 결국 전체에 있어서 평균적인 능력은 계속 줄어들게 됩니다. 바로 이것이 PHP가 가지고 있는 가장 큰 문제점입니다. 그야말로 장님이 장님의 무리를 이끌고 있는 상황.

좋아요, 일단 팩트로 돌아갑시다.

연산자

변수

언어 구조

오류 처리

함수

객체지향

표준 라이브러리

예를 들어 Perl은 "약간의 조립 과정이 필요"입니다. Python은 "배터리 포함"입니다. PHP는 캐나다산 키친 싱크대입니다. 게다가 양쪽 수도꼭지에 전부 C라고 적혀 있습니다.

일반

C의 영향

이 내용은 아주 중요합니다. 왜냐하면 전혀 말도 안되는 것들인데도 언어 전반에 퍼져있으니까요. PHP는 하이레벨, 동적타이핑 프로그래밍 언어라구요. 그런데도 스탠다드 라이브러리의 대다수가 C API를 아주 살짝 싸놓았을 뿐입니다. 그 결과 아래와 같은 일이 생기죠.

제너릭

그런거 없습니다. 만약 두가지의 미묘하게 다른 기능이 필요하다면 PHP에는 두 개의 함수가 있습니다.

배열을 어떻게 반대 방향으로 정렬하나요? Perl이라면 sort { $b <=> $a }로 하면 되겠죠. Python은? .sort(reverse=True)로. PHP에서는 rsort()라는 별개의 함수가 있습니다.

텍스트

시스템과 반영(reflection)

기타

데이터 조작

프로그램은 데이터를 먹고 더 많은 데이터를 뱉어내는 것 이상도 아닙니다. awk부터 시작해서 Prolog, C까지 좋은 언어들은 조작할 데이터의 유형에 따라 설계됩니다. 만약 언어가 데이터를 만질 수 없다면 아무것도 할 수 없다는 겁니다.

숫자

텍스트

배열

Oh, man.

배열이 아닌 것

함수

기타

웹 프레임워크

실행

배치 (deployment)

배치는 주로 PHP의 가장 큰 장점 중 하나로 꼽혀 왔습니다. 그냥 파일만 몇개 놓으면 끝이라는 거죠. 정말로 Python이나 Ruby, Perl보다 모든 과정이 쉽긴 하지만 미비한 점이 많습니다.

전반에 걸쳐서 저는 웹 애플리케이션을 앱 서버로 돌리고 리버스 프록싱을 하는 것을 선호합니다. 설정하는데 그렇게 노력이 들지도 않고 장점은 충분합니다. 웹 서버와 앱을 따로 관리할 수 있으며 웹 서버를 더 설치할 필요 없이 여러 개의 앱 프로세스를 동시에 돌릴 수 있으며 다른 사용자로 앱을 돌리는 것도 쉬우며 웹 서버를 교체할 수도 있으며 웹 서버를 건드리지 않고 앱을 내릴 수도 있으며 FIFO 시점만 조정하는 것으로 빈틈없이 배치할 수 있습니다. 웹 애플리케이션을 웹 서버와 합치는 것은 불합리하며 그렇게 해서 얻을 수 있는 이점은 없습니다.

부재하는 기능들

아래의 기능들 모두 웹 애플리케이션을 개발할 때 여러가지 면에서 중요하다고 생각합니다. PHP가 "웹 프로그래밍 언어"로 팔리고 있기 때문에 이런 기능들의 일부라도 구현되어 있으면 합리적일 것입니다.

보안

언어의 경계

PHP의 보안에 대한 나쁜 평판의 대부분이 임의의 언어로 된 데이터를 받아서 다른 언어로 그대로 내놓는다는 점에서 옵니다. "<script>"는 SQL에서는 아무런 의미가 없지만 물론 HTML에선 있습니다.

이걸 더욱 악화시키는 것은 "입력을 정화(sanitize)하십시오" 라는 공통적인 외침입니다. 이건 완전히 잘못된 것입니다. 한번 휘두르면 데이터 더미를 본질적으로 "깨끗하게" 만드는 마법의 지팡이 같은 것은 없습니다. 단지 필요한 것은 언어를 쓰는 것입니다. SQL에 플레이스홀더(placeholder)를 단다거나 프로세스를 호출할 때 인자 목록을 쓴다거나 등등....

지금까지 SQL 인젝션에 대한 PHP 문서에서는 타입 검사, sprintfis_numeric 사용, mysql_real_escape_string을 어디서든지 직접 사용, (심지어 도움이 될지 안될지 모르는!)addslashes를 직접 사용하는 등의 제 정신이 아닌 것 같은 대응 방법을 추천하고 있습니다. 유저 코멘트란을 제외하고 PDO나 파라미터화(parameterization)의 언급은 하나도 없습니다. 2년 전에 PHP 개발자들에게 이 점을 매우 구체적으로 이야기했고 개발자들은 들었습니다. 하지만 이 페이지는 아직까지 바뀌지 않았습니다.

기본 상태가 취약함

핵심

PHP 인터프리터 자체에 정말 끝내주는 보안 문제가 몇 차례 있었습니다.

찾아보면 더 나오겠지만 X개의 보안 취약점이 있다는 것은 요지가 아닙니다. 소프트웨어는 버그가 있고 뭐든 일어날 수가 있기 때문이죠. 하지만 이것들의 본질이 끔찍하다는 겁니다. 그리고 이것들은 제가 찾은 것이 아닙니다. 최근 몇 달동안 갑자기 저희 집 문 앞에 나타났을 뿐입니다.

결론

몇몇 코멘트에서 저한테 결론이 없다는 것을 잘 지적했습니다. 네, 뭐 저는 결론이 없습니다. 여기까지 읽어보셨다면 시작하기도 전에 저에게 동의했을 거라고 추정했죠.

PHP만 알고 있는 상태고 다른 것을 배울 의향이 있다면 Python 튜토리얼을 읽어보시고 웹 개발에서는 Flask를 써 보세요. (저는 템플릿 언어의 팬은 아닙니다만 그래도 괜찮긴 합니다.) 그것은 여러분의 앱을 나누지만 모두 다 같은 조각들이고 충분히 친숙하게 보일 겁니다. 여기에 대해서는 나중에 여기에 속하지 않는 언어와 웹 스택 전반을 소개하는 블로그 포스팅에서 따로 다루겠습니다.

그리고 이후에 더 큰 프로젝트를 하실 거라면 중간 레벨에 있는 Pyramid가 좋습니다. Django도 있습니다. Django 사이트와 비슷한 것을 만들기에 적합한 엄청나게 거대한 괴물이죠.

만약 개발자가 아닌데 어떤 이유로 이 글을 읽으셨다구요? 지구상의 모든 사람들이 Learn Python The Hard Way를 정독하기 전까지 전 행복해지지 않을 겁니다. 그러니 읽으세요.

써본 적은 없지만 Ruby와 Rails나 경쟁자들이 있고 Perl 역시 Catalyst와 함께 여전히 잘 살아 있습니다. 끊임없이 읽고 배우고 만들고 열중하세요.

감사의 말

이하에 감사드립니다.