어색하지 않게 한국어로 소개하고 싶었지만 가능하지 않을 것 같은(위키피디아에서 초본문이라고 소개하는) 하이퍼텍스트.

하이퍼텍스트는 문서 안의 하이퍼링크(참조)를 통해 다른 문서로 즉시 접근할 수 있는 문자를 말한다. html의 ht가 바로 하이퍼텍스트이며 앞서 설명한 내용 보다 html 단어를 봤을 때, 그 의미 파악이 더 쉬웠을 것이다.

1960년대에 테드 넬슨이 하이퍼텍스트라는 개념을 처음 고안했다는 글들이 많이 보이지만 이 개념은 우리가 광복을 맞이하던 해, 1945년, 베네바 부시가 기고한 ’As We Think’에서 메멕스(=MEMory EXtender) 시스템 제안과 함께 시작 되었으며 그것을 테드 넬슨이 하이퍼텍스트라는 단어를 사용하며 정리했다고 보는게 맞을 것 같다. 당연하게도 테드 넬슨은 부시에게서 영감을 얻었다.

테드 넬슨은 미래에는 전 세계가 네트워크로 연결이 되고 사용자 인터페이스를 통해 상호작용이 가능할 것이라 예견하였다. 이와 함께 어느 곳에서나 임의적으로 원하는 정보에 접근할 수 있는, 하이퍼텍스트라는 용어를 만들어 사용했다.

html 외에도 이러한 개념을 찾을 수 있는게 또 있다. 화석들은 당연히 알고 있을 하이퍼픽션(=하이퍼텍스트픽션)이다. 당연히 난 모르던 것이다. (*하이퍼픽션을 소개한 이전 기사)

하이퍼텍스트의 특성을 이용, 여러 갈래를 가진 이야기를 출판할 수 있는 전용 프로그램으로 소설을 제작한다. 하이퍼픽션 최초의 작품으로 인정받고 있는 마이클 조이스의 ‘오후: 이야기’는 1990년 이스트게이트 시스템스(프로그램 이름이 아니라 회사 이름이다)를 통해 쓰여진지 3년만에 퍼블리싱 된다.

  • 주의 1. 이 글은 소속 회사의 입장을 대변하지 않습니다.
  • 주의 2. 이 글에는 늘 그렇듯이 현명함 보다는 멍청함이 묻어 있습니다.
  • 주의 3. 선택한 방법과 주장하는 바가 옳지 않을 수 있습니다.
  • 주의 4. 위의 이유로 예고없이 삭제될 수 있습니다.
  • 주의 5. 수정할 사항이 있다면 댓글에 남겨주세요. 검증 후 본문을 업데이트 하겠습니다.


배경

가끔 개발자들이 완벽한 프로덕트를 위해 무언가를 늦춰야 한다고 이야기합니다. 맞습니다. 가끔은 시간 보다는 품질이 중요할 때가 있습니다. 하지만 대부분의 사업은 충분한 시간이 오히려 적이 되는 경우도 많습니다.(소속 회사의 사정을 말하는게 아닙니다) 프로덕트, 또는 서비스는, 그 가치가 지속 가능하기 위해서 이윤을 남겨야 하거나 그것을 벌어들이는 도구일 수 밖에 없습니다. 그런데 가끔은 그런 것들을 망각하는 경우도 많은 것 같습니다.
 
 
시간이 많지 않은 상황에서 우리는 두개의 센터를 연달아 가동시켜야 할 상황이 되었고 저와 우리 팀, 전체의 조직이 해당 목표를 달성하기 위하여 힘차게 뛰어야 했습니다. 지금은 두개의 센터가 잘 기능하고 있습니다. (너무 감사하게도... 아직 보완할 점은 엄청 많지만...) 그러면 어떻게 동시에 진행할 수 있었을까요?!


섣부른 추상화 대신 아주 작은 교집합 찾아내기

제가 회사에서 수행하는 업무는 물류 도메인에 필요한 프론트엔드 개발을 지원하는 것입니다. 이번 센터 오픈 지원을 진행하면서 새롭게 개발이 필요한 영역은 '피킹 프로세스'였습니다. 피킹 프로세스는 물류 센터에 보관하고 있는 상품을 패킹(출고할 수 있는 상태로 만드는 절차)할 수 있도록 만드는 전처리라고 생각해주시면 됩니다. 할당된 물품들을 물류 창고에 보관되어 있는 곳들을, 동선에 따라 지나가며 토트(상품을 담는 바구니)에 지정된 상품을 담아서 약속된 장소로 이동시켜주는 절차입니다. 이를 위해 작업자들은 스캐너 기능이 있는 PDA 기기를 이용하며, 우리 팀은 해당 기기에 사용할 어플리케이션을 개발하는 업무를 맡게 되었습니다.
 
 
그런데 왜 그런 비슷한 일을 하는 시스템을 별도로 개발하게 됐을까요?! 앞서 설명한 핵심 요건은 같았지만 그 절차가 매우 달랐기 때문입니다. 이럴 때 우리는 많은 고민을 하지만 저와 팀은 한개의 어플리케이션을 만들어 서로 다르게 사용하는 것이 위험할 수 있다는 판단을 했습니다.

  1. 실무에 투입되기 전 섣부른 추상화를 하여 더욱 복잡도를 향상시키는 행위를 하지말자.
  2. 사용성이 비슷해지면 어느 하나를 말라죽이고 이관하는 행위가 더 쉬울 것이다.

위의 두가지가 가장 큰 이유였습니다. 많은 개발자 분들이 효율성을 위해 하나를 만들어 여러 곳에서 사용합니다. 재사용성을 프로그래밍의 미덕으로 생각하고 아직 현장에서 사용하지도 않은 로직을 하나로 개발하여 여러 분기를 만들어냅니다. 물론 이는 중요합니다. 그리고 이것이 나쁘다는 의미는 아닙니다. 하지만 이미 사용중인 어플리케이션에 사용자의 피드백이 어느 정도 예측되는 기능을 넣는것과 아직 사용하지 않은, 앞으로 현장에서 많은 피드백을 수용해야 할 어플리케이션에 개발자들이 예측한 기능을 포함시키는 행위는 많이 다르다는 것을 경험했습니다.
 
 
어플리케이션 사용을 시작하며 개발자들이 예측한 사용자들의 사용 방법이나 프로세스는 늘 예상을 빗나가거나 교묘히 다르기 마련입니다. 두개의 어플리케이션을 따로 개발하면서 저와 팀은 사용자들의 요구사항이 오픈 전과 그 후가 매우 다를것이라 판단한 이유입니다. 만약 우리의 예측이 다르면 적정한 시기에 하나를 닫고 다른 하나를 확장하는 것이, 하나의 어플리케이션을 모든 분기 처리의 다른 부분을 포함한 또 다른 어플리케이션으로 분리하는 것 보다 고통스러운 부분이 덜하다고 판단하였습니다.
 
 
그래서 우리는 더이상 쪼갤 수 없는 단위의 기능들을 열거하고 그 기능들을 만들고 또 로그인 페이지와 같이 공통으로 사용할 수 밖에 없는 단위들을 찾아내며 컴포넌트들의 조합을 만들었습니다. 라이브러리 제작을 하기로 결정했습니다.

아토믹 디자인 패턴

글의 시작 부분에서 언급했듯이 동시에 하나의 목적을 가진 두개의 어플리케이션을 개발할 수 밖에 없는 상황이었기에 저는 효율적인 방법을 찾아보았습니다. 그래서 별개의 절차에서 아주 작은 단위로 재사용이 될수밖에 없는 컴포넌트들을 제작하여 그것을 별개의 어플리케이션에서 가져다 쓰고 나머지는 어플리케이션의 구현부에서 다름을 장착하기로 결정했습니다.
 
 
완벽하고 또 베스트 프랙티스라고 할만한 수준은 아니지만, 목적에 합당한 수단으로 아토믹 디자인 패턴을 이용하기로 하였고 그것을 결정하고 약속하기 위해 팀원들과 많은 회의를 거쳤습니다.
 
 
여러가지 스캔과 입력상황을 대비하여 많은 수의 input 컴포넌트들을 만들었고 그것들을 각각의 page에 잘 조합하거나 또 꼭 동시에 쓸만한 것들은 조금 더 큰 단위의 컴포넌트를 만들어 개발을 진행했습니다.
 
 
비록 아직 추가해야되거나 지원해야 할 기능들이 많지만 우리는 적기에 어플리케이션을 완성할 수 있었고 각 센터의 요구사항에 충족되도록 수정하거나 확장할 수 있게 되었습니다.

마무리

솔직히 포스팅한지 너무나 오랜 공백이 있었고, 또 기억에 남는 일이었기에 글을 남기는거여서 여러분들이 읽기 재밌거나 유익한 내용이 아닐수는 있습니다. 하지만 간단하지만 복잡해지는 로직들을 보면서 우아한 방법으로 여러 곳에서 사용하게 만드는 것 보다 때로는 단순하지만 안전하게 코드베이스를 관리하는 방법도 있다는 말씀을 전달하고 싶었습니다.
 
 
현장의 피드백을 충분히 적용하고 그 후에 발견된 공통된 규칙으로도, 우리는 우아하게 시스템을 관리할 수 있습니다.(물론 제가 많이 부족하여 내린 결론일 수 있습니다.)

if (a == 0 && a == 1)

며칠 전 꽤 흥미로운 짤을 접했습니다.

그냥 지나가는 짤이라 생각하고 별 생각이 없었지만 해당 게시물에 페친분들의 댓글이 계속해서 달리면서 위의 난해한 코드를 직접 구현해 보게 되었습니다.

 

자바스크립트를 다뤄본 개발자라면 위 구문의 'a'는 '변수'라고 자연스레 가정할 것입니다. 하지만 일반적인 변수로는 위의 평가를 통과할 수 있는 구문을 작성할 수 없습니다. 그렇다면 어떻게 접근해야 할까요?? 이와 비슷한 기능을 하는 것은 무엇일까요?? 만약 a가 일반적으로 프론트엔드 개발자들이 담는 예측할 수 있는 값이 아니라 프로퍼티라면??

 

아마 getter와 setter를 활용하여 해당 값을 담고 반환할 수 있겠죠?! 그렇다면 window의 프로퍼티로 1. 일반적인 변수 형식으로 2. getter에 변화를 주어 반환하게 한다면 가능하지 않을까요??

 

다음은 위의 개념을 증명하기 위해서 테스트를 진행한 코드입니다.

Object.defineProperty(window, 'a', {
    get: function () {
        return window.b++;
    },
    set: function (val) {
        window.b = val;
    }
});
Window { parent ... }                 // 시스템 출력
a = 0;
0;                                    // 시스템 출력
a == 0 && a == 1
true                                // 시스템 출력

const, let과 달리 var를 사용한 변수는 자동적으로 window의 프로퍼티가 되며 window는 생략 가능합니다. 이러한 부분을 고려하여 위에서 정의된 'a'를 'window.a'로 만들면 자연스레 'a'로 접근과 사용이 가능합니다. 그러면 위의 '1. 일반적인 변수 형식'은 만족합니다.

 

동치연산자는 좌변과 우변의 값을 대조하여 평가(이때 여러가지 일이 벌어지지만 해당 부분은 별도로 찾아 보시면 좋을것 같습니다)합니다. 이때 값을 가져오면서 해당 프로퍼티의 값을 평가하게 됩니다. 이 말은 getter가 실행된다는 의미입니다. 위의 '2. getter엔 변화를 주어 반환'한다는 조건에 맞아 떨어집니다.

 

이제 'a'는 위의 두 조건을 모두 만족하여 변수처럼 할당한 값이, 평가되는 순간 변이가 일어나게 되며, 'a == 0 && a == 1'도 true로 평가됩니다.

 

...

...

 

그렇다면 이것은 과연 좋은 코드일까요??

좋은 코드는 무엇인가??

좋은 코드는 무엇일까요?? 클린 코드?? 오류없는 코드?? 요구사항이 잘 반영된, 납기일을 만족하는 코드??

 

좋은 코드는 각자의 상황과 역할에 따라서 정의하는 것이 매우 다를것 같습니다. 좋은 코드를 말하기 위해서, 저는 나쁜 코드는 무엇인가를 매우 한정적으로 정의를 내리고 그것의 반대되는 개념을 찾게 되었습니다.

 

제가 생각하는 나쁜 코드는,

  1. 목적이 불분명한 것들의 조합
  2. 성장하지 않는(리팩토링 되지 않는) 코드
    입니다.

매우 한정적이지만 많은 것을 포함하고 있습니다.

if (a == 0 && a == 1)은 무엇인가??

만약 이 게시물을 만들게 된 평가식을 우리가 관리하고 있는 프로덕트에서 마주하게 된다면 '기 작성된 코드'는 프로퍼티로 식별할 수 있게 반드시 수정되어야 합니다.

 

전역객체를 오염시킬 뿐 아니라 함께 작업을 하고있는 많은 협업자들을 혼란에 빠지게 할 수 있습니다. 구문을 이해하기 위하여 파편화 된 전역 설정을 찾아봐야 할 것이고, 'a'가 도대체 어디서 어떻게 이용되고 있는지 수정 혹은 개선하기 전 모든 스펙과 사용처를 확인해야 합니다.

 

자바스크립트의 전문가 중 한분은 이러한 코드도 '명확한 의도를 가지고 기능하도록 만들었기에' 문제가 없다고 피드백 주시는 분도 계셨습니다. 하지만 우리는 실제 프로덕트를 '그루'로 불리는 전문가들로 구성된 lab에서 개발하지 않습니다. 우리는 함께 일하고 있는 '누구나', '언제든', 해당 코드를 찾고 개선할 때, 명확한 방법과 영향을 알고 사용해야 합니다.

좋은 코드는 나쁜 코드의 반대, 그리고...

사람은 항상 실수를 합니다. 사람이 작성한 코드는 실수를 유발할 수 있습니다. 우리는 이것을 각종 약속과 규약으로 줄이기 위해 노력합니다.

 

코드컨벤션, 현재의 문제점 공유, 코드리뷰, 정적 분석 모두가 실수를 줄이기 위하여 하는 행위(꼭 순수한 목적은 아닙니다)들 입니다.

 

실수를 줄이고, 실수를 할 수 있는 부분을 없애가며, 그 경험을 공유하는 것은 좋은 코드를 향해 나아가는 좋은 자세가 될것이라 믿습니다.

 

조직이나 개인의 여건에 의하여 언제나, 늘, 좋은 품질의 코드를 만들어낼 수는 없을 것입니다. 하지만 그것을 계속해서 묵혀두고 알고만 있다면 훗날 더 큰 어려움을 가져올 수 있다는 것도 인지하여야 합니다.

+ Recent posts