2022년 8월 12일

과학적 프로그래밍

[[/No-Silver-Bullet]]{은총알은 없다}는 말을 종종 생각하는 요즘이다. 그냥 한 가지만 확실히 처리하도록 만들고, 삭제하기 쉽게 만들고, 이름 깨끗하게 붙이고, 찾기 쉽게 계층구조로 패키지 구성하고, 최소주의를 지향해 다른 언어들에 잘 없는 기능은 가능한 한 적게 쓰는 것이 최선이 아닐까 한다.

얼마 전에 번역했던 [[/clipping/ewd/32]]{데이크스트라의 글}에 나왔던 과학적 프로그래밍의 개념을 계속 곱씹게 된다. 스스로 설명하기 어려웠던 내 취향이 있었는데, 이 글을 읽어보면서 그와 맞아 떨어지는 지점이 있다고 생각했다. 그래서 스스로 납득할 수 있는 원인을 좀 마련하게 됐다.

과학적 프로그래밍은 과학적 과제에 대한 프로그래밍을 말하는 것이 아니다. 표준화된, 아주 오래 지속될만한 표현에 집중해 프로그래밍하자는 것이 과학적 프로그래밍의 핵심이다. 머신의 특성이나 언어의 특성에 집중하는 것은 덜 바람직하다고 생각하는 방향이다.

헤밍웨이는 최근 100년 안에 생겨난 유행어는 자기 작품 안에 사용하지 않는다고 했던가? 그와 비슷한 방향이다. 예를 들어 if return filter map reduce 같은 것들은 역사가 길고 여러 언어에 많이 등장해서 대부분 한눈에 알아보기 용이하고 동작도 예측하기 쉽다. 즉 언어나 환경을 덜 탄다. 이런 것들로 작성된 프로그램을 운영하고 있는 조직이라면, 다른 언어를 다루다 건너온 사람도 쉽게 적응한다.

두 개의 취향: 과학적 언어 표현과 청테이프라는 만능 도구

Java + SpringBoot를 쓸 때를 떠올려본다. 애노테이션으로 이런저런 설정을 하는 건 편리한 일이었지만 취향에는 맞지 않아 미묘한 감정이 들었다. 편리하지만 마음에 안 들다니 자신을 정확히 알 수가 없었다. 상당한 고맥락 대화를 나누는 느낌이었기 때문이었던 것 같다. 한번에 생각해야 하는 프로그램의 양을 줄이고 싶은데 애노테이션이 나에게는 그렇게 작동하지 않았던 것 같기도 하다. 이것은 관점에 따라 좋은 의미의 예술적인 코드를 선언한 것에 해당할 수 있다. 그러나 나에게는 데이크스트라가 말하는 비과학적 코드의 냄새가 느껴졌다. 이 애노테이션들에 대한 지식은 언젠가 SpringBoot가 사라지면 힘을 잃는다.

많은 사람들이 SpringBoot의 애노테이션 스타일을 선호하고 장점도 뚜렷하지만 내 취향에서는 애노테이션 달아서 해결하는 것보다 그냥 iffor 로 해결하는 것이 더 바람직하게 느껴진 것. '그래서 내가 Go를 좋아했구나'라는 생각도 새삼 떠올리게 되었다.

그래서 그런지 나는 Spring 핵심 기능은 좋아하는 편이고 SpringBoot는 별로 안 좋아했는데 (그럼에도 회사에서 SpringBoot는 계속 잘 써먹었다) DI를 설정 파일로 명시해서 깔끔하게 분리되는 느낌이 흡족했던 것 같다.

  • 소스코드는 비즈니스 로직을 표현한다.
  • xml 설정은 로직의 네임스페이스들 사이의 관계를 연결한다.
  • Spring은 Bean을 생성하고 관리한다.
  • 따라서 프로그램의 예술적 성격을 띄기 쉬운 영역은 설정 파일 안쪽으로 격리된다.

생각해보면 SpringBoot는 빠른 서비스 개발이 가능하지만 설정이 애노테이션의 형태로 소스코드에 침투해 들어간다는 점이 내게 아쉽게 느껴졌던 것이다. 분리해 놓았던 두 영역이 다시 섞인 것이니까.

Clojure를 통해 Lisp을 해보니 내 취향을 더 잘 알게 됐다. Lisp을 사용하게 된 건 굉장히 좋은 경험이라 생각한다. 그냥 Lisp을 쓸 수 있게 됐다가 아니라 Java + SpringBoot를 사용한 경험과 비교해보며 몇 가지 아이디어를 얻었고 내가 왜 셸 스크립트와 Go를 좋아했는지를 좀 더 꼼꼼하게 생각하게 됐다.

그리고 셸 스크립트는 오래 써먹을 프로그램을 작성할 수단으로서가 아니라 내가 한두번 써먹거나 대충 고쳐서 돌리는, 그야말로 청테이프 같은 용도로 쓰고 있었기 때문에 좋아했다는 결론. 즉 Go는 프로그래밍 언어로 좋아했고 셸 스크립트는 손에 익은 가위나 청테이프 같은 도구로서 좋아했던 것이다.

이런 관점에서 보면 놀랍게도 Vim은 언어로 좋아하는 것과 청테이프로 좋아하는 것이 적절하게 결합되어 있다. Vim의 normal 모드는 텍스트 편집을 위한 표준적인 언어를 제공하고(이 언어는 역사가 있고 널리 퍼져 있으며 앞으로도 오래 살아남을 것이다), 문제를 대충 해결하기에 적합한 Vimscript라는 튼튼한 청테이프를 제공한다.

계층형 네임스페이스

앞에서 언급한 "예술적 성격을 띄기 쉬운 영역을 격리하는 것"에 대해 더 생각해 보자.

최근의 나는 많은 것을 계층형 네임스페이스 문제로 변환해 생각하고 있다. OOP를 하건 FP를 하건 거기서 거기고 네임스페이스를 잘 꾸리기만 하면 평균적으로 괜찮을 것이다. 이런 접근을 하는 셈인데 좋게 보면 크게 보는 시각이 생긴 것 같고, 나쁘게 보면 디테일에서 거리를 두려는 것 같다.

아무튼 내가 데이크스트라의 글을 읽고 이모저모 생각해보며 느낀 건 나는 예술적 취향보다 과학적 취향에 가깝다는 결론. 내가 왜 emacs를 안 쓰나? emacs가 예술적 취향에 가깝다고 느끼기 때문이다. vim을 왜 쓰나? vim의 normal 모드가 과학적 취향에 가깝다고 느끼기 때문이다.

어떤 사람은 정규식이 사라져야 한다고도 말하는데 나는 왜 정규식을 좋아하나? 정규식이 예술이 아니라 어느 정도 대략적으로는 표준화된(…) 과학에 가깝다고 느끼기 때문이다. 정규식은 문제를 가린다는 측면에서 애노테이션과 비슷하지만 표준화 관점에서 볼 수 있어서 내 취향에 맞는다는 결론.

최근 동료 남영환님은 "엑셀은 영원할 것이다. RDB도 따지고 보면 엑셀이다. 두 애플리케이션의 핵심 아이디어는 단순한 2차원 테이블을 토대로 한다"라는 식의 말을 했다. 나도 비슷한 생각을 해왔으므로 강하게 동의했다. 나는 2차원테이블 아이디어는 지금까지 말한 과학의 선상에 있다고 생각한다.

일도 취향에 맞게 할 수 있으면 좋을텐데. 내가 원하는 식으로 드라이브하기보다는 어째 매일 다른 사람들 설득하고 여기저기 구멍 난 곳에 청테이프만 바르는 것 같다. 현자타임이 오는군.

2022년 8월 13일

DDIA: 산업 생태계가 바뀌었다

어제에 이어서 생각한다. 최근 나는 옛날 글 몇 개를 번역했는데, 목록은 대략 다음과 같다.

  • [[/clipping/predicting-the-future/]]{1989년, 앨런 케이: 미래를 예측하는 가장 좋은 방법은 미래를 만드는 것}
  • [[/clipping/ewd/32]]{1962년, 데이크스트라: 과학적으로 프로그래밍하자}
  • [[/clipping/marvin-minsky/why-programming-is-a-good-medium]]{1967년, 마빈 민스키: 프로그래밍은 확실하지 않게 이해한 대상을 표현하기 좋은 도구}

이 글들을 선택한 것은 내가 요즘 생각하고 있는 것들을 정리하기 위해서였다. 특히 과학적 프로그래밍은 오래 고심해왔던 주제와 맞닿는 면이 있어서 큰 도움을 받았다.

고민이 시작된 건 2018년에 데이터 중심 애플리케이션 설계(DDIA)를 읽으면서부터였다. 사람마다 책을 다르게 읽기 마련이지만 나는 [[/study/ddia/01-reliable-scalable-maintainable]]{이 책의 1장이 가장 인상적이었다}. 이 책에서 가장 중요한 챕터는 1장이라 생각했다.

1장 이후의 나머지 챕터들은 각각의 분야를 훑고 지나가는 내용을 담고 있다. 그래서 이 책은 설계 공부를 시작하는 사람을 위한 "지도"같은 책이라 생각했다. 흥미롭게도 이 책의 각 챕터 시작지점에는 지도 모양의 삽화가 있는데 때문에 나는 저자의 의도에 대한 내 생각이 대충 맞는다고 생각한다.

하지만 1장은 달랐다. 이 책의 1장 제목은 "신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션"인데 이것이 아주 달성하기 어렵다는 이야기를 한다. 1장에서 나오는 중요한 주장은 "계산 중심" 애플리케이션에서 "데이터 중심 애플리케이션"으로 유행이 바뀌었다는 것이다. 그리고 데이터 중심 애플리케이션은 만들기가 아주 어려운데 그 이유는 믿을 수 없는 것들을 엮어 신뢰할 수 있는 것을 만들어내야 한다는 목표가 있기 때문. 읽어보면 웃을 수 만은 없는 내용이 나온다. "하드웨어 못 믿고 클라우드 못 믿고 소프트웨어 못 믿고 사람도 못 믿는다"는 말이 1장 내내 나오는 이야기이다.

즉 산업 생태계가 바뀌었다는 말을 하고 있는 것.

1장을 잘 읽으면 개발자가 하는 일이 1970년대와 어떻게 달라졌는지를 대강 알 수 있고 많은 의문에 대한 어렴풋한 답변을 받을 수 있다. 예를 들어 컴퓨터를 전공한 사람이 회사 실무를 해보니 많이 다르더라는 말을 할 때가 있는데 그건 대학의 목표가 실무를 가르치는 것이 아니라 학문을 가르치기 때문이라는 대답도 가능하지만, 1장의 관점에서는 계산관점에 스스로 목표를 두고 공부하다 데이터 중심 관점의 일을 하는 회사에 취직한 것이 아닌가 라는 주관적 대답도 가능하게 되는 것.

말하자면 많은 것이 상대적으로 확실했던 계산 중심에서 어떤것도 믿을 수 없는 데이터 중심의 시대로 이동하게 되어 개발자는 이제 코딩만 하는 사람이 아니라 시스템 설계도 함께 해야 하는 사람이 되었다.

"이제부터 개발자는 애플리케이션 개발자뿐만 아니라 데이터 시스템 설계자이기도 하다"
– 5쪽

나는 이 문장이 이 책에서 가장 중요한 문장이라 생각했다. 왜냐하면 자신이 시스템 설계자 역할도 해야 한다는 사실을 모른다면 취업 준비는 물론이고, 회사를 다니며 별도로 해야 하는 공부, 사람들과 이야기하는 방법, 더 나은 회사가 어디인지 판단하는 기준 등이 모두 달라지기 때문이다.

내가 DDIA를 저렇게 읽었다는 것은 내가 그렇게 생각했다는 것이지 다른 사람도 그렇게 읽어야 한다는 말은 아니다. 다양한 방향에서 읽을 수 있는 책이라고 생각한다. 나는 이 책을 스터디할 때는 1장 스터디만 하고 나머지는 개인자습해도 된다고 생각한다.

바뀐 산업 생태계 관점에서 바라보는 과학적 프로그래밍과 코드 재사용

아무튼 번역한 글 이야기로 돌아가자.

데이크스트라는 예술적 프로그래밍과 과학적 프로그래밍을 이야기한다. 예술적 프로그래밍은 문제 해결에 대해 성능과 영감, 아름다움 등에 몰두한다. 반면 과학적 프로그래밍은 표준화에 몰두한다. 예술적 프로그래밍은 훌륭하고 나도 선망하는 가치이긴 하지만 과학적 프로그래밍 관점에서는 문제가 있는데 특정한 환경에 맞춰 기가막힌 작업물을 만들어내긴 하지만 일반화하기는 어려운 트릭이 생산된다는 점. 데이크스트라에 의하면 이런 트릭에 대한 지식은 해당 환경의 수명에 영향을 받으므로 인류의 지식에 별로 기여하는 바가 없다. 고립된 환경에서 독자적인 생태계를 구축하는 것과 비슷하다.

그래서 괴상한 트릭을 사용해 기발하게 문제를 해결하는 것이 아니라 성능상의 피해가 있다 하더라도 표준적인 방식으로 코딩하고, 훗날의 상식을 가진 다른 사람이 읽더라도 이해할 수 있게 만드는 것이 중요하다.

몇 년 전 앤디 허츠필드의 Revolution in the valley(미래를 만든 Geeks, 인사이트 출판)를 읽어보니1 이런 종류의 트릭을 쓴 코드를 작성했더니 [[/people/bill-atkinson]]{빌 앳킨슨}이 이건 해커들의 방법이지 책임감있는 방식이 아니라며 엄청 화를 내더라는 이야기가 나온다. 빌 앳킨슨도 이런 생각을 했던 것.

빌은 몇몇 경우만 빼고는 마라톤 식으로 진행되는 코드 처리에 참여하지 않았고 퀵드로가 그것에 영향을 받게 하지 않았다. 빌은 모든 코드는 가능한 간단하고 명확해야 한다고 믿었고 아마도 그가 옳았겠지만 결국에는 기교를 쓰지 않는 편이 더 좋다고 생각했다. 1983년 9월 롬이 동결되기 바로 전에 빌은 다른 팀원들이 간단하게 수정했던 메모리 매니저에서 버그를 발견했다.

나는 빌과 함께 메모리 매니저 소스를 유지 보수하는 래리 캐년의 자리로 갔다. 빌은 우리가 코드를 조금 추가해 버그를 수정하는 모습을 어깨 너머로 봤다. 그러나 빌은 우리가 꼼수를 사용하는 것을 보더니 그 방법을 반대하면서 화를 냈다.

"이봐, 그건 코드를 짜는 바른 방법이 아니야. 당신들 해커야? 나는 해커들과 일하고 싶지는 않다고."

래리와 나는 바이트와 사이클을 최대한 절약하기보다는 빌이 화내지 않게 하는데 더 신경을 쓰느라 수정 코드를 더 느리고 좀 더 보수적이며 빌이 인정한 기법을 사용하는 것으로 바꾸었다. 그 상황에서 더 느린 방법을 쓴 이유를 나중에 기억할 수 있게 소스코드 설명문에 주석도 달았다. 주석에는 "우리는 해커가 아니다!"라고 적었다.

– 미래를 만든 Geeks, 296쪽.

한편으로 이와 관련해 함께 생각해볼만한 깨어진 신화 중 가장 중요한 것 중 하나는 재사용성에 대한 것. 코드 재사용성은 중요한 가치로 언급되곤 했고, 많은 기업/학자/발명가들이 자신이 만든 생태계의 코드 재사용성을 강조했지만 실제로 작성된 코드를 재사용하는 것은 쉽지 않았고 대부분의 경우 새로운 코드로 대체하는 케이스가 더 많다는 것을 경험적으로 느낀다. cpan에서 maven을 거쳐 npm까지 이르며 오픈소스 라이브러리를 통한 코드 재사용이 이런 문제를 상당히 해결해주는 것이라 생각하기도 했었지만 요즘의 생각은 좀 다르다.

생각해보면 많은 문제가 코드 재사용의 레벨이 아직도 매우 낮다는 데에서 비롯된다. 문제의 근본은 재사용할 수 없게 코딩할 수 밖에 없는 기술적/환경적 원인들이다. 만약 램프의 지니에게 소원을 빌어서 완벽한 코드재사용이 가능한 세계가 되었다고 하자. 많은 개발자가 직업을 잃을 것이다.

차선책: 삭제 가능성

사실 나는 재사용성을 마음속에서 내려놓은지 좀 되어서 차라리 삭제하기 쉽게 만드는 것이 좋다고 생각한다. 대부분의 작업이 재사용하기 어려운 코드를 삭제하고 다시 작성하는 거라면, 공학적 측면에서 삭제하기 쉬운 코드를 작성하는 것이 바람직한 접근이라 본 것.

그래서 [[/article/hierarchical-controller-package-structure]]{이런 스타일}로 취향이 움직이게 됐다. 나는 이 관점에서 SRP가 강력한 실용적차선책이라 생각한다. 나이브하게 말하자면, 파일 하나에 여러로직이 있다면 지우기 위해 안쪽을 열심히 읽어야 한다. 하지만 파일 하나에 로직 하나가 있다면 그냥 파일을 지우면 된다.

그렇다면 남는 문제는 "지울 파일을 어떻게 찾을 것인가"인데 이건 계층 구조로 파일을 잘 배치해야 하는 문제라고 생각한다. 이건 처음에 감으로만 느끼고 있었다가 [[/REST-paper-summary]]{로이 필딩의 논문을 읽고 구체화하게 됐다}. 그래서 나는 REST가 내게 좋은 영향을 준 스타일이라 생각한다.

정리하자면 다음과 같다.

  1. 재사용성 해결하면 많은 문제가 해결.
  2. 재사용성은 부분적으로 달성됐지만 아직 멀었다. 해결하려면 과학적 코딩을 할 수 있는 환경이 강력히 마련되어야.
  3. 차선책: 삭제하기 쉽게 만든다.
  4. 삭제하기 쉬우려면: SRP. 계층 구조. 부모를 삭제할 때 자식도 한꺼번에 삭제.

차선책은 내 툴벨트에 들어왔다. 이제 생각할 문제는 앞으로 더 강력한 재사용성을 지향하려면 어떻게 해야 하는가이다. 이건 나 혼자만의 문제가 아니기도 하고, 잘 해결하면 대단한 성공을 이룰 수도 있다고 생각한다.

maven, npm의 수많은 라이브러리들을 보면 (물론 완성도와 보안 등에 문제가 있는 것들도 많지만) 벽돌은 많은데 이 벽돌들을 잇는 것은 아직 수작업으로 풀칠해서 이어붙여야 하는 느낌.

그래서 내 직업이 소중하지만 한편으로는 답답하다. 일상의 너무 많은 것들이 하드코딩이다. 재미있는 언어를 다룬다는 기쁨으로는 상쇄가 안된다. 어쩌면 내가 정말 즐거우려면 개발자가 아니라 다른 일을 하는 것이 더 맞을지도 모르겠다. 현대 사회의 회사라는 시스템이 나랑 안 맞는 거 같기도.

링크

주석

  1. 책을 선물해주신 @insightbook 님께 감사드립니다.