오픈소스에 한걸음 더: 2018 오픈소스 개발자 이야기를 다녀와서

KakaoTalk_Photo_2018-07-07-20-57-06
한국 마이크로소프트

지난 6월 30일 토요일, OSS 개발자 포럼의 주최로 ‘2018 오픈소스 개발자 이야기’라는 주제의 세미나가 한국 마이크로소프트에서 열려 참석했다. 인프라 엔지니어로 일하던 시절, 개발자로 일하기를 열망하며 퇴근후 틈틈이 웹을 공부하고 ‘구글은 SKY를 모른다’, ‘오픈소스 소프트웨어 아키텍쳐’와 같은 책을 읽었었다. 그때만 해도 오픈소스에 대해 어렴풋이 알고있었는데 이런 책들을 통해, 그리고 뭔지 모르면서도 GitHub Explore를 기웃거렸던 경험을 통해 오픈소스에 대한 이해를 키워갔다. 그러면서 참 설레었다. 나도 언젠가 누군가에게 도움이 될 수 있는 소프트웨어를 만들고 싶다는 생각을 했다.

몇년이 지나 나는 지금 Frontend Engineer로 재미있게 일하고 있고, 오픈소스를 더 많이 사용하고, 더 많이 듣고 접하고 있다. 그럼에도 여전히 내가 어떻게 오픈소스에 기여할 수 있고, 오픈소스 소프트웨어를 만든다는 것은 어떤 의미이고, 이것으로 어떤 영향을 미칠 수 있는지 등 오픈소스를 아우르는 전반적인 것에 대해서는 이해가 많이 부족하다. 딱 이럴때 2018 오픈소스 개발자 이야기라는 매력적인 주제의 세미나가 Facebook을 훑던 중 눈에 들어와 바로 결제했다. 오후 1시부터 5시간이 넘는 시간동안 보고 느낀 것이 많았는데 이것에 대해서 정리해보고자 한다. 시작하기 전에, 정말.. 안타깝게도 세미나 당일 이천에서 11시에 출발해서 올라왔는데 교통이 너무 혼잡해 종민님의 발표부터 듣게되어 여기부터 후기를 작성하고자 한다. 정규님 죄송합니다..

김종민님의 ‘Elastic에서 Remote로 일하기’

Elastic에 대해서는 ElasticSearch를 여기저기서 많이 듣고 관련 오프라인 강의 세션도 몇번 들으면서 조금 알고있던 차였다. 종민님이 쓰신 ElasticSearch 책도 갖고있어서 종민님에 대해서도 조금 알고있었다. 제목에서 알 수 있듯이 종민님의 발표는 Elastic에서 원격으로 일하는 것의 다양한 면을 담고있었다. 언젠가 원격근무를 하고싶은 나에게 유익하고 재밌었던 시간이었다.

스크린샷 2018-07-06 오후 10.39.57

Elastic은 ElasticSearch이었던 사명에서 Search를 빼 현재의 이름이 되었다고 한다. 그래서 종민님의 말씀대로 구글에서 Elastic을 검색해보면 진성(?) ‘Elastic’ 말고도 고무줄 같은 것이 잔뜩 나온다..(피식했다) 발표를 들으며 깨달았던 것, 재밌었던 포인트들이 몇가지 있는데 이를 위주로 이야기 해야겠다.

Elastic이 돈을 버는 방법

오픈소스로 일군 회사는 대체 어떻게 수익을 내는지 궁금했었다. 소프트웨어를 파는 것은 아닐텐데 그럼 컨설팅이나 교육으로 버는 건가? 그러기엔 조금 적지 않을까? 라고 자문했었다. 알고보니 반은 맞고 반은 틀렸었다. 교육과 컨설팅이 있는 것은 맞지만 이외에도 기술지원과 유료 사용자 기능이 있었다. 기술지원은 지원하는 범위와 지원 시간에 따라서 가격이 책정되는듯 하다. Elastic에서 정기적으로 메일이 오는데 여태 자세히는 읽어보지 않았었다. 돌이켜보니 Subscription에 대한 내용과 기술지원에 대한 내용이 많았던 것 같다. 유료 사용자 기능은 뭔지 잘 모르겠지만 최근 ELK 이외에 Beats와 X-Pack 같은 전에 보지 못했던 제품군들이 눈에 띄었는데 당연히 유료 사용자라면 이런 추가적인 강력한 기능들이 제공되지 않을까 추측해보았다.

Elastic은 현재 약 800명의 직원이 있는데 Elastic의 제품을 사용하는 기업의 수에 비해 조금 적은 것은 아닌가하는 생각이 들었다. 기업의 종류와 국가도 매우 다양할텐데 직원이 그에 맞게 적절히 포진해 있는 것도 상당히 어려운 일이라고 느꼈다. 오픈소스 회사를 세워 수익을 어떻게 내는지 궁금했는데 조금 더 구체적으로 알 수 있었다.

원격으로 근무한다는 것

원격으로 근무하는 것이 어떤 것인지에 대해서 그간 여러 글들이나 세미나, Automattic에서 근무하시는 태곤님의 이야기를 통해 들었었는데 종합적인 장단점은 이런 것 같다.

우선 고정적으로 이동하는 시간이 사라지므로 시간적으로 더 여유가 있다. 이런 시간을 연단위로 계산하면 꽤 나올 것이다. 나의 경우, 하루 평균 출퇴근을 1시간으로 잡고 워킹데이를 200일로 잡으면 벌써 200시간이 나온다. 200시간이면 아주 많은 시간이다. 1시간이 넘는 경우가 대다수일 것이라 생각하면 정말 큰 장점으로 다가오지 않을까싶다. 다음으로, 개인이 가장 집중도가 높은 시간에 자율적으로 일할 수 있다. 낮이든 밤이든 본인이 가장 편한 시간에 일할 수 있다. 그리고 당연히 편하게 있을 수 있다.

그렇지만 이에 못지 않은 단점들도 존재하는데, 대표적으로 회의가 있다. 크고 작은 회의들을 Skype나 Zoom같은 툴을 이용해 진행할텐데 이게 생각보다 불편한 점들이 있다. 누군가 말을 하고 있으면 순간 interrupt 하기도 어렵고 순간순간 즉흥적으로 말하기도 어렵다. 화질 및 음질이 좋지 않을 수도 있어서 집중이 조금 어려울 수 있다. 그리고 아무래도 원격으로 근무하면 혼자 일하는 경우가 대부분이어서 회사 동료들과의 물리적이고 인간적인 소통이 결여된다. 얼굴을 보고 웃으며 이야기하기도 어렵고, 같이 식사나 맥주 한잔 하는 것도 없다.

종민님이 말하셨던 장단점도 이것과 크게 다르지 않았던 것 같다. 다만 단점에서 한가지 새로 배운 사실이 있는데, 동료들과 물리적으로 함께 일한다면 캐주얼한 대화를 가끔 하게 되는데 의외로 그것에서 배우는 점이 많다는 점이다. 생각해보니 정말 그런 경우가 많았던 것 같다. 요새 이런 이슈가 있었는데~, 이런 공부하고 있는데 이런 모임이 있더라~ 부터 시작해서 기술적인 이야기도 많이 나눴던 기억이 있다. 그러니 원격으로 일한다면 이런 부분을 놓치게 되는 셈이니 이것도 단점으로 작용하게 되는 것이다.

그리고 원격으로 일을 한다는 것은 필히 나에 대한 이해가 수반되어야 한다는 것을 느꼈다. 원격으로 일하고자 한다면 이렇게 일하는 것의 장점은 최대한 살리고 단점은 최대한 보완해야 할 것이다. 먼저 내가 혼자 대화없이 오랫동안 일을 할 수 있는지부터 알아야할 것이고, 없어진 이동시간을 어떻게 활용할 것인지, 나는 어느 시간대에 일하면 가장 능률이 좋은지, 일을 밀도있게 집중해서 단번에 끝내는 것 혹은 여유있게 천천히 하는 것 중 어떤 것이 내게 편한지 등 나 스스로에 대해 이해해야 하는 것이 많다. 그리고 동료들과의 인간적인 소통도 어떻게 보완할 것인지도 생각해봐야 한다. 참 ‘원격으로 근무한다는 것’이라는 짧은 한 문장에 많은 내용이 함축되어 있는 것 같다.

전에는 몰랐던 다양한 Software Engineer 직군들

Software Engineer 안에서도 다양한 직군들이 있는 것을 보고 놀랐다. Solution Architect, Developer, Infra Engineer는 알고 있었는데 Community Engineer, Support Engineer, Education Engineer라는 직군은 처음 알았다. 이름을 보고 어떤 일을 하는지 감이 오기는 했는데 그걸 알고나니까 일을 더 다양하게 할 수 있다는 것을 깨달았다. 내가 어떤 일을 잘 하고 좋아하는지 이해하고 있다면 그것에 맞춰서 이런 직군들을 선택해볼 수 있겠다는 생각을 했다. 가령, 전에는 단순히 Software Engineer라면 항상 기술을 다루고 만드는 일에만 관련이 있을 거라고 생각했는데 이제보니 나는 기술 자체를 만들고 활용하는 것보다는 이 기술을 다른 엔지니어들에게 잘 전달하고 이것으로 무얼 할 수 있는지 설명하기를 더 잘 하고 좋아한다면 Community Engineer나 Support Engineer를 하는 것이 좋을 수도 있을 것이다. 물론 아직 정확히 이 직군들이 어떻게 다른지는 잘 모른다. 전에는 단순히 알고있던 것을 이번 기회를 통해 좀더 자세히 알게되었고 나도 지금은 만들고 활용하는 것만 해왔는데 내가 잘 할 수 있는 것이 무엇인지 다시 한번 생각해봐야겠다.

변정훈님의 ‘오픈소스 생태계 일원으로서의 개발자’

개발자가 아니었을때 혼자 공부하면서 모르는 것을 찾아보면 변정훈님의 블로그가 매번 나와서 많이 참고하고 댓글도 달았었는데 눈앞에서 직접 뵙고나니 감회가 무척 새로웠다. 아웃사이더님이라니!

이 슬라이드 쇼에는 JavaScript가 필요합니다.

아직도 기억나는 것이, 당시에 git stash와 remote branch를 찾아보고 있었는데 사진처럼 동일한 블로그가 계속 나와 git 관련 글들은 정훈님의 블로그를 많이 참고했다.

정훈님은 오픈소스 생태계를 어떻게 바라보고 기여하는지에 대해 이야기 해주셨다. 근데 GitHub 티셔츠를 정말 좋아하시는 것 같다.

우리는 이미 오픈소스 생태계 안에서 살고있다

나는 지금껏 어떻게 하면 오픈소스 생태계에 입문할 수 있을까, 아직 부족한 게 너무 많은데 어떻게 기여할 수 있을까라고 생각해왔었다. 그런데 정훈님이 이미 우리는 모두 오픈소스 생태계 안에서 살고있다고 하는 것이 아닌가. 놀랐다. 그간 나는 오픈소스와는 관계가 아직은 먼 사람이고 어떻게 하면 발을 담을 수 있을까라고 단순하게만 생각하면서 계속 오픈소스에 관심을 두는 것을 망설였던 것 같다. 허나 이미 안에 들어와있고 이 생태계를 활용하면서 살고있다는 것을 깨닫게 되니 마음이 한결 가벼워졌다. 너무 딱딱하게 생각해왔었는데 이번을 계기로 내가 자주 사용하는 라이브러리들부터 되돌아보고 싶다는 생각을 했다. 가령, 내가 가장 많이 사용하는 API에 대한 Docs는 어떠한지, 설명이 추가되면 좋지는 않을지, 현재의 모습은 어떤 과정을 거쳐 이루게 된 것인지, 현재 가장 이슈가 많은 부분이 어느 것인지 등에 대해 먼저 살펴보면 재미있을 것 같다는 생각을 했다.

어떤 프로젝트를 하나 선택해서 시작한다기 보다는 조금씩 천천히 빠지게 되는 것

이 문장도 위 단락과 깊이 연결되어 있는 것 같다. 정훈님의 발표를 듣고 위에서와 같이 생각을 다시 해보게 되었는데 아래와 같은 흐름으로 생각이 바뀌게 되었다.

  • 내가 어떻게 오픈소스에 기여할 수 있을까? 잘 모르겠다. 아직은 아닌것 같은데..
  • 나중에 하게된다면 어떤 프로젝트를 선택해서 기여하면 좋을까? 잘 모르겠다.
  • 그런데 이미 내가 이 생태계 안에서 살고있다고? 아 내가 이미 도움을 크게 받고 있구나. 그렇다면 내가 지금 자주 쓰고있는 것들에 무엇이 있었지?
  • 아 내가 A라는 라이브러리의 B라는 API를 자주 쓰는구나. 이게 어떻게 동작하는지 한번 살펴보면 어떨까? Docs를 이렇게 보충하면 어떨까?…

전에는 무얼 하나 선택해서 시작해야 한다는 생각이 강해서 그런지 그것에서 오는 왠지 모를 압박감이 있어서 선뜻 선택하지 못했고 그래서 Docs나 코드 한번 살펴보지 않았었다. 그런데 이렇게 생각이 바뀌게 되니 정훈님의 말씀처럼 내 주위를 먼저 둘러보고 그것에 자연스럽게 관심을 갖게되어 천천히 기여하는 흐름이 훨씬 자연스럽다는 생각을 했다.

그리고 기여는 꼭 코드만으로 하는 것은 아니라는 말이 기억에 남았다. 이렇게 자연스럽게 관심을 갖고, 오탈자가 있으면 고쳐주고, 불필요한 개행이나 문법 오류가 있으면 고쳐주는 등의 문서화 그리고 이슈 리포팅 등의 다양한 활동이 모두 이 오픈소스를 더 낫게 만드는데 도움이 된다는 것을 깨달았다.

이력서를 받다보면 GitHub 활동을 꾸준히 하는 사람이 드물어서 아쉽다

위와 같은 말씀도 하셨는데 생각보다 활동하는 사람의 비중이 적어서 놀랐다. 그래도 지원하는 사람 중 절반은 되지 않을까 생각했었는데 꾸준히 활동하는 것이 중요하다는 것을 다시 한번 느꼈다. 대단한 것을 만드는 게 아니더라도 GitHub에 꾸준히 무언가를 올리며 활동을 한다는 것은 적어도 내가 무엇에 관심이 있는지, 어떤 언어 및 기술을 사용하는지, 얼마나 꾸준히 하고있는지 등에 대해 나타내는 것이니 안한다고 해를 입진 않겠지만 다른 개발자들과 교류하고 구직할 때에도 도움이 되지 않을까? Interviewer의 입장에서도 문장 뿐인 이력서만 보는 것보다는 GitHub 활동과 코드를 직접 볼 수 있다면 Interviewee에게 있어서는 더 잘 어필할 수 있는 좋은 도구가 되지 않을까한다.

송태웅님의 ‘해외 오픈소스 컨퍼런스 발표와 참여’

스크린샷 2018-07-07 오후 5.55.12

태웅님은 Linux Foundation – OSSEU17에 스피커로 참여하신 경험에 대해 이야기 해주셨는데 비록 같은 분야가 아니라서 구체적인 것은 잘 모르지만 그럼에도 느낀 것이 많았다.

꼭 Professional level이어야만 하는 것은 아니다

아직 국내 컨퍼런스에서 발표할 생각도 해보지 못했던 나로서는 해외 컨퍼런스에서 발표한다는 것은 대단하고 멀게만 느껴졌다. 태웅님의 발표에서 기억나는 것 중 하나는 이런 해외 오픈소스 서밋 및 컨퍼런스에서 스피커로 참여하는 것이 꼭 전문가 수준이어야만 하는 것은 아니라는 점이다. 여전히 스피커로 나서는 것 자체가 도전적인 과제이지만 어떤 프로젝트를 진행하면서 겪었던 문제, 이슈, 해결 및 대처 방법 등에 대한 경험 그리고 그 과정에서 느끼고 배운 것을 공유하는 자리가 될 수도 있다는 점을 알게되었다. 여기까지 생각이 미치니 틈틈이 생각하고 기록하는 습관이 중요하다는 생각이 들었다. 만약 올해 말 혹은 내년 초에 있을 서밋에 스피커로 참여하고자 한다면 무슨 프로젝트를 진행했는지, 어떤 문제점들이 있었는지, 그것을 어떻게 받아들이고 해결했는지, 무엇을 배우고 깨달았는지, 비하인드 스토리는 없었는지 등을 적어도 기억을 하고 어떤 주제로 이야기를 풀어나갈지 정리할 수 있어야하기 때문이다.

영어는 여전히 중요하다

후배들에게 영어를 매일같이 하라고 말하고 다닐만큼 직업의 종류에 상관없이 영어가 얼마나 중요한지 잘 이해하고 있었는데 태웅님처럼 해외 서밋에 스피커로 나가 영어로 자신의 경험을 전달하고 질문을 주고받으며 다른 개발자들과 잘 이야기하기 위해선 영어를 잘 해야한다는 생각을 색다른 느낌으로 다시 하게 되었다. 구글 검색에서 찾을 수 있는 좋은 글과 문서들이 대부분 영어로 되어있기 때문에 영어를 잘 하면 좋다는 말은 이제는 흔하지만 만약 내가 당장 다음달에 유럽에서 영어로 발표를 해야한다면 느낌이 어떨까? 질문도 오고 중간에 쉬면서 다른 사람들과 이야기도 해야할텐데 상상하는 것만으로도 벌써 떨린다. 물론 이것이 꼭 영어 때문이라기 보다는 발표를 한다는 점에서 떨리는 것도 있을 것이다. 이런 색다른 관점에서 생각해보니 영어는 정말.. 여전히 중요하다.

김영근님의 ‘파이썬, 파이콘, 파이썬소프트웨어재단’

영근님은 파이썬 커뮤니티가 파이콘 등을 통해서 교류하고 성장하는 과정에 대해서 이야기 해주셨는데 중간중간 너무 웃겨서 몇번을 웃었는지 모르겠다. 문장의 호흡이 짧은데 툭툭 개그를 치시는게 정말 웃겼다. 그러면서 표정은 또 진지하심.

건강한 커뮤니티

발표의 많은 내용이 파이썬 커뮤니티가 어떻게 사람을 대하고 그것을 통해 어떻게 성장해왔는지에 대해 다루었다. 무엇보다 감명 깊었던 것은 파이썬 커뮤니티의 정신이었다. 어떻게 사람을 대하고, newcomers를 어떻게 반기는지, 또 그들이 커뮤니티에 안착할 수 있도록 다양한 방법으로 돕고, 어떠한 차별없이 다양성을 존중하고 장려하는 문화가 정말 너무 좋았다. 이런 문화가 있는 커뮤니티라면 꼭 파이썬이 아니어도 그냥 들어가서 눌러앉고 싶은 생각이 절로 든다. 그래서 영근님의 발표를 들으며 파이썬이 갑자기 더 좋아졌다. 차별없고 다양성이 존중받는 그 어느 곳이든 모두 아름답다.

코드만이 오픈소스에 기여하는 방법은 아니다

변정훈님의 말씀과 닮은 점이 있었던 문장이다. 이미 파이썬을 사용하고 있는 것 자체가 파이썬과 파이썬 커뮤니티에 기여하고 있다는 점은 다시 한번 놀랍다. 누군가 만약 파이썬을 활발히 사용하고 있다면 다른 누군가가 모르는 것이 있을때 알려줄 수도 있고 파이썬이 보다 나은 언어가 될 수 있도록 개선안을 제시할 수도 있을 것 같다. 이외에도 커뮤니티를 알리고, 문서를 번역하고, 이슈를 리포팅하고, 문서화를 돕는 것 모두 오픈소스에 기여하는 일이라는 점이 기억에 남는다. 점점 나도 기여해보고 싶다는 생각이 강해지는 것 같다.

이문수님의 ‘아파치 제플린, 프로젝트 시작부터 아파치 탑레벨 프로젝트가 되기까지’

문수님은 어떻게 아파치 제플린 프로젝트를 시작했는지, 그 과정에서 어떤 일이 있었고, 어떻게 아파치 탑레벨 프로젝트가 되었는지에 대해 이야기 해주셨다. 발표 내용도 재밌었지만 말하시는 내내 웃는 인상이셔서 나도 모르게 계속 웃고 있었던 발표였다.

작게 시작하는 것

크게 성장한 많은 프로젝트들의 공통적인 특성인 것 같다. 그리고 유니콘 스타트업들의 시작에서도 비슷한 면이 있는 것 같다. 모두들 작게 시작했다는 점이다. 아래와 같은 흐름인 것 같다.

처음 어떤 자그마한 문제나 의문점에서 프로젝트를 작고 빠르게 만든다. 그리고 바로 공개한다. 운이 좋으면 크고 작은 피드백들이 오기 시작한다. 만든이는 이런 피드백을 보고 신나서 기능을 추가하고 없애고 수정하면서 더 개선된 형태로 프로젝트를 발전시킨다. 다시 피드백이 온다… 이하 사이클 반복

발표를 들어보니 아파치 제플린도 비슷했다. 하둡과 관련된 생태계(정확히 어떤 생태계였는지 기억이 ㅜㅜ)에서 비어있는 부분을 발견하고 그 부분을 채우면 어떨까하는 생각에 프로젝트가 시작된다. 얼마간 놔뒀다가 다음 해에 다시 빠르게 만들고 공개한다. 얼마후 반응이 오기 시작한다. 신난다. 개선한다… 반복

신기하다. 거창하게 시작하는 것보다 작게 시작하면서 사람들에게 정말 필요했던 것을 만들고 그것이 좋은 반응을 얻으면 그때부터 성장의 길이 열리는 것 같다. 뭔가 Lean 개발 방법론과 궤를 같이 하는 것 같은 생각이 들었다.

완벽한 코드 보다는 돌아가는 코드

발표를 잘 이해하지 못한 것일 수도 있는데 아파치 제플린 프로젝트가 커져가면서 더 많은 가치를 빠르게 전달하기 위해 완벽한 코드 보다는 돌아가는 코드에 집중했다는 기억이 있다. 문수님도 이를 두고 좋지 않은 코드가 당시에 많았었다고 회상하시던 기억도 난다. 물론 그 정도가 얼마만큼을 의미하는 것인지는 알 수 없지만 적어도 완벽한 설계를 바탕으로한 코드에 집착하는 것 보다는 돌아가는 코드를 빠르게 만듦으로써 프로젝트의 성장을 우선시한다는 뉘앙스로 다가왔다. 코드의 가독성 개선이나 최적화 등의 리팩토링은 프로젝트가 어느정도 궤도에 오른 뒤 밟아나가도 된다고 받아들이면 되는 것일까? 아마 그렇지 않을까싶다. 물론 처음부터 좋은 설계 위에 좋은 코드를 쌓으면 더할나위 없이 좋겠지만 꼭 좋은 프로젝트/서비스가 항상 좋은 코드로만 시작하고, 그런 코드로만 구성되어 있지는 않으니까 말이다.

소감

이렇게 후기를 마쳤다. 이야기만 들었을 뿐인데 오픈소스에 한걸음 더 다가간 것 같다. 내가 살고 있는 세상이 생각보다 훨씬 더 오픈소스에 영향을 받고있음을 느꼈다. 이제 개발자로 일한지 14개월이 되었는데 지금은 부족하지만 연차가 늘어갈 수록 더 실력을 쌓으면서도 코드 뿐만이 아닌 여러 방면으로 오픈소스에 기여해야겠다는 다짐을 해본다. 좋은 배움과 좋은 계기가 남는 알찬 세미나였다. 이런 세미나를 기획하고 준비한 OSS 개발자 포럼과 황금같은 주말 시간을 내어 발표해주신 모든 발표자분들께 감사한 마음이 든다. 나는 오늘도 도움을 받는다. 나도 조금씩, 더욱 도움이 되는 사람이 되기를.

참고하면 좋은 링크들

http://it.chosun.com/site/data/html_dir/2018/05/03/2018050385084.html

 

세미나 당일에 찍은 사진들

Advertisements

[webpack v4] Development 환경 구성하기

지난 Output Management 편에서는 다수의 js 파일을 entry point를 사용해 하나의 bundle 파일로 만들어보았다. 이번 포스팅에서는 프로젝트를 개발할때 쓰는 개발 환경을 구성해보도록 하자.

이 포스트에 관련된 코드는

https://github.com/brightparagon/webpack-conquer/tree/development

에서 확인해볼 수 있습니다.

이 글은 다음과 같은 내용을 다룰 것이다.

  1. webpack-dev-server
  2. Dev server options: proxy, historyApiFallback, stats…
  3. Source map

왜 이런 옵션들을 이용해서 개발 환경을 구성할까? 우선 webpack을 사용하는 환경이라면 대부분 [ 코드를 작성하고, babel 등을 이용해 트랜스파일하고, 결과물을 브라우저로 확인하는 ] 일련의 반복적이고 구조적인 과정이 잡혀있을 것이다. 간단한 웹을 만드는 경우에도 코드 수정 – 저장 – 브라우저 확인이라는 세가지 단계를 거치게 마련이다. 그런데 코드를 수정하고 결과물을 확인하는 일은 한두번으로 끝나지 않는다는 문제가 있다. 매번 이 작업을 수동으로 한다면 아주 귀찮은 일일 것이다.

webpack으로 이 과정을 자동화해주면 ctrl + s를 누르는 순간 변경 사항이 반영된 결과물을 브라우저에서 확인할 수 있다. 꽤나 큰 수고를 덜어줄 수 있어서 아주 편리한 기능이다.

webpack-dev-server

위에서 언급한 작업을 해주는 webpack의 도구에는 아래와 같이 크게 세가지가 있다.

  1. 기본적인 webpack cli + watch mode
  2. webpack-dev-server
  3. webpack-dev-middleware

이런 옵션들이 나뉘어있는 것은 다양한 환경에서 webpack으로 개발 환경을 구성할 수 있게 하기 위함이다. 1번은 단순히 모든 파일들을 감시하고 있다가 변경사항이 있을 경우 webpack config에 따라 리컴파일 한다. 다만, 변경 사항을 확인하기 위해서는 매번 브라우저를 새로고침 해줘야 한다. 2번은 express로 만들어진 간단한 web server이다. 이 옵션도 1번과 같이 변경 사항을 감지해 리컴파일을 한다. 그런데 1번과는 달리 브라우저를 리로드하고 더 다양한 configurable option들을 사용할 수 있다. proxy나 historyApiFallback 같은 것들이 이 옵션에 속한다. 3번은 2번에서 내부적으로 사용되는 subset인데 코드 변경시 webpack config 파일에 따라 컴파일한 코드를 내뱉는 역할만을 middleware로 패키징한 모듈이라고 이해하면 된다. 그래서 자체적으로 express server를 사용한다면 이 3번을 사용해 입맛에 맞게 서버와 함께 커스터마이즈 할 수 있다.

세 도구 모두 많이 쓰이지만 사이드 프로젝트를 셋업하는 등의 용도로서는 2번이 가장 많이 쓰인다는 경험하에 이 글에서는 webpack-dev-server를 다뤄보도록 하겠다.

먼저 npm install –dev webpack-dev-server 혹은 yarn add webpack-dev-server –dev를 터미널에 입력해 설치해보자. 그리고 저번 글에서 작성했던 webpack.config.js 파일을 아래와 같이 수정해 webpack-dev-server를 위한 설정을 추가해보자. 27 라인에 devServer라는 옵션이 추가되었다.

carbon (2)
webpack.config.js

devServer 옵션에서 포트를 8000으로 주었고 inline 모드로 설정했다. 포트가 8000이기 때문에 브라우저에서 localhost:8000으로 접근할 수 있다. devServer를 사용할때 컴파일된 코드를 일반적인 template html에 삽입하는 inline 모드와 iframe에 넣어 업데이트하는 iframe 모드가 있는데 HMR이 inline 모드에서 지원이 되므로 여기서는 inline 모드를 사용하도록 하겠다.

이제 이 설정을 이용해 서버를 실행하기 위한 스크립트를 package.json 파일에 작성해서 개발을 할때마다 이 스크립트로 프로젝트를 실행할 수 있도록 해보자. 8 라인에 “start” key가 추가되었다.

carbon (1)
package.json

webpack과 webpack-dev-server 두가지 도구 모두 –config 옵션을 주지 않으면 기본적으로 webpack.config.js 파일을 찾아서 사용하기 때문에 위 파일에서 “–config webpack.config.js”는 생략가능하다. 만약 config 파일명을 달리한다면 해당 부분을 변경해서 사용하면 되며 이후에 Production(운영 환경)을 위한 설정을 할때도 –config 옵션을 요긴하게 사용할 것이다.

이제 터미널에 npm start 또는 yarn start를 입력해 프로젝트를 실행해보자.

스크린샷 2018-06-27 오전 12.25.45

위와 같이 나올 것이고 버튼도 잘 작동할 것이다. 그리고 app.js 파일을 열어 Hello 문구를 Hello Development로 수정한 뒤 저장하고 브라우저를 확인해보자.

스크린샷 2018-06-27 오전 12.25.58

위와 같이 자동으로 변경 사항이 반영되어 있고 full refresh까지 된 것을 확인할 수 있다. port와 inline 이외에도 devServer에 줄 수 있는 다양한 옵션이 있는데 대표적으로 아래와 같은 것들이 있다.

  • proxy: 프로젝트 내에서 호출하는 외부 API나 다른 포트를 사용하는 로컬 서버 API가 있을 경우 이 API url들은 해당 서버로 호출하도록 우회할 수 있도록 만드는 옵션
  • compress: gzip compression을 사용하는 옵션
  • overlay: 에러가 발생했을때 브라우저에 풀스크린으로 에러 내용을 오버레이로 표시해주는 옵션
  • hot: HotModuleReplacementPlugin을 사용해 HMR 기능을 이용하는 옵션
  • historyApiFallback: HTML5의 History API를 사용하는 경우에 설정해놓은 url 이외의 url 경로로 접근했을때 404 responses를 받게 되는데 이때도 index.html을 서빙할지 결정하는 옵션이다. React와 react-router-dom을 사용해 프로젝트를 만들때도 react-router-dom이 내부적으로 HTML5 History API를 사용하므로 미지정 경로로 이동했을때, 있는 경로지만 그 상태에서 refresh를 했을때와 같은 경우에도 애플리케이션이 적절히 서빙될 수 있어서 유용한 옵션이다.
  • host: 기본적으로 애플리케이션은 localhost에서 서빙되지만 이 옵션을 이용해 다른 host를 지정해줄 수 있다. 또한 이 옵션에 ‘0.0.0.0’을 주면 개발중인 localhost를 외부에서 접근할 수 있다.

devServer에 사용할 수 있는 다양한 옵션에 대해 자세한 내용은 이 링크에서 확인하면 된다.

Source map으로 넘어가기 전에 위의 옵션들 중 몇가지를 사용해보자.

overlay

carbon (3)
webpack.config.js

위와 같이 devServer에 overlay 옵션을 true로 주고 app.js 파일에 일부러 잘못된 코드를 작성하자.

carbon (4)
app.js

8번 라인이 바뀌었다. appendChild 함수 실행부가 온전히 닫혀있지 않고 btn 변수명도 치다 말았다. 이렇게 변경하고 저장하면 브라우저에서 아래와 같은 화면이 나타날 것이다.

스크린샷 2018-06-27 오후 9.19.07

./src/app.js 에서 에러가 났고 문제가 되는 코드의 부분을 친절하게 알려준다. 이 옵션을 사용하지 않아도 개발자 도구 콘솔에서 알려주므로 꼭 사용하지 않아도 된다. 다만 에러가 났을때 확실하게 알려주는 것 같아서 필자는 꼭 쓰는 옵션이다.

historyApiFallback

다시 app.js 파일을 원래대로 돌리고 브라우저 url 주소를 보자. localhost:8000 일 것이다. 아직 우리의 애플리케이션은 루트 경로 이외의 url에 해당하는 페이지를 만들지 않았다. localhost:8000/mypage 를 직접 입력해 접속해보자. 아래와 같은 화면이 나타날 것이다.

스크린샷 2018-06-27 오후 9.34.50.png

이 url로 접속하는 순간 webpack-dev-server(express server)는 mypage라는 라우팅 경로가 있는지 확인할 것이다. 그런데 아무런 라우팅 설정을 하지 않았기 때문에 Cannot GET 에러를 낸다. 애플리케이션은 에러가 난 상태로 가만히 있게 되는데 개발 중간에 이렇게 멈춰있으면 url을 다시 입력해 이동해야 하는 번거로움이 생긴다. 이때 아래와 같이 historyApiFallback 옵션을 사용하면 이런 번거로움을 피할 수 있다.

carbon (5)
webpack.config.js

 

true를 주게되면 모든 404 responses에 대해 index.html로 리다이렉트를 하고 rewrites 옵션을 담은 객체를 주면 정규식을 이용해 더 복잡한 경우를 다룰 수 있다.

이제 아까와 같이 localhost:8000/mypage 경로에 다시 접속해보자. 곧장 접속해도, 이 경로에서 새로고침을 해도 애플리케이션이 서빙되는 것을 확인할 수 있다.

host

웹 애플리케이션을 개발하다 보면 다양한 태블릿이나 모바일 기기로 화면 및 기능 동작을 확인하거나, 결제 모듈을 테스트하거나, 근처에 있는 팀원이 봐야하는 경우가 종종 생긴다. 이럴때 host 옵션을 사용하면 유용하다. 아래와 같이 설정해보자.

carbon (6).png
webpack.config.js

이렇게 config 파일을 수정하면 앱을 재실행해주자. 그리고 맥이라면 터미널을 열어 ifconfig | grep inet을 입력해 현재 IP주소를 확인하자. 이제 태블릿이나 모바일 기기로 개발 중인 컴퓨터와 같은 와이파이에 접속한 다음 브라우저에서 방금 확인한 IP주소의 8000번 포트로 접속해보자. 예를 들어, 10.23.2.2:8000 과 같은 주소로 접속하면 된다. 필자는 모바일에서 접속했는데 아래와 같이 나온다.

KakaoTalk_Photo_2018-06-27-22-12-27

이제 app.js 파일을 열어 div의 text를 이리저리 바꿔보면서 저장해보고 모바일 화면을 지켜보자. 아래와 같이 저장할 때마다 자동으로 업데이트 되는 것을 확인할 수 있다.

KakaoTalk_Photo_2018-06-27-22-12-26

정말 편하다! 이제 Source map을 알아볼 차례다.

Source map

개발을 진행하다보면 점점 js 파일이 늘어나게 되는데 webpack은 여러 파일들을 하나 또는 특정 갯수의 bundled 파일로 묶다보니 error와 warning 메시지를 통해 어느 파일의 어느 코드에서 문제가 되는지 정확히 추적하기가 어려워진다. 이럴때 Source map을 사용하면 원본 파일을 통해 코드를 보여주고 error 및 warning 메세지도 정확한 파일명과 코드 위치를 짚어주기 때문에 유용하다.

bar.js 파일에서 아래와 같이 일부러 버그를 심어놓자.

carbon (7).png
bar.js

console을 cosnole라고 바꿨다. webpack v4 공식 다큐먼트에서 에러를 이렇게 심었다 ㅎㅎ. 그리고 앱을 재시작하고 버튼을 클릭해보자. 그리고 개발자 도구의 콘솔을 열어보자.

스크린샷 2018-06-27 오후 10.23.19

버튼을 누르면 이렇게 cosnole이 선언되어 있지 않다는 레퍼런스 에러를 뿜을 것이다. 그리고 이 에러 옆에 에러가 난 파일명과 몇번 라인인지 표시가 되어있다. 파일명을 클릭해보자.

스크린샷 2018-06-27 오후 10.23.35

webpack이 실컷 빌드한 코드로 연결하고 있음을 알 수 있다. webpack_require… 같은 코드가 보인다. 아직은 코드가 간단해서 볼만(?) 하지만 거대해지면 더욱 보기가 어려울 것이다. 이 에러를 보다 더 눈이 덜 아프고 깨끗하게 추적할 수 있도록 webpack config 파일을 아래와 같이 수정해보자.

carbon (8).png
webpack.config.js

4번 라인에 devtool 옵션이 추가되었고 ‘inline-source-map’ 이라는 값을 주었다. 저장하고 앱 재실행 뒤 다시 버튼을 클릭해보자. 이번엔 아래처럼 조금 다르게 표시될 것이다.

스크린샷 2018-06-27 오후 11.14.32

벌써 여기부터 조금 깔끔해졌다. 파일명에 군더더기도 없고 정확한 코드 라인을 표기하고 있다. 파일명을 클릭해보자.

스크린샷 2018-06-27 오후 11.14.40

전과는 달리 정확히 원본 파일을 보여주면서 에러가 난 라인도 잘 나타내고 있다. 이렇게 유용한 옵션이긴 하지만 webpack은 이를 위해 내부적으로 빌드된 파일과 원본 파일간의 관계를 나타내는 매핑 파일을 따로 만든다. 이걸 매 빌드마다 새로 만들어내므로 프로젝트가 거대해지면 한번 저장하고 변경 사항이 반영되기까지 상당한 시간이 걸린다. 필자가 만드는 리액트 프로젝트의 경우 총 11,000 라인 정도의 코드로 이루어져있는데 반영까지 체감상 3~4초 정도 걸리는 것 같다. 어찌보면 양날의 검일 수도 있어서 개발자들에 따라 이 옵션을 사용하지 않고 본능(?)으로 어느 부분이 잘못되었는지 추측하려 노력하는 경우도 있고(이 방법이 생각을 많이 하게 해서 좀 더 논리적인 사고를 하게 만드는 것 같다. 처음엔 무지 힘들긴 하지만..) 빠른 빌드를 위해 아예 사용하지 않거나 ‘inline-source-map’ 이외의 다른 옵션을 사용하기도 한다. 개발과 운영 모드에서 사용할 수 있는 옵션이 서로 다르고 개발과 운영 각각에서도 옵션이 다양하게 존재하는데 이에 대해서는 이 링크에서 확인하면 된다. webpack 공식 문서에서는 개발 모드에서는 ‘eval-source-map’ 또는 ‘cheap-eval-source-map’를, 운영 모드에서는 none(아예 사용하지 않음) 또는 ‘hidden-source-map’ 정도를 권장하고 있다. 필자의 프로젝트에서는 아직 크기가 아주 크지는 않기 때문에 개발 모드에서는 ‘source-map’을, 운영 모드에서는 ‘hidden-source-map’을 사용하고 있다.

글이 길어졌으므로 다음 글에서는 이번에 만든 개발환경에서 사용할 수 있는 Hot Module Replacement을 알아보도록 하자.

이 포스트에 관련된 코드는

https://github.com/brightparagon/webpack-conquer/tree/development

에서 확인해볼 수 있습니다.

Reference

https://webpack.js.org/guides/development/

https://webpack.js.org/configuration/dev-server

https://github.com/webpack/docs/wiki/webpack-dev-server

[webpack v4] Output Management

저번 Asset Management 편에서 index.html에 번들된 app.js와 bar.js를 불러와 사용했었다. 이번에도 비슷하게 시작해보자. 단, 이번에는 두개의 entry point로 만들어보자.

carbon
webpack.config.js

이렇게 복수의 entry point를 명시하면 webpack은 각 entry point마다 완전히 독립적인 dependency graph를 만든다. 흠.. 이걸 왜 하는걸까? 이후에 다른 글(CommonsChunkPlugin 관련)에서 더 설명하겠지만 이렇게 여러 entry point를 만들면 CommonsChunkPlugin를 이용해 앱을 원하는 청크들로 분리할 수 있다. 이렇게 분리하면 처음 웹앱을 접근할때 모든 js 파일들을 한꺼번에 불러오지 않고 dependency graph에 따라 그때그때(예를 들어 route 경로 변경) 필요한 js 파일을 불러오게 된다. 결론적으로 첫 랜딩 시간을 줄일 수 있다. real-world use case에서는 웹앱의 entry인 app과 앱에서 사용하는 third-party library들을 vendor라는 entry point로 묶는 방법을 많이 사용한다. 당연히 vendor가 각종 library들의 집합이므로 무거우니 이를 필요한 시기에 불러오면 효율적일 것이다.

webpack.config.js 파일을 위와 같이 만들고 yarn build 혹은 npm run build로 빌드를 해보면 두개의 번들 파일이 생긴다. 이외에도 entry point는 배열을 받을 수도 있는데 배열을 쓰게 되면 js 파일들이 여러개로 나뉘어 있을때 간단하게 하나의 entry point로 묶을 수 있다. entry point 전략에 대해 공식적인 설명이 궁금하면 이 글을 참고하자.

자, 이것이 우리의 실제 프로젝트라고 생각해보면 아래와 같은 일들이 생길 수 있다.

  • app.js의 파일명이 바뀐다
  • apple.js라는 새로운 js 파일이 생긴다
  • bar.js 파일이 삭제된다

이런 일들이 일어났을때 index.html의 script tag는 변경 사항을 반영해야만 의도된 결과를 얻는다. 거기다 output filename 설정에 hash라도 해놓으면 파일이 변경되면 매 build 마다 이름이 변경되어 index.html에 매번 반영해주기가 귀찮게 된다. webpack이 알아서 똑똑하게 현재 쓰이는/안쓰이는 파일을 구분해줬으면 좋겠지만 그러지 못하는게 아쉽다.

html-webpack-plugin comes to the rescue!

다행히 webpack 초창기부터 html-webpack-plugin이라는 플러그인이 생겼는데 이 문제를 해결해준다. yarn add html-webpack-plugin 혹은 npm install html-webpack-plugin –dev 설치하고 webpack.config.js를 아래와 같이 수정해보자.

carbon (1)
webpack.config.js

설치한 html-webpack-plugin를 불러오고 plugins 옵션에서 위와 같이 사용하고 있다. 이 플러그인은 Default로 아주 간단한 index.html을 사용해 자동으로 번들 결과를 script tag에 반영해주므로 더이상 index.html 파일을 따로 갖고 있지 않아도 된다.

html-webpack-plugin 옵션으로 title, inject, template 옵션을 사용하고 있는데 만약 우리가 우리만의 index.html을 사용하고 싶다면 template 옵션에 우리가 관리할 index.html 파일의 경로를 명시해주면 된다. 예를 들어, head tag에 cdn으로 style이나 폰트를 불러와 사용하고 번들 파일만 webpack이 자동으로 넣어주는 방식으로 사용할 수 있다. 그리고 inject 옵션을 true로 주었는데 Default로 true가 잡힌다. 이 옵션이 true 혹은 ‘body’일 경우엔 플러그인이 body tag에 script tag를 삽입해주고 ‘head’일 경우엔 head tag에 삽입한다. 자세한 것은 공식 문서에서 확인해보자.

clean-webpack-plugin

뭔가 편해진 것 같은데 아직 한가지 문제가 더 있다. 우리는 앞으로 build를 계속할텐데 번들 파일들이 build 폴더에 계속 쌓이고 있다. 이름이 같으면 덮어씌워지지만 다르면 계속 파일이 늘어난다. 이미 번들된 파일의 기존 파일이 지워졌을 수도 있고 파일명이 변경되어 새 번들 파일이 생겼을 수도 있다. 이 문제는 clean-webpack-plugin으로 간단하게 해결할 수 있다.

yarn add clean-webpack-plugin 혹은 npm install clean-webpack-plugin –dev 설치하고 webpack.config.js 파일을 아래와 같이 수정하자.

carbon (2)

지금껏 번들된 파일들은 build 폴더에 넣고 있었다. clean-webpack-plugin을 불러와 plugins 옵션에서 위와 같이 설정해주면 build 폴더를 매 build 마다 clean-webpack-plugin이 build 폴더를 먼저 비우고 html-webpack-plugin이 그 다음 index.html template에 번들 결과를 삽입하고 build 폴더에 결과물을 저장한다. 이제 build 사이클을 어느 정도 완성했다. 더이상 build 폴더를 직접 관리해주어야 하는 일이 사라지게 되었다.

이 포스트에 관련된 코드는

https://github.com/brightparagon/webpack-conquer/tree/output-management

에서 확인해볼 수 있습니다.

[webpack v4] Asset Management

들어가며

저번 글에서는 간단한 js 파일 하나를 번들링해서 index.html 파일에서 사용하도록 만들었다. 그런데 우리가 웹 애플리케이션을 만들때 JavaScript 파일만 쓰지는 않지 않은가? 스타일링을 위해 CSS 파일을 만들고, 사진을 보여주기 위해 jpg, png 등의 이미지 파일을 추가하고, 때로는 글씨체를 위해 font 파일이나 json 파일을 사용하기도 한다. 이때 사용되는 모든 종류의 파일들은 CDN과 같은 외부링크로 불러들이지 않는 이상 우리 프로젝트 디렉토리 내에 존재한다. 물론 webpack은 js 이외의 파일들도 번들링 해준다. 이 파일들을 각각 하나의 JavaScript 모듈로 만들어 js 파일과 마찬가지로 dependency graph로 관리한다. 이번 글에서는 이런 asset을 webpack으로 어떻게 관리하는지 알아보자.

CSS를 사용하는 웹을 만들어보자.

이 포스트에 관련된 코드는

https://github.com/brightparagon/webpack-conquer/tree/asset-management

에서 확인해볼 수 있습니다.

 

carbon
index.html
carbon (1)
app.js
carbon (2)
style.css

 

이전 예시와 크게 다르지 않다. app.js는 h1이 들어있는 div를 만들고 body에 붙인다. 몇가지 차이점은 파일 상단에서 style.css 파일을 불러오고 h1에 className을 ‘hello’로 정하고 있다. 그런데 app.js를 보면 css 파일을 import 하고 있다. index.html에는 css 파일을 불러오는 링크는 없는데 어떻게 h1에 css를 적용하는 걸까. 아래의 webpack config를 보자.

carbon
webpack.config.js

entry와 output은 전 예제와 변함없다. module 프로퍼티가 새로 생겼는데 이곳에서 우리가 원하는 파일들을 webpack이 불러올 수 있도록 각 파일에 맞는 loader를 지정한다. 지금 우리는 css 파일을 불러들일 것이므로 .css 확장자를 가진 파일들을 style-loader와 css-loader로 불러들이도록 설정하고 있다. 이때 webpack은 아래에서 위로 loader를 적용한다. css-loader가 먼저 css 파일을 읽어들이고 그 결과물을 style-loader가 index.html의 head 태그에 삽입한다. 그래서 만약 scss를 사용한다면 먼저 scss 파일을 css 파일로 변환해야 하기 때문에 sass-loader를 맨 아래에서 필요한 옵션과 함께 지정해주면 된다. 이제 설정 파일 준비가 끝났으니 npm run  buildyarn build 명령어를 통해 빌드하고 브라우저에서 index.html을 열어보자.

스크린샷 2018-04-08 오후 1.17.43

스크린샷 2018-04-08 오후 1.19.02

css가 적용이 된 h1이 보인다. 개발자 도구를 열어 Elements 탭을 보니 head 태그에 style 태그가 삽입되어 있는 것을 볼 수 있다. 만약 app.js에서 다른 js 파일을 불러와 사용하고 그 파일에서도 css를 사용하면 어떻게 될까? 그리고 이미지 파일은 어떻게 불러올까? json 파일이나 font는?

위에서 만든 js, css 파일들을 수정해보자.

carbon (3)
app.js
carbon (6)
style.css
carbon (4)
bar.js
carbon (5)
another.css
carbon (7)
webpack.config.js

app.js에서 새로 만든 bar.js 파일과 the1975 이미지, data.json 파일을 불러오고 있다. style.css 에서는 이미지에 적용할 center class를 추가했고 새로운 폰트 파일을 불러오고 있다. 이미지, json, font 파일은 컴퓨터에 저장되어 있는 것을 활용했다. bar.js는 app.js와 비슷하게 another라는 css 파일을 사용하고 h3 태그를 만들어 반환한다.

webpack.config.js 파일의 module에 두 부분이 추가됐다. file-loader를 사용해 이미지 파일과 각종 폰트 파일을 불러올 수 있도록 만들었다. 이외에도 csv, tsv 파일 등을 csv-loader로 불러올 수 있다. 다시 빌드해서 브라우저로 열어보자.

스크린샷 2018-04-08 오후 1.40.34스크린샷 2018-04-08 오후 1.40.43

 

the1975(아주 좋아하는 밴드..) 이미지와 bar.js의 결과가 잘 나오고 있다. 그런데 Elements 탭을 보니 head tag에 style tag가 두개가 있다. style-loader는 css 파일을 부르는 js 파일을 만날때마다 style tag를 삽입하는 것을 알 수 있다. 만약 프로젝트가 점점 커지고 css 파일도 많아지면 html 파일도 불필요하게 커지게 될 것이다. 그래서 style-loader는 production으로는 그렇게 좋은 선택은 아니다. 이때 css 파일을 개별적으로 추출하고 caching까지 할 수 있는 extract-text-webpack-plugin 이라는 좋은 플러그인이 있다. 이 웹팩 시리즈에서 이후에 production에서 이 플러그인을 사용하는 것을 다룰 것이다.

CSS Module

지금까지 style.css, another.css 이라는 두 파일을 만들었다. 그런데 만약 style.css에 있던 hello 라는 클래스의 이름이 another로 바뀌게 되면 어떻게 될까? another.css에도 another라는 클래스가 있는데 중복되지 않을까?

carbon (8)
app.js
carbon (9)
style.css

위와 같이 app.js와 style.css 파일을 변경해보고 다시 빌드해서 결과를 확인해보자.

스크린샷 2018-04-08 오후 2.21.50스크린샷 2018-04-08 오후 2.22.04

두개의 another 클래스는 다른 내용을 담고 있지만 style-loader에 의해 두개의 style 태그가 삽입되고 아래에 있는 style 태그의 another 클래스가 위의 클래스를 덮어씌우게 되어(중복된 클래스의 경우 나중에 오는 클래스가 우선순위를 갖는다) h1와 h3 둘 모두 배경색이 coral이 되었다. 프로젝트가 점점 커지면 스타일링도 여러 개발자가 하게 될 수 있고 점점 클래스 네이밍이 중요해진다. 일정한 규칙에 따라 이름을 짓기도 하고 개발자 나름의 묘책을 세워 만들 수도 있다. 그럼에도 파일이 더 복잡해질 수록 트래킹이 어려워지고 결국 중복되는 지점이 찾아오는데 이때 CSS Module을 사용하면 이 문제를 해결할 수 있다. CSS Module은 css 파일 하나하나를 개별적인 모듈로 간주하고 css-loader가 option에 주어지는 규칙에 따라 css 파일의 이름과 DOM에 들어갈 css 클래스명을 결정함을 의미한다. webpack config 파일과 app.js, bar.js 파일을 아래와 같이 수정해보자.

carbon (2)
webpack.config.js
carbon
app.js
carbon (1)
bar.js

webpack.config.js 파일에서 css-loader 설정 부분을 변경했다. modules option을 true로 하고 localIdentName option에 일정한 규칙을 주었다. 이 부분은 css-loader document를 참고하면 된다. localIdentName를 살펴보자. path는 css 파일의 디렉토리 경로, name은 css 파일의 이름, local은 css selector 이름이고 마지막 hash는 매 build 마다 파일에 변경 사항이 있을때 자동으로 변경되는 부분이다. 이 옵션으로 우리는 개발 중일때 파일별로 중복되는 css 클래스명이 있어도 우리 의도대로 스타일링을 할 수 있다. 그리고 app.js와 bar.js에서 css를 불러오고 클래스명을 적용하는 부분이 바뀐 점을 주목하자.

예를 들어, book 화면에 적용할 list class를 만들고, user 화면에 적용할 list class를 만들면 list 라는 이름이 중복되어도 개발 중일때 list-book, list-user 와 같이 불편한 작업을 하지 않아도 되어 직관적으로 스타일링을 할 수 있다. 이외에도 sass-loader(sass-loader에도 동일한 modules option을 사용할 수 있다)를 사용하거나 styled-component를 사용할 수도 있다.

이제 빌드해보고 브라우저에서 결과를 확인해보자.

스크린샷 2018-04-08 오후 3.00.30.png

localIdentName의 규칙대로 css class 이름이 만들어진 것을 확인할 수 있다.

이 포스트에 관련된 코드는

https://github.com/brightparagon/webpack-conquer/tree/asset-management

에서 확인해볼 수 있습니다.

 

나만의 길을 걷는 것

두려움

개발자로 일을 한지 이제 11개월이 되었다. 긴장감이 끊이질 않았다. 하루를 마감할때 쯤이면 다음 날과 그 주에 해야할 일을 생각해보는 버릇이 생겼다. 뭘 해야할지 정리가 안된 상태에서 일을 시작하는 것이 너무 무서웠기 때문이다. 못하면 어쩌지라는 걱정과 함께. 물론 그렇게 했음에도 예상대로 진행된 적은 단 한번도 없었다.

시간이 지나 두려움은 약간의 익숙함으로 변했고 그 안에서 미래를 고민하기 시작했다. 현재 걷고 있는 길에 대해서도 다시 고민하게 되었다. 아마 많은 직장인들도 이런 고민을 하지 않을까?

가령, 이렇게 해서는 발전이 전혀 안될 것 같은데 어떡한담..?, 지금 이렇게 하고 있는 게 맞는 걸까?, 이대로 가면 내가 원하는 방향으로 가는 걸까?, 남들은 이만큼 하고있는 것 같은데 나는 그만큼 하고 있는걸까?, 나는 왜 학습 속도가 늘지 않는걸까?, 공부는 많이 한 것 같은데 왜 삶에 변화가 없는 것 같지?, 지금 몸담고 있는 분야 말고 또 어떤 분야를 터득해야 할까?.. 등

모두 나 스스로 해본 질문들이다. 직장인으로 살았던 3년 가까운 시간동안 끊임없이 나를 괴롭힌 질문들이다. 분명 몇개월 전에 답했던 질문 같은데 어느새 또 질문을 되뇌이고 있는 나를 종종 발견한다. 질문의 수만큼 두려움을 느꼈다. 왜 또 떠오르는 질문은 그렇게 많은지. 그간 수많은 질문을 스스로에게 던지고 답하면서, 답하기 위해 책과 신문을 읽고 글을 쓰면서 다행히 두려움과 불안감을 많은 부분 해소했다. 어느 정도 해답을 찾은 것 같아 그간의 고군분투를 정리해보고자 한다.

좋은 질문을 해야 좋은 답을 얻는다

누구도 가지 않은 길, 사람들이 잘 가지 않는 길 혹은 대부분의 사람들이 가는 길 중 어느 것을 선택해야 할까? 이 문장을 잘 뜯어보면 내 길을 정하는 데 있어 기준은 내 안이 아닌 남들이 어떤 길을 가느냐에 있다. 다시 말해, 이 문장에 답을 하게되면 필연적으로 그 대답은 타율성을 띄게 된다. 내 길을 선택함에 있어 다른 사람들의 행동을 살피고 있기 때문이다. 그래서 결론적으로는 내 길을 선택하는데 있어 이 질문은 큰 도움을 주지 못한다. 그런 의미에서 좋은 질문은 아니다.

본질적으로 중요한 것은 내가 누군지 이해하고, 내 마음을 따라 정말 하고자 하는, 온전히 열정과 에너지와 시간을 쏟을 수 있는, 큰 보상이 없어도 그걸 하는 것만으로도 좋은, 동시에 생계는 해결해줄 수 있는 길을 찾는 것 그리고 그 길을 묵묵히 걷는 것이지 않을까. 어떤 길을 선택하고 그 길을 걷는 이유를 내 안에서 찾는 것이기 때문이다. 그래서 질문을 바꿔야 한다.

  • 나는 어떤 사람일까?
  • 평생 어떤 일을 하면 아무 후회가 없을까?
  • 나는 무엇에 열정이 있을까?
  • 지금 갖고 있는 관점으로 별로라고 판단했던 많은 것들 중에 다른 관점으로 보면 완전히 다른 판단을 내릴 만한 것들이 있을텐데 그것들은 무엇일까?
  • 나는 나의 취향과 편향에 따라 지금껏 내린 가치판단들을 얼마나 신뢰할 수 있을까?

나 자신에 대해 알게 해주는 질문을 많이 던지면 던질 수록 미궁에 빠질 것 같지만 놀랍게도 생각이 훨씬 더 분명해진다. 질문에 하나씩 답하다보면 어느 질문에 답하기 위해서는 다른 질문에 대한 답을 선행해야만 하는 경우가 있다. 그런 것들을 그림으로 그리는 방법 등을 통해 질문들을 연결하고, 얻은 대답들을 모아놓고 구조를 살펴보면 더 전체적인 ‘나’가 보인다.

나만의 보폭

어느 길을 걸을지 정한 뒤 조금 걷다보면 분명히 나아가는 속도에 대해 생각을 하기 시작할 것이다. 그럼 또 아래와 같은 질문 다발을 맞이하게 된다.

  • 모르는게 너무 많은 것 같은데 왜 이 모양이지..?
  • 나는 학습이 좀 느린 것은 아닐까?
  • 이 속도로 가는 건 남들에 비해 좀 느린 건 아닌가?
  • 기반 지식을 넓히면 속도를 개선할 수 있는가? 관련된 책이 있을까?

어떤 질문은 자신을 외부와 비교해보게 하고 어떤 질문은 나에 대해 더 깊이 알아보도록 주문한다. 이 경우에도 앞선 문단과 맥락을 같이 한다. 외부와의 비교를 할때는 참고 수준에서 답을 내리고 나에 대해 이해하도록 만드는 질문을 많이 해야한다. 특히 학습의 속도에 대해 고민할때 남과의 비교는 자신이 최고 반열에 들지 않는 이상 나는 ‘어쨌든 느린’ 사람이 되어버리기 때문에 백해무익하다. 따라서 ‘저 정도 수준의 사람은 저 속도로 나아가니 나는 이 정도면 적당하겠구나’ 식의 참고까지가 좋을 것이다.

조승연의 ‘공부 기술’, Henry Roediger의 ‘어떻게 공부할 것인가’, 이준영의 ‘구글은 SKY를 모른다’, 학습과 교수법에 관한 희대의 역작인 Ken Bain의 ‘What best college students do’, Angela Duckworth의 ‘GRIT’, Anders Ericsson의 ‘1만 시간의 재발견’ 등 여태 읽은 학습에 관련된 책들을 종합해보면 인간의 학습에는 심적 구조물이 활용된다. 실제로 Anders Ericsson은 그의 저서에서 이를 두고 심적 표상이라는 단어로 표현했는데 가령 이런 것이다.

img_0037
이런 심적 구조물을 3차원으로 머릿속에서 그리거나 이미지와 연결지을 수도 있다. 심지어 이 그룹들에 색을 입혀 기억을 도울 수도 있다. 그림은 아이패드로 그렸다.

단어를 기억하는 방법은 여러가지가 있을 수 있다. 단순히 단어별 의미를 기억하는 방법, 단어가 가진 패턴을 분리해 새로운 단어를 패턴 그룹에 묶어서 기억하는 방법, 주제 및 상황 별로 묶어서 기억하는 방법 등 다양하다. 머릿속에 그림을 그려 구조를 만들고 그 안에서 단어들을 이리저리 옮기는 식의 방법이라면 심적 구조물을 활용하고 있는 것이다. 마음에 그림을 그리니까 말이다. 이때 중요한 것은 ‘외국어 잘하기’라는 목표아래 세부 목표로 단어를 많이 익히기로 했다면 더 좋은 심적 구조물을 갖고 있을 수록 더 빠르고 더 정확히 목표를 이룰 수 있다.

그런데 문제는 사람마다 갖고 있는 심적 구조물이 서로 다르고, 가진 갯수도 다르며 각각의 질 또한 다르다는 것이다. 영어 뿐만이 아니라 모든 종류의 학습에서 심적 구조물이 활용된다. 수학, 스포츠, 의학, 과학, 예술, 컴퓨터 공학 등 인간이 하는 모든 종류에 적용된다. 위상 수학에서 새로운 모델을 생각할때, 방사선과 의사들이 엑스선 사진 판독을 할때, 음악가가 선율을 머릿속에서 그릴때, 심지어 연주할때, 엔지니어가 딥러닝 모델 구조를 생각할때 등을 예로 들 수 있다.

학습의 속도가 걱정이 된다면 문제를 바라볼때 활용하는 내가 가진 심적 구조물을 생각해야 한다. 속도에 영향을 미치는 거의 유일한 변수이기 때문이다(여기서 지능은 의미가 없다. 지능이 낮아서 심적 구조물을 많이 생각해내지 못할 것 같은 걱정이 든다면 1만 시간의 재발견을 꼭 읽을 것을 권한다.). 따라서 내 생각의 방식의 구조와 틈새 그리고 한계를 면밀히 살펴보는 것이 우선이며 그 뒤에 한 단계씩 나아가야 한다. 아마 이렇게 걷는 것부터 ‘나만의 보폭’으로 걷고 있다고 말할 수 있을 것이다. 이런 점에서 남보다 늦고 빠르고 또한 별 의미가 없다. 이러한 보폭을 생각하는 일의 궁극적인 목표는 위 문단에서 얻은 나만의 길을 오래도록 걷는 것이기 때문이다. 남보다 더 잘 나가고 빠른 것을 원한다면 이 글은 소용이 없을 것이다.

개발자로서의 나는

글 전체의 흐름은 이어지지만 문단 별로 어느 정도 독립적인 내용을 담고 있으니 건너 뛰면서 읽으셔도 좋습니다.

Angular로 시작해 지금은 React 위주의 개발을 해오고 있다. 아주 많은 사람들이 이 분야에서 일하고 있기 때문에 이게 나만의 길이라고 말하기는 어렵다. 다양한 배경과 동기에 의해 이 분야를 택했을 것이고 나도 그들 중 하나다. 이 분야에서 왜 일을 하고 있는지, 나에 대한 이해와 개발자로 일하는 것이 서로 어떤 관련이 있는지 묻는다면

  1. 하다보니 너무 재미있고
  2. 재밌어서 더 하다보니 프로그램 자체가 아름다워서 신기하고
  3. 이걸로 해결할 수 있는 사회, 환경, 문화적 문제들이 많다는 걸 깨달았고
  4. 나 혼자만 잘 사는 것에 관심이 없기 때문에 더 멋지고 나은 세상을 만드는데 활용하고 싶고
  5. 가장 큰 관심사 중 하나인 교육 문제에 큰 영향력을 미칠 수 있다는 것을 깨달았기

때문이라고 현재까지는 이렇게 답할 수 있을 것 같다. 가장 근본적인 이유를 오랫동안 생각해온 것이기 때문에 아마 거의 변하지 않을 거라고 생각한다.

개인적으로는 이런 이유에서 이 일을 하고 있다. 단순히 돈을 벌고 커리어를 만들어나가는 관점도 있겠지만 그것만으로는 부족했기 때문에 근본적인 이유를 찾아 헤매온 것이다. 그럼 이대로 나아가면 될 것인가?, 이것만 계속 할 것인가? 라는 질문을 해볼 수 있는데 선뜻 그렇다고 대답하기는 어렵다. 당분간은 맞겠지만 10년, 20년을 생각해보면 그림이 잘 그려지지 않는다.

다행히 최근 우연히 머신러닝 분야가 위의 다섯가지 이유와 완전히 맞아떨어진다고 생각하게 되었고 이쪽 공부를 계속 해오고 있다. Tensorflow나 Keras 같이 ML/DL 모델을 빠르게 프로토타이핑 할 수 있는 걸출한 오픈소스들이 이미 엄청난 인기를 누리고 있고 이에 따라 굳이 이 분야를 병행하기 위해 반드시 대학원 진학을 해야만 하는 것은 아니기 때문에 계속 해나갈 수 있는 분야라고 판단했다. 앞으로는 블로그에 개발 외에도 모델링이나 수학에 관련된 글들도 많이 올려야할 것 같다. 개발 글도 거의 못쓰고 있는 형국이지만.. 먼산..

나의 이런 판단을 듣고 ‘굳이 프론트와 머신러닝을..?’ 이라는 반응이 더러 있었다. 의기소침할 뻔 했으나 생각해보면 또 안될 이유는 없지 않은가? 그래서 요새 페이스북에서 Sung Kim 교수님과 조대협님의 글들을 보면서 많은 용기를 얻고 있다(감사합니다!).

능숙해지기

아직은 개발과 공부에 엄청난 몰입을 하고 있는 것 같지는 않다. 위에서 나를 이해하네 어쩌네 했어도 남과의 비교에서 완전히 자유롭지는 못하…다. 인간이란.. 근래에 탁월함에 관한 어떤 글에서 Kobe Bryant는 자는 시간 6시간을 제외한 거의 모든 시간을 농구를 위해 사용했고, 월마트의 창업자인 Samuel Walton은 억만장자가 되어서도 항상 같은 태도를 유지했다는 내용을 보았다. 그럼 나는 그렇게 할 수 없는가? 라는 질문이 떠올랐다.

그들은 어떤 동기가 있었기에, 어떻게 동기를 계속 유지했기에 그렇게 엄청난 몰입을 했을까? 나는 하루에 자고 일하는 시간을 제외하고 거의 모든 시간을 개발과 공부에 쏟을 수 있을까? 나는 그들처럼 몰입할 수 있는 내적 동기를 갖추었는가? 내적 동기는 먼저 나를 이해해야 찾을 수 있는 것인가? 그럼 찾기만 한다면 그 뒤로는 실행과 correction만 남는 것일까? 그들은 그들의 분야에서 어디까지 가고 싶은 걸까? 아마 가고자 하는 목표에 따라 동기를 부여받는 방식과 빈도가 달라지지 않을까?

자신의 분야에 매우 능숙해지고 싶은 사람이 아주 많을 것이다. 잘하게 되면 얻을 수 있는 보상들이 많기 때문이다. 나는 왜 능숙해지고자 하는지 생각하기 전에 보상에는 어떤 것들이 있는지 생각해보자. 누군가는 자신의 꿈을 더 분명히 이뤄줄 길을 더 잘 보게될 것이고, 누군가는 더 많은 돈, 누군가는 사회적 인지도, 누군가는 기술과 지식 자체를 깊이 이해하고 갖고 노는 것에서 오는 희열감 자체를 원할 수 있다.

책, 페이스북, 링크드인 그리고 주위에서 유명하거나 아주 실력있는, 가히 괴물이라 부를 수 있을만한 사람들을 계속 보다보니 위에서 언급한 내적 동기와 보상은 능숙함의 정도와 무관하지 않음을 알게되었다. 그리는 꿈이 선명할 수록, 원하는 것과 이루고자 하는 것이 분명할 수록 더 많은 집중을 하게 될 거고 더 많은 시간과 에너지를 투자할 여지가 크다. 그것은 자연스레 능숙함의 향상으로 이어질 것이다. 무언가에 매우 능숙해지고자 한다면 내적 동기를 찾고 원하는 보상의 형태를 생각하고 그 이미지를 더 선명하게 만들어 보는 것이 도움이 되지 않을까 생각한다.

능숙해질 수 있는 대상은 참 많다. 내가 하고 있는 일, 타인과의 소통과 협업, 대인관계, 가정 꾸리기 등등. 그리고 놀랍게도 이 관계없어 보이는 것들 또한 서로 관련이 있다. 사랑하는 사람과의 관계는 분명 오늘 집중하는 일에 큰 영향을 미친다. 가정을 이루고 안정감과 행복을 느끼고 싶은 마음이 강하다면 가정을 이루는데에 관심이 가기 마련일 것이다. 또 자신이 대인관계와 다양한 분야의 타인과 소통하는 것에서 어려움을 느낀다면 그것 또한 커리어에 있어서의 능숙함에 영향을 미칠 것이다. 거대하거나 복잡한 서비스의 아키텍쳐를 설계하는 사람, 섬세한 미술 작품을 만드는 사람, 복잡한 의술을 행하는 의사, 연주할 모든 곡들의 흐름과 선율을 머릿속에서 끊임없이 그려가며 연주에 몰두하는 피아니스트와 같이 장인이라 부를 수 있는 대부분의 사람들 중에서도 롱런하는 사람들의 공통적인 특징은 위의 능숙해질 수 있는 네다섯가지의 영역 거의 모두 다에서 능숙하다는 점이다. 이 점을 절대 간과할 수 없다. 한번 반짝이고 사라진 장인들은 저 영역 중 한두가지가 아주 부족했다. 대인관계에 아주 서툴다던지, 다른 분야의 사람들과 소통이 잘 안된다던지 등이 이런 경우에 속한다. 이 소통에 관련된 부분은 전에 쓴 이 글에서도 다룬 적이 있다.

따라서 이런 생각을 해볼 수 있다. 아직 또래보다 기술적인 것에서 한참 뒤쳐져 있다고 생각이 든다면 내가 다른 이보다 좀 더 능숙한 영역에서의 장점을 적극 활용해보고, 이런 사고를 바탕으로 꾸준히 성장할 수 있는 장기적인 계획을 꾀할 수 있다. 예를 들어, 기술적 능숙함은 부족하지만 대인관계 및 네트워킹에서 능숙하고, 지식에 대한 호기심이 남달라 습득 속도가 빠르다면 기술 커뮤니티, 컨퍼런스 등에 적극 참여해 그 사람들과 교류하며 모르던 것을 배우고 함께 공부하거나 혼자 공부할때 조언을 얻을 수 있다. ‘능숙해지기’에 대해서 이와 같은 관점으로 살펴본다면 남과의 비교와 사회적 압박에서 자유로운, 좀 더 안정적인 마음으로 성장 계획을 세우고 나아갈 수 있다.

이에 관련해 Tai Lopez라는 기업가의 블로그에서 도움이 되는 몇가지 팁을 찾았다.

  • Mentor: 선망하는 누군가를 찾고 직접 연락해보라. 할 수 있다면 그와 교류하고 조언도 구해보라. 배우고자 찾아온 사람을 매정하게 내칠 사람은 많지 않다.
  • Read more: 좋은 책은 여러번 읽는다. 1회독 때는 정독하고 2회독 때는 1회독때 표시해두었던 주요 포인트만 읽으며 속독하고 3회독 때는 본인에게 제일 중요한 몇 부분만 읽는다. 대부분의 책은 일부분만 읽어도 될 정도의 가치를 갖는다. 따라서 엄청난 양의 책을 비교적 적은 시간을 들여 읽는다. 양이 쌓이고 정리가 되어가면 전체적으로 볼 수 있는 능력이 매우 향상될 것이고 그 뒤부터 더 현명하고 가치있는 결정을 내릴 수 있을 것이다.
  • Be humble: 자만, 오만하지 않는다는 것은 인생, 세계, 사물, 사람에 대해 쉽게 판단을 내리지 않는다는 것이고 이는 바꿔말하면 겸손하면서도 호기심이 있는 것이다. 그런 사람만이 오래 학습하고 오래 성장하여 인간 지식의 미개척 영역을 한톨 넓히는 사람이 된다. 내 의견이 아니라 역사가 그렇다. (낮은 자세를 취하는 것은 도덕이 아니라 이쯤 되면 과학인듯)
  • Persevere: Bill Gates도 스무살부터 서른살까지 거의 쉬지 않았다. 그만큼 집중할 것이 뚜렷했다는 것이고 그렇게 할 수 있으려면 인내해야 한다. 될때까지. 나(Lopez)는 내가 선망하는 기업가의 비서를 17번 찾아갔다.
  • Stoic: 정말 재밌는 미래를 꿈꾼다면 그걸 위해 준비하고 조금만 참자. 오늘의 즐거움을 살짝 양보하고 스스로를 단련한다. 뭐 그렇다고 즐거움을 다 버리라는 것은 아니다. 다만 현재를 희생하면서까지 즐겨버리면 그만큼 성장해있을 미래는 없다. 성장에 관심이 없고 이대로만 행복하게 살고싶다면 현재를 마음껏 즐기자.

나를 믿는 것

그리고 나만의 생각을 키워나가는 것.

나만의 생각을 키워나가는 것은 답이 정해진 문제를 해결하는 나만의 방식일 수도 있고, 비구조적 문제를 이해하고 해결하는 나만의 방식일 수도 있고, 남들은 생각하지 못하거나 전통적인 생각의 방식에서 벗어나 비록 그것이 기존의 것과 충돌하더라도 나만의 방식으로 접근하는 것일 수도 있다. 남들이 절대 아니라고 해도 내가 확고하게 믿는 것이 있으려면, 그걸 갖고 강하게 밀고 나갈 수 있으려면 이러한 나만의 생각이 잘 진전되어 있어야 한다.

앞서 프론트 영역에서 개발을 시작해 머신러닝으로 영역을 넓혀간다고 했을때 ‘왜 굳이’라는 반응을 들었다고 소개했다. 만약 내가 그리는 미래가 분명치 않았다면, 내가 한번 주어진 인생에 무얼 하다 갈지, 어떤 사람으로 기억될지 구체적으로 상상해보고 정해놓지 않았다면 나는 분명히 흔들렸을 것이다. 왜? 남들의 기준, 사회의 일반적인 기준에 따르면 내가 가고자 하는 길은 전도유망하지 않기 때문이다. 그들의 관점으로는 머신러닝을 처음 시작했으면 했지 굳이 프론트로 이미 시간을 보낸 뒤 진입하는 것은 그리 큰 메리트가 없었을 것이다. 동의하지 않는 것은 아니다.

나는 다행히 여기서 나를 믿고 나만의 생각을 키워온 것에서 큰 힘과 방향을 얻었다. 어쩌면 이것은 인생을 대하는 나의 태도일지도 모른다. 그리고 나는 이 태도를 얻으려 부지런히 노력했다. 얻기까지 너무 힘들었고 좌절했던 적도 많았다. 그래서 그 얻은 힘과 방향이 무엇인고 하니, 머신러닝은 모델링 및 학습보다 데이터 전처리 및 가공에 더 많은 힘을 쏟아야 하는 성질의 분야이고, 내가 시작한 분야인 프론트 영역에서는 무엇을 데이터로 간주하고, 언제 어떻게 저장하고 가져올지 생각해볼 수 있는 곳이기 때문에 둘 간의 연결지점을 분명히 생각해볼 수 있었다. 자연스레 학습할 분야도 데이터와 관련된 분야로 옮아갔고 나는 미래를 더 분명히 그려볼 수 있는 기회를 갖게 되었다.

몇달전 읽은 Airbnb 스토리라는 책에 이런 내용이 있다. ‘이렇다, 저렇다 식의 남 얘기에 집중하지 마라. 나만의 생각을 키우는 것이 중요하다.’ Warren Buffett이 한 말이다. 그는 출근하고 대부분의 시간을 독서하는데 사용했다고 한다. 분명 사회에는 노이즈가 많다. 듣기 싫은 것도 있고 뭐만 하려고 하면 안된다고 초를 치는, 하등 도움이 안되는 말들도 많다. 그래서 흔들리지 않고 내 길을 올곧게 오래 나아가기 위해서는 남의 이야기에 경청할 줄도 알아야 하지만 반대로 듣지 않아야 할때도 있음을 깨달았다. 둘이 상충하는 것 같지만 자동차의 기어에 D와 R이 공존하는 것과 같은 이치다. 경청과 무시. 둘 중 아무래도 그간 사회가 이야기해온 것에 따르면 경청이 더 좋은 자세 같다. 경청만 해야할 것 같다. 그렇다고 차에 D만 있으면 막다른 길에서 빠져나올 길이 없을 것이다. 앞만 보고 달리는 것만큼 바보같은 것이 또 없다.

뭔가 하고싶은데 남이, 사회가 그걸 두고 별로라고 하는가? 본인이 봐도 별로라고 생각이 들면 안하는게 맞지만, 분명히 좋다고 생각한다면 기쁘게 남을 무시하자. 한국 사회는 지나치게 남에게 관심이 많다. 예의있게 무시하고 오래 성장하고 전진해서 멋지게 살자.

정리하며

이제 막 커리어를 계획하고 다듬어나가는 입장에서 보면 앞날이 까마득하고 배울 것은 왜이리 많은지 답답하기만 하다. 이걸 다 언제하지 라는 조바심도 나고 이렇게 해서 정말 내가 원하는 레벨의 엔지니어가 될 수 있을지도 의심스럽다.

이럴때 상상력을 적극 활용해보자. 영화를 보다보면 온갖 일을 겪고 은퇴해 노년기를 보내며 지난 날을 회상하는 장면이 간혹 나온다. 이런 장면들을 보면서 이런 생각이 들었다. 지금 아무리 치열하고 앞이 안보이고 어쩌고 해도 삶의 끝에 가면 결국 남는 것은 돈도 명예도 아닌 곁에 있는 사랑하는 사람들이다. 그렇지 않은가? 치열하게 살아온 젊은 나날들이 무의미하다는 것이 아니라 중요하고 어려워 보이는 모든 것들도 끝에 가서는 아련함, 시원섭섭함, 아름다움, 그리움으로 남는다는 것이다.

아마 사람들이 꿈을 갖고, 무언가를 만들고, 고군분투하는 모든 것의 존재 이유는 진행하는 당시에는 모르겠지만 그저 그것이 재밌어서일 것이다. 그리고 그것이 아름다워서일 것이다. 편리, 재미, 환경을 위한 모든 일과 사업들. 당시엔 사명감, 욕심 등 여러 이유를 갖고 그것에 따라 생각하고 무언가를 해나가겠지만 끝에가서 남는 것은 추상적 감정들일 것이다. 그러니 지금 하는 것이 어렵고 힘들고 앞이 보이지 않아도 풀어나갈 한가지의 실마리만 있다면 그걸 쥐고 하나씩 알아나가는 과정들을 기꺼이 받아들이고 즐기면 되지 않을까.

이 글을 쓰기까지 도움이 된 책들, 써온 글조각들, 만들어온 것들, 공부한 흔적들

img_4114

img_4134
1만 시간의 재발견: 2018년에 읽은 최고의 책(아직까지는)

img_4136

img_4118
Surely You’re Joking, Mr. Feynman!: 학습에 대해 유쾌하게 풀어내는 파인만의 재밌는 사연들이 감명 깊었다. 리처드 파인만은 정말 사랑스러운 과학자다.
img_4140
이 글의 바탕이 되는 첫 의식의 흐름
img_4054
심적 표상에 대한 정리
img_4141
이글과 연관이 있는 그간 써온 학습에 관련된 글조각들: 이 조각들은 이 글을 구성하는데 쓰였다.
스크린샷 2018-03-11 오후 5.39.34
입사하고 참여한 프로젝트의 결과물(React.js): dcode 앱의 웹 버전인 itsdcode
스크린샷 2018-03-11 오후 5.37.54
ML 분야의 hello world: tensorflow로 mnist 학습시키기

img_4138img_4139img_4137

KakaoTalk_2017-12-31-16-28-51_Photo_6
작년에 들었던 Coursera Stanford Machine Learning Course

KakaoTalk_2017-12-31-13-58-06_Photo_38

[webpack v4] webpack v4 시작하기

들어가며

2016년 초반 즈음 react에 입문해 개발을 시작하게 되었다. 웬걸, react를 하려고 봤더니 이것만으로는 웹을 만들기가 번거로워 여러(꽤 많은…) 도구들이 거의 필수적으로 사용해야 함을 알게되었다. redux도 redux지만 그중에서도 오랜 시간에 걸쳐 머리를 지속적으로 아프게 했던 것은 단연 webpack이다. 처음 사용했을때 버전이 1이었는데 해가 바뀌기가 무섭게 메이저 버전이 2로 뛰더니 여러 부분에서 사용 방식이나 문법 등이 바뀌어서 잊을만하면 재학습을 요구했다.

그래서 쓴다. 나를 위한 webpack v4 정리 시리즈. 이제와 생각해보니 redux도, redux-saga도 참 어려웠지만 유독 webpack이 골치아팠던 이유는 특히 UI Library인 react를 사용함으로써 개발 과정에서 필요한 UI 이외의 많은 부분들을 webpack이 커버하기 때문이었다. 프레임워크를 생각해보면 이해가 쉽다. 프레임워크가 제공하던 인터페이스가 없으므로 예를 들어 MVC에서 V만 지원되는 상태에서 다른 라이브러리들로 MC를 구성하고 이것을 V와 함께 일관된 패러다임 하에 서로 꿰매고 컨트롤해야 한다. 다시 말해, webpack은 개발 사이클의 전반적인 부분에 관여하기 때문에 웹 개발의 큰 구조를 어느정도 이해하고 있지 않은 경우엔 쉽고 직관적으로 활용하기가 어렵다. 갈 수록 더 많은 option과 보조하는 plugin들이 많아지는 것은 react의 활약을 포함한 Modern Web Development의 흐름 변화와 무관하지 않다.

이런 배경에서 webpack 활용에 대해 아주 기초적인 것부터 복잡한 것까지 천천히 그리고 아주 자세히 정리해보고자 한다. 버전이 또 바뀌어 사용법이나 문법이 바뀌더라도 정리한 것을 바탕으로 내 머리를 업데이트하면 되므로 이 시리즈를 webpack 활용에 대한 형상관리라고 해두면 되겠다.

아주 간단한 웹을 bundle 해보자

이 포스트에 관련된 코드는

https://github.com/brightparagon/webpack-conquer/tree/getting-started

에서 확인해볼 수 있습니다. 작은 예제부터 모두 실행해보며 학습해보고 싶으신 분은 위 링크에서 레파지토리를 fork 하거나 zip 파일을 다운로드해서 활용해보세요.

시작하기 전에 준비물이 몇가지 있다.

  • 코드를 작성할 적절한 에디터 like Sublime Text, Atom, VS Code
  • 외부 모듈을 설치하고 관리해줄 npm 또는 yarn

이제 간단한 웹을 구성해보자.

carbon
앞으로 계속 고생해줄 우리의 index.html
carbon (2)
indext.html에서 불러와 사용할 app.js

app.js를 번들해 index.html에서 사용할 것이다. 이때 app.js 말고도 다른 파일들도 함께 번들될 수 있고 이렇게 번들된 결과를 지금은 bundle.js라고 부르자. 그래서 index.html에서 app.js 대신 bundle.js를 불러오고 있다.

app.js에서는 h1 tag를 만들어 body에 붙이고 있다. 이 간단한 웹을 앞으로 점점 커져갈 우리의 프로젝트라고 생각하자.

이제 이것을 번들 해볼건데 이때 번들되는 대상은 우리의 web application을 동작하게 해줄 요소들이다. 이 요소들에는 js, css, image 등이 있다. 여기서 js 파일이 확장되면 react나 vue로 만들어진 앱도 webpack으로 번들될 수 있다.

이제 번들하기 위해 webpack을 설치해보자.

carbon (4)

webpack을 설치할때 -g 옵션 등을 주어 글로벌로 설치하는 것보다 프로젝트 내부에 설치하는 것을 권장한다. webpack의 버전, 나아가 프로젝트 dependencies의 버전들이 서로 의존적일 수 있기 때문이다. 더불어 이렇게 하는 것이 다른 개발자나 다른 팀이 프로젝트 셋업을 빠르게 하는데 수월하다.

carbon (5)
package.json

webpack을 글로벌로 설치하지 않았다면 터미널에서 webpack 명령어를 사용할 수 없다. 따라서 package.json의 scripts에 위와 같이 입력해 npm run build 혹은 yarn build로 webpack 명령어를 사용할 수 있도록 하자. 이때 webpack 명령어를 실행할 수 있는 것은 node_modules에 있는 webpack을 npm이 찾아주기 때문이다.

그 다음 webpack이 무엇을 어떻게 번들할 것인지에 대해 정해줄 수 있는 설정 파일을 작성해보자.

carbon (6)
webpack.config.js

당장 지금은 9줄로 아주 간단하다. webpack으로 할 수 있는 것이 아주 다양한 만큼 이 파일은 앞으로 더 복잡해질 것이니 지금부터 기초를 단단히 잡아두자.

이 파일에서는 객체 하나를 내보내고 있다. 이를 webpack이 읽어 사용할 것이다. 객체 안의 속성을 하나씩 살펴보자. 먼저 4번째 줄의 entry는 webpack이 번들을 진행할 첫 진입 파일을 명시한다. webpack은 진입 파일을 시작점으로 이 파일과과 import 혹은 require로 연결된 모든 파일들 간의 관계를 dependency graph로 만들어 이것을 기준으로 번들링을 진행한다. 따라서 만약 app.js 에서 const bar = require(‘./bar.js’)와 같이 다른 파일을 불러들이면 이를 의존 관계로 보고 bar.js까지 번들 결과에 포함시킨다. 그럼 당연히 여러 파일을 작성하더라도 index.html에서 여러 script tag로 그 파일들을 일일이 불러주지 않아도 된다. 그 다음, 5번째 줄의 output은 번들링 결과를 저장할 경로(path)와 파일 이름(filename)을 결정하고 있다. 즉, entry에서 명시된 진입 파일을 기준으로 모든 파일을 하나로 묶고 이름을 bundle.js로 지어 path에 명시된 경로로 저장하게 된다.

이때 entry와 output path에서 Node.js의 path 내장 모듈(webpack은 Node.js 환경 위에서 움직인다)을 사용해 path.resolve(__dirname, …)와 같이 경로를 지정하고 있는데 여기에 대해서는 다른 글에서 다뤄보도록 하겠다. __dirname은 현재 프로젝트의 경로를 의미한다. 현재 경로가 /Users/brightparagon/Documents/workspace/webpack-conquer라면 entry의 결과는 /Users/brightparagon/Documents/workspace/webpack-conquer/src/app.js가 되고 output path의 결과는 /Users/brightparagon/Documents/workspace/webpack-conquer/build가 된다. 이제 번들을 해볼 차례다. 아래 명령어를 실행해보자.

carbon (7).png

build 폴더 내부를 보면 bundle.js이 생성되어 있을 것이다. 아래는 현재 프로젝트의 디렉토리 구조다.

스크린샷 2018-02-22 오후 11.21.54
디렉토리 구조

index.html이 build 폴더 내에 있고 webpack에 의해 생긴 bundle.js가 함께 있다. 이렇게 우리의 첫번째 번들링 과정이 완성되었다. 이제 브라우저를 열고 index.html을 열어보자.

스크린샷 2018-02-22 오후 11.25.37.png

정상적으로 동작하는 것을 확인할 수 있다!

웹에서의 module과 webpack의 역할

위의 예제를 이어서 생각해보자. 지금은 app.js 파일 하나만 있고 이 파일 마저도 코드의 양이 많지 않다. 그런데 이제 로그인 기능을 붙이고, 홈페이지에서 사진을 보여주고, 네비게이션을 붙여 여러 페이지로 이동시키는 등 필요한 기능이 늘어감에 따라 한 js 파일에서 다루는 코드의 양이 점점 늘어날 것이다.

여러 기능을 한 파일에서 다루면 기능 추가나 수정이 필요할때 쉽게 접근하기 어렵다. 그래서 기능별로 파일을 나눌 필요가 생기고 어느 파일이 어느 파일을 불러 사용하는 등의 의존 관계가 생기게 된다. C++이나 Java에 익숙하다면 JavaScript에 모듈 시스템이 따로 없는 것을 받아들이기 힘들 것이다. 필자는 처음 JavaScript를 접하고 공부할때 require()가 언어가 자체적으로 지원하는 함수인줄 알았는데 브라우저에서는 지원되지 않는 것을 알고 문화컬쳐에 빠졌다.. 이에 JavaScript를 범용적 언어로서 활용하기 위한 움직임이 일었고 표준화 작업에 있어 CommonJS와 AMD가 이끌어가고 있다. Node.js도 이런 움직임에 영향을 받았다. 더 자세한 것은 14만번 정도 조회된 스택오버플로 링크에서 찾아보자.

이것이 어떤 의미인지 알아보기 위해 위 예제에서 src 폴더에 아래와 같이 bar.js를 만들고 app.js에서 불러오는 코드를 만들어보자.

carbon (8)
app.js와 bar.js

이번엔 webpack을 활용하지 않고 index.html에서 script 태그의 src 속성 값을 “../src/app.js”로 수정하고 브라우저로 다시 열어보자.

스크린샷 2018-02-23 오전 12.02.56.png

개발자 도구를 열어 Console 탭을 확인해보면 이와 비슷한 에러를 볼 수 있다. 저 Unexpected identifier는 import from 구문을 의미한다. 만약 require를 사용했다면 require is not defined와 같은 에러를 뱉는다. 그렇다. 브라우저엔 정말 당연히 있을 것 같은 모듈 시스템이 없다.

Modern Web Development의 많은 비중을 JavaScript가 잠식해가고 있는 만큼 webpack이 건네는 도움의 손길은 더욱 크게 느껴진다. 부족한 모듈 시스템을 브라우저가 알아듣게끔 대신 설명해주고, 동시에 개발자인 우리에게는 모듈 시스템을 이용해 손쉽게 파일들을 모듈화할 수 있도록 도와준다. 벌써 v4의 베타 버전이 올라왔고 더 많은 개선 사항이 포함되어 있다. webpack은 모듈화 말고도 훨씬 더 멋진 기능들을 갖고 있다. 가령,  bundle.js가 너무 비대해지면 이것을 쪼개 parallel로 불러오게끔 만들어 초기 로딩 속도를 개선시킬 수도 있고, 심지어 SPA의 경우엔 라우팅 경로를 구분해 처음엔 필요한 번들만 불러오고 경로에 따라 알맞은 파일만 그때그때 불러와 앱을 가볍게 느껴주게 할 수도 있다. 또, 개발 과정을 단순화하고 코드 변경에 따른 앱 리로딩을 자동으로 해주며 Progressive Web Apps를 지원하는 플러그인을 사용할 수도 있다. 걸작이다. 근데 이 모든 것을 사용하려면 많이, 아주 많이 복잡하다. 그래서 요새 많이 parcel로 넘어가는 듯 하지만.. 필자는 webpack이 더 프로덕트 친화적이라 생각해 webpack에 잔류할 생각이다.. 앞으로 연재할 webpack 포스트들에서 이런 멋진 기능들을 예제로 직접 만들어보면서 사용해보도록 하자.

이 포스트에 관련된 코드는

https://github.com/brightparagon/webpack-conquer/tree/getting-started

에서 확인해볼 수 있습니다. 작은 예제부터 모두 실행해보며 학습해보고 싶으신 분은 위 링크에서 레파지토리를 fork 하거나 zip 파일을 다운로드해서 활용해보세요.