개발&Development/프로그래밍 일반

개발자의 기본! 너가 다루는 데이타가 어떤 타입인지를 알라.

겐도 2008. 9. 1. 04:33
"G-Test Pattern" 이 글은 내 블로그에서 유명한 글 중 하나이자, 종종 오프라인이나 온라인에서 언급이 되기도 한다. 개인적으로는 웹 개발에 있어 기본적인 테스트를 수행할 수 있도록 도와주는 획기적인 "도구"라고 생각한다. 그래서 공개하기로 마음먹었고 몇몇 서비스라도 문제 가능성을 줄어들길 바랬다. 허나 설명이 불충분 했는지 아직도 Version 1인 <gen&doh'">를 통과하지 못하는 서비스가 최신으로 공개되는 것을 보고는 통탄을 금할 수 없다.

G-Test와 관련해서 가장 많이 받는 질문이, 각 스트링 혹은 문자를 어떻게 처리해야 되는가이다. 그리고 나의 항상 대답은 "그때그때 달라요"라는 약간은 불친절한 것이었다. 매우 기본적인 것이라고 생각되어 설사 초보 개발자도 조금의 경험을 거치고 생각을 하고 나면 충분히 해결 가능한 것이라고 보았는데 역시 업계 전반적으로 구루라고 부를 수 있는 경험많은 코더들의 부족으로 답을 찾기가 힘든가 보다. 좀 친절해 보자.

예제로 '&'의 처리에 관한 것이다. 티스토리 글쓰기창(혹은 비슷한 html 편집기)에서 사용자에게 입력받아 최종적으로 RSS로 출력하는 과정의 처리방법을 고민할 것이다. 이 예제는 심지어 본인의 팀원도 잘못 생각해서 잘못 대답했다가 며칠을 구박 받았던 문제이기도 하다.(처음 당하면 매우 어려운 문제일 수도 있지만 당연한, 아니 상식이라고 할 정도의 이야기다. 이 블로그를 방문중인 많은 분들이 왜 이런 쓰잘데기 없는 것을 설명하고 있냐고 할 정도다. 허나 모르는 사람 많더라.)

편집기를 열고 사용자가 '&'를 입력하고 글을 저장한다. (1)"HTML 위지윅 편집기 모듈"에서 입력을 받아 (2)이를 POST로 (HTTP)서버에 전송하고, (3)PHP에서 DB에 저장한다. RSS를 보여줄 때 (4)DB에서 읽어와서, (5)RSS 모듈에 넘겨주면 (6)XML에 기록이 된 다음 (HTTP)RSS리더로 전송되고, (7)HTML을 지원하는 리더의 화면에 '&'로 표시되는 과정을 거친다. 중간에 (HTTP) 과정은 네트웍 레이어라 논의에서 제외하겠다.

이 과정을 막 세상에 나온 개발자에게 시킨다면 '&'는 어떻게 나올지 모른다. 허나 "&gt;"정도 되면 RSS리더가 XML이 깨졌다고 구박할 것이다. 수정하라고 하니 5번 단계에서 RSS 모듈에 넘겨줄때 htmlspecialchars(PHP의 html entity escaping 함수)한번 적어주고는 '>'라는 결과를 볼 것이며 다시 수정할 때 많은 초보 개발자들이 5번 단계에 한번 더 htmlspecialchars 함수를 쓴다. 사실 위의 단계 구분은 머리속에 들어 있지도 않고 (5)단계에서 RSS로 넘겨주는 루틴에 이스케이핑 해 주면 되겠지 하고는 정상적으로 나올 때 까지 함수를 처집어 넣다가 잘 동작한다 싶으면 버그가 수정되었다고 보고한다.

여기서 잠시, 형상관리(SVN등)와 코드 리뷰라던가 디플로이에 대한 글도 요즘 쓰고 싶은데 아직 구상 정리가 덜 된 상태지만.
많은 개발조직이 저런 상태로 넘어간다. 실서버에 버젓이 적용된다. 적어도 TnC에서는 나에게 딱 걸리고는 한두달 잔소리좀 들어야 할 것이다. 아무도 남이 작성한 코드에 관심은 없고, 아니 자신의 일 하기에도 정신없는 상황이다. 인력은 부족하고 시간은 없어서 개발자를 가르치고 발전시켜 주는 노력에 대해 신경을 제대로 쓰는 조직은 드물다. 또한 남의 코드를 가지고 왈가왈부 하는 것은 동료애에 금기시 되거나, 남에게 싫은 소리는 하지 않는 것이 좋다는 한국의 이상한 문화가 서비스를 망하게 만든다.

제대로 된(?) 개발자라면 위의 문제 자체가 무의미 하다.
(1) html entity escaping
(2) POST용 escaping
(3) DB escaping
(4) 그냥 읽어오면 됨
(5) XML모듈에 그대로 전달
(6) XML 모듈 내에서 xml-string escaping
(7) HTML Viewer가 html entity를 역변환

각 단계마다 '&'가 어떤 형태로 나오는지는 각자 알아서.

<gen&doh'">의 각 글자에 대해 어떻게 처리해야 하는지 고민하는 것이 아니라 레이어별로 인풋과 아웃풋에 대해 적절한 처리만 하면 아무런 문제가 없다. 화면에 뭔가 이상하게 출력이 되었다면 막무가내로 처음과 끝을 잡고 고민할 것이 아니라 중간단계에서 자신이 해야 할 일을 제대로 하지 않고 있는 것이니 그것을 검증하면 되는 것이다.

가령 6번 단계를 보자. XML 출력기 모듈은 출력해야 할 스트링이 Plain Text든 JSON이든 상관하지 않는다. 주어진 데이터를 잘 포장해서 다시 XML 파서가 데이터를 뽑아 내었을 때 똑같은 데이터가 나오면 된다. XML의 String Representation(표현방식)에 맞춰서 변환해 줄 필요가 있는 것이다. CDATA를 사용하지 않고 직접 스트링을 적겠다고 판단하였다면 htmlspecialchars 함수를 한번 써 주어야 한다. 반대로 5번 과정에선 DB의 HTML로 저장되어 있는 데이터를 그대로 전송해 주어야 하므로 이스케이핑을 해서는 안된다.

DB에 저장하는 SQL문을 작성하거나, HTML Tag의 Attribute에 스트링을 출력하는 경우 따옴표(")는 적절히 변환(escaping)되어야 한다. 자바 스크립트를 HTML에 기술할 때도 변환되어야 한다. HTML Tag의 Attribute까지 포함한 HTML String을 Writing하는 JS를 HTML에 기술할때는? 익숙한 개발자는 단방에 두번 이스케이핑 하겠지만(물론 급 초보도;;) 이 코드를 작성하는 생각의 과정은 두 레이어가 존재하여 이름은 같을 지언정 목표-결과가 아닌 목적-가 다른 함수를 두번 쓰게 된다.

G-Test에 들어있는 문자들은 웹과 관련된 String Representation에서 Special Charater로 사용되는 것들을 섞고는 gendoh가 제대로 보이는지 확인하는 것에 지나지 않는다. 약간의 조미료로 화면을 깨지게 만들거나 JS가 에러가 나도록 하는 트릭들이 들어 있을 뿐이다. 좀 심각하게 받아 달라고. 그럼에도 전혀 심각하지 않다고 생각하는 사람들이 대부분인듯 하지만.

데이터 처리의 기본은 이것이다. 인풋이 무엇인지, 아웃풋이 무엇인지, 그리고 그것들의 표현방식이 무엇인지 제대로 알고 작성하는 것이다. 표현방식에서 어떤 것들이 특별하게 표현되어야 하는지 확인해야 할 것이며 그렇기에 여러 종류의 Escaping 함수들이 존재한다. 대부분의 C-like 언어들이 따옴표로 스트링을 표현할 때 내부에서 따옴표를 쓰려면 역슬래쉬(\)를 사용해야 하는 것은 알고 있지 않은가. 마치 그것처럼 각각의 레이어들도 그런 것이 필요하다.

이것이 개판이 되면, 몇몇 신문사들의 RSS에서 제목에 <BR>이 보인다거나 가끔 RSS 자체가 깨져버려 그 기사가 사라질 때 까지 정상적인 구독이 불가능한 상황이 발생하는 등의 사고가 일어난다. 레이어마다의 데이터에 대한 설계미스(mistake가 아니라 miss).

제발 좀 "테스트"라는 글자가 잘보인다고 "오예~ 다짰다~"라고 넘겨버리는 짓을 하거나, 테스트 단계에서도 그 글자가 잘보인다고 OK 하는 우를 범하지 말길 바란다. 자신이 처리하는 데이터가 무엇인지 명확히 알고 정확히 처리해야 한다.

테스트라는 것은 성공하는지 검사 하는 것도 있지만 실패 안하는지 확인하는 과정이기도 함을 명심해야 한다.

PS.
이런 것도 모른체 프로그램을 작성하고 앉아 있는 것을 시간이 없어서, 기획이 쪼니까, 일단 만들고 나중에 버그수정~ 식의 말로 변명 할 수는 없다. 졸다가 한두군데 놓친다거나 사이드 이펙트로 생기기도 한다. 하지만 아예 그런 개념이 탑재되지도 않은 채 작성하는 사람도 많다. 그사람만의 문제가 아니라 상사, 동료 즉 그 팀 전체의 문제다.