inlee's blog

회사 소프트웨어 개발 문화를 만든 과정과 느낀점

· inlee

과유불급(過猶不及) - 정도를 지나침은 미치지 못한 것과 같음.

개발자들이 자부심을 가지고 있는 것 중 하나는 사내의 개발 문화라고 생각한다. 이 개발 문화로 인해 개인이 성장하고 협업이 수월하게 되며 소스 코드의 품질이 올라간다. 심지어 개발자 채용에도 영향을 미친다. 마치 개발자들에게 매우 좋은 장비(특히 Mac과 4K 모니터)를 지급한다고 하면 혹하는 것처럼.

이전 회사는 작은 규모였으며 초기에 개발 문화라는 것이 없었다. 담당자가 관리한 결과물을 인수인계해 주는 방식이였다. 이 글은 개발 업무 과정에서 나가며 느꼈던 불편한 점을 해결하고 추가로 진행했던 것들을 포함해 개발 문화를 만들어 간 과정과 느낀 점에 대한 이야기이다.

가장 먼저 했던 것: 버전 관리 시스템의 도입

가장 먼저 했던 것은 여러 곳에서 보관중이였던 소스 코드를 모은 후 하나의 장소에 모아 버전 관리 시스템(VCS; Version Control System)을 적용하는 것이었는데, SVN과 Git 중 고민하다가 Git을 도입했다. 그리고 코드 저장소 및 이슈트래킹 도구인 Gitlab 도 남는 컴퓨터에 설치하여 도입하였다. Git과 Gitlab에 대한 학습이 필요했지만, 이들을 선택한 주요 이유는 아래와 같다.

  • 많은 패키지 도구들(composer, npm, bower 등)이 Git을 기반으로 동작.
  • Git은 Github에서 구현 코드를 참조 & 공유 할 수 있는 플랫폼이 있음.
  • Github은 Private Repository를 유료로 제공했으나 비용이 들고 클라우드 환경이라 배제.
  • Bitbucket은 당시 5명까지 무료로 Private Repository를 사용 가능했으나 이 역시 클라우드 환경이라 배제.
  • Gitlab은 Github과 매우 유사하며 회사 내 설치하여 사용 가능. 소스코드를 클라우드가 아닌 내부 보관이 가능.
  • 그 외: 유연한 브랜치, 오픈 소스 기여 가능성 등.

개인적으로 Git과 Gitlab의 도입은 가장 잘한 것 중 하나라고 생각한다. 특히 Gitlab은 코드 리뷰, 문서 관리, 이슈 트래킹 등의 기능과 같이 전반적인 개발 프로세스 등에 필수였으며 모든 프로젝트의 중심에 있었다.

이후 Gitlab은 직접 설치가 아닌 Docker 기반 으로 설치하고 Let’s Encrypt 인증서를 적용하여 사용하였다.

Docker의 도입

회사는 PHP로 개발하였는데, 처음엔 APM1 패키지를 이용해 개발했었다. 프로젝트마다 PHP 버전이 바뀌고 최신 버전 적용을 하기 위해서는 컴퓨터에 설치된 APM 패키지의 업데이트가 필요하였으며 여의치 않으면 무시하고 개발하기 일쑤였다.

이후 앞서 언급한 단점을 해결하고 적은 인원으로 개발과 운영을 동시에 하고자 Docker 를 도입하였다. Docker를 도입한 이후 PHP 버전에 맞는 이미지를 제작하여 사용한 후 삭제하면 깔끔하게 해결되었기 때문에 이러한 걱정은 싹 사라졌다.

처음엔 개발에만 Docker를 사용하고 서버는 예전과 같이 LAMP2 스택을 설치하여 사용했으나, 이후 Docker를 적용하였다. 어느 정도 Docker의 사용이 익숙해 지면서 한 대의 서버에 최대한의 자원을 활용하고자 Reverse Proxy로 여러 컨테이터(Container)를 운영하였다.

Docker는 현재 웹 개발자들에게는 없어서는 안 되는 공기와도 같은 존재가 되었기 때문에, 사용하지 않는다면 사용해볼 것을 권장한다. 팀 혹은 개인이 Dockerfile을 만들고 Docker Compose로 환경을 구성해 보는 것을 추천한다.

소프트웨어 개발 구성

Backend

PHP 7 버전 이상에서 개발하였으며 공개된 프레임워크를 이용하였다. Codeigniter 를 처음으로 Express.js 와 비슷한 Slim 을 도입하여 사용하였으며 마지막 프로젝트에는 Laravel 을 사용하였다.

Slim은 구성원들이 Express.js의 학습에 도움이 될 것 같아 도입하였고 써본 결과 효과가 있다고 생각한다. 그러나 규모가 큰 코드 구현에는 라우터(Router)에 직접 코드를 작성하는 것이 아닌 클래스로 컨트롤러를 구현한 후 라우터(Router)에 연결해야 복잡도를 낮추고 구조적으로 개발을 할 수 있었다. 결국 이렇게 되면 Laravel과 비슷한 형식이 되었다.

그래서 이전 회사에서 진행한 마지막 프로젝트는 Laravel을 도입하였고, 러닝 커브(Learning Curve)3가 높지만 이를 넘어서면 artisan 명령어를 이용해 필요한 코드에만 구현을 할 수 있도록 되어 있으며 기본적인 패키지(사용자 인증, ORM, Session 등)가 포함되어 있어 편리하였다.

Slim과 Laravel을 사용해본 결과 REST API 용으로는 Slim, 모놀리딕(Monolithic)4 어플리케이션 용으로는 Laravel이 적절하다고 생각한다.

Frontend

처음엔 단일 파일로 CSS, JavaScript를 구현했지만, 코드가 방대해짐에 따라 모듈화의 필요성을 느껴 Webpack 을 도입했다. 그리고 코드의 보안을 신경 쓰고자 Webpack의 Uglify, Minify 등을 적용하였다. CSS의 경우 전처리기인 SASS의 SCSS를 이용해 구현했으며 JavaScript는 ES6의 방법으로 모듈화를 한 후 하나의 CSS, JS 파일로 생성한 번들(Bundle)을 소스코드에 사용하였다. 이 과정은 C++ 기반으로 개발할 당시의 빌드(Build)와 매우 유사한 과정이다.

이전 회사의 마지막 프로젝트에는 개인적으로 공부하였던 Vue.js 를 사용했으며 때마침 Laravel에서도 지원하고 있었다. 이에 따라 CSS, JavaScript를 좀 더 효율적으로 구현하여 사용할 수 있게 되었다. Laravel의 경우 Vue 사용을 설정하면 webpack 설정까지 같이 적용되는데, 기존 webpack을 사용했던 경험으로 인해 손쉽게 사용이 가능하였다.

IDE

텍스트 위주의 에디터를 이용하였다. 개인적으로 Sublime Text 를 사용해본 후 회사에 도입하여 사용하려 하였으나, 유료였기 때문에 이후 Github에서 만든 ATOM 에디터를 적용하였다. ATOM 에디터는 Sublime Text와 사실상 같았으나 심각한 수준으로 느리다는 단점이 있었고 Visual Studio Code로 변경하여 현재까지 사용하고 있다.

PhpStorm 같은 도구를 고려할 수도 있었으나, Visual Studio를 이용해 C++로 OpenGL or DirectX, MFC, CUDA, Shader(GLSL, Cg, HLSL) 등을 이용해 개발할 당시에도 인텔리센스(Intellisense)5는 크게 도움이 되지 않았으며 필수라고 생각하지 않았고 비용 문제 때문에 고려 대상에서 제외하였다.

Code Convention

되도록 해당 언어의 표준을 따르려 했으며 JavaScript를 이용할 경우 eslint를 적용하여 사용하려 하였다.

들여쓰기(Indent) 등은 space로 2칸 혹은 4칸과 같이 에티터의 환경설정을 통해 적용하여 사용했으나, editorconfig 라는 것을 알고 나서 관련 설정은 이곳에 하기 시작하였다.

서버 환경 구성

앞서 언급한 것과 같이 처음에는 개발은 Docker 기반에서 하고 서버는 LAMP 스택을 설치하여 사용했으나, 개발 / 운영 환경을 일치시키기 위해 서버도 Docker로 변경하였다.

이후 서버 1대에 여러개의 웹 서비스를 운영하기 위해 NginX Reverse Proxy를 이용해 구성하였고 Let’s Encrypt 인증서의 발급 / 갱신 과정에도 Docker 기반의 Certbot 을 이용해 사용하였다.

업무 프로세스

개발

기본적인 사용자 인증, 게시판과 Webpack 관련 설정 정보를 먼저 구현해놓은 기본 프로젝트를 만들고 새로운 프로젝트는 이를 fork 하여 진행했었다. 그와 동시에 업무를 진행하며 기본 프로젝트에 개선이 필요한 부분이 발견되면 수정하여 개선해 나갔다.

코드는 개인이 프로젝트를 맡아 진행했기 때문에 master branch에서만 진행했었다. 개인적으로는 이 것이 가장 후회되는 것인데, 최소 master/dev branch로 각각 나눈 후 Master는 현재 운영 서버의 내용, Dev는 현재 개발 진행중인 내용으로 분리한 후 merge를 했다면 효율적임과 동시에 개발 규모가 커졌을 때를 대비할 수 있게 되었을 것 같다는 생각이 든다. pull request도 진행했으면 어떠했을까 하는 생각도 든다.

코드 리뷰는 Gitlab에서 Push한 코드들에 대해 Comment를 작성한 후 피드백을 받는 식으로만 진행했다. 최대 2명 정도만 개발 인원이 유지되었기 때문에 특별한 상황 혹은 반드시 고쳐야 할 부분이 있을 경우에만 이와 같은 방식으로 진행했지만, 개인이 프로젝트를 전부 맡아 진행했고 업무가 증가함에 따라 나중엔 잘 하지 않게 되었다.

Gitlab기능 중 이슈 트래킹, 위키(Wiki) 등은 필요할 경우에만 작성했으며 크게 사용하지 않았다. 개인이 프로젝트를 맡아 진행했고 주로 고객 요구사항을 최대한 빨리 수정하여 운영서버에 반영해야 했기 때문에 이슈 작성, 업무 분배 등을 할 필요성을 느끼지 못하여 결국 하지 않게 되었다.

고객과의 협업

Docker를 도입한 이후 대부분의 프로젝트에서 개발된 결과물을 실시간으로 테스트 서버에 업로드하고 고객에게 공개하였다. 이후 개발이 완료되면 테스트 서버는 데이터의 초기화를 거쳐 운영 서버가 되었다.

이는 개발 중간중간 잘못된 요구사항의 수정이 가능했고 동시에 테스트가 됨에 따라 동작, 웹사이트 레이아웃의 오류 등을 개발 과정에서 수정할 수 있었다. 또한 요구사항이 추가될 경우, 비용/일정 조정 등이 가능했고 프로젝트 완료 후에는 큰 문제가 발생하지 않았다.

개발자 입장에서는 중간중간 요구사항이 변경되면 Side Effect6 발생 가능성 등을 고려해 수정을 해야 하기 때문에 번거로우며 심지어 짜증 나는 일이 아닐 수 없다. 하지만 긍정적으로 생각해야 한다. 개발이 완료된 상태에서 수정을 하려면 Side Effect 범위 판단이 되지 않기 때문에(최악의 경우에는 전체에 발생) 개발 중간에 일정과 요구사항을 넘어서지 않는 범위 내에서 수정을 하는 것이 낫다. 마치 치과를 미리 가는 게 돈이 덜 드는 것처럼. 숨기면 안된다.

어찌보면 이 방법은 애자일(Agile)에서 주장하고 있는 방법과 유사한 것 같다.

배포(Deployment)

과거에는 서버를 일반 웹 호스팅을 사용했기 때문에 FTP를 이용해 업로드하여 배포하였으나 서버 자체를 사용하게 되면서 Git을 이용해 ssh로 로그인한 후 git pull 명령어를 이용해 수동으로 배포하기 시작했다.

그러나 이 과정은 서버에 직접 로그인해야 하기 때문에 최악의 경우 서버의 소스코드가 없어질 가능성이 항상 존재한다. 그래서 이 배포 과정을 도구를 통해 사용하는 것을 고려하였고 Jenkins에 있는 배포 기능과 같은 Gitlab CI/CD를 테스트 하고 도입까지 준비하였으나, 적용은 하지 못하였다. 개인이 프로젝트 전부를 담당했기 때문에 필요성을 느끼지 못한 것도 있었다.

그 외

  • 팀 내 혹은 사내에 개발관련된 내용을 공유할 때는 이메일 혹은 전자결재를 이용하기도 하였다.
  • 노션(Notion) 도 사용했으나, 과금 문제로 인해 최대 블록(Block)을 다 채우고 난 후 사용하지 않게 되었다.
  • 메신저는 슬랙(Slack) 을 사용했으나, 팀원이 얼마 없었던 관계로 사용하지 않게 되었다.
  • 타입스크립트(Typescript) 을 적극적으로 도입하려 했으나 하지 못해 후회가 된다. 자바스크립트에 없는 자료형을 사용할 수 있다는 것이 가장 큰 이유였다.
  • TDD(Test Driven Development) 하는 방법은 알았지만 하지 않았다. 이것 또한 후회가 된다.
  • 프론트엔드(Nuxt) 와 백엔드(Node.js)를 완전 분리하려 적용하려 하였으나, 시간/여건상 과(過)했다.
  • GraphQL, REST API(swagger.js 이용 문서화)적용하려 했으나, 시간/여건상 과(過)했다.
  • Redis, ElasticSearch 는 사용해볼 기회는 없었지만 현 상황에서는 과(過)했다. 그러나 언젠가 필요하다고 생각한다.
  • Logstash 도 검토했으나, 현 상황에서는 과(過)했다.
  • 비동기 메시지 큐(Queue)인 RabbitMQ 도 보게 되었는데, Apache Kafka 를 더 많이 사용한다는 것을 지인과의 대화를 통해 알게 되었다. 이 또한 언젠가 필요하다고 생각된다.
  • Docker를 사용하게 되면서 k8s(Kubernetes) 도 보게 되었는데 이 또한 언젠가는 필요하다고 생각된다.
  • 개발 스터디를 진행했었는데, 얼마 가지 못하였다.
  • 팀 블로그를 해봤으면 했지만 실현하지 못했다.
  • Confluence / Jira 같은 도구들은 현 상황 및 사정상 과(過)했고 사용하고 있는 Gitlab으로도 충분하다고 판단하여 도입하지 않았다.

결론

이 글은 아무것도 없는 상태에서 개발 문화를 만들어 나간 경험에 대한 이야기이다. 이 과정에서 과(過)하게 한것도 많이 있었고 하지 않은 것도 있었으며 후회 되는 것도 있었다.

개발 문화를 만들어 가며 느낀 점은 사정에 맞에 적용해야 한다는 것이다. 많은 것을 하려 하다보니 개발 업무보다 도구를 사용하는 것이 비중이 더 커지는 경우가 있기도 했다. 과유불급(過猶不及) 이였다.

또한 이 개발 문화는 만든다고 해서 당장 만들어지는 것은 아니였다. 필요하다는 것을 설득시키는 과정이 필요했으며 적응의 시간 또한 필요했다. 그리고 개발자의 능력은 상대적이기 때문에(신입 포함), 모르는 사람에게는 반드시 배려해야 하며 공유할 수 있는 수단이 필요하다. 변화에 더디거나 싫어하는 사람들도 있기 때문에 너무 빠른 도입과 폐기는 독이 될 수도 있음을 반드시 알고 있어야 한다.

중요한 것은 이 글은 개발 조직이 **“작은 회사에서 나름 문화를 만들어 나간 경험”**에 대한 내용이라는 것이다. 큰 조직이라면 이미 만들어진 문화가 있을 것이기 때문에 상황은 달라질 것이다.

마지막으로 개발 문화의 발전은 조직과 개인을 성장시키고 고인물이 되지 않게 도와준다. 그리고 개인이 했던 경험들이 공유될수록 누군가 또한 간접 경험을 통해 성장을 하게 된다. 소프트웨어 개발은 창의적인 일을 하는 직업이며 이를 가능하게 해 주는 것 또한 개발 문화이다. 좋은 토양에서 좋은 비료와 물, 잡초의 관리 등을 통해 좋은 열매와 곡식이 나오듯이 개발 문화 또한 발전과 개선을 꾸준히 해 나간다면 좀 더 효율적이고 건설적이며 개발에 집중할 수 있는 있는 환경이 만들어질 것이다. 그리고 개발자를 꿈으로 삼는 누군가에게 긍정적이고 희망을 줄 수 있을 것이라 생각한다.


  1. Apache, PHP, MySQL 패키지. ↩︎

  2. APM + Linux. 리눅스에 APM 패키지 설치하여 사용하는 것을 말함. 설치 방법 참조. ↩︎

  3. 학습 곡선이라고도 하며 무엇인가를 습득하는데 드는 시간(학습 비용)을 말함. 자세한 내용은 링크 참조. ↩︎

  4. 모놀리딕 아키텍쳐(Monolithic Architecure) 라고도 하며 어플리케이션 하나에 모든 것을 구현하는 것을 말함. 반대말은 마이크로 아키텍쳐(Micro Architecture). ↩︎

  5. 변수나 함수 이름 등의 단어 자동 완성 기능. 자세한 내용은 링크 참조. ↩︎

  6. 부작용으로 번역되며 프로그래밍에서는 한 곳에서 오류가 발생하면 다른 곳에도 오류가 발생한다는 의미. ↩︎