내가 4년동안 혼자 SNS를 만든방법

Lee young-jun
38 min readNov 30, 2023

--

저자는 기존의 Facebook나 Youtube를 대체할 만한 크레이터를 위한 Platform을 만들기로 결심했다.

당시 그는 총 경력 6년의 .NET 서버, WPF Client 경험이 전부였다.

생각한 것을 만들려면 웹사이트도 만들어야 하는데 경험도 없었고 야근까지 하는 마당에 불가능한 일 처럼 보였다.

하지만 일단 시작한다 2018년 1월 1일에

2018년: 계획 세우기

결코 쉽지 않은 일이 될거라고 스스로 다짐했다.

앞으로 취미와 놀거리도 포기하고 휴가나 여행 중에도 계속 작업해야 할 것이다...

생각은 쉬웠지만 리소스가 부족했다. 그러나 웹 사이트를 만드는 동안 막힐 때 Stack Overflow에 물어보지 않기로 결심했다.

이유는 간단하다 물어봐서 문제를 해결했다면 나는 어떤 경험도 얻지 못할 것이기 때문이었다.

하지만 그것은 너무 가혹한 일이기에 이미 답이 있는 것은 참고하기로 했다.

설계는 OOAD를 따르기로 했다. 각 요소가 어떻게 되어야 하는지 상호간에 어떻게 작용하고 어떤 규칙들을 뽑아내야 하는지 알기 위해서다.

Note

노트에 그려보고 나서 앞으로 집중해야할 사항을 알게 되었고 그것들을 하기 위해서는 시간 관리 계획부터 해야했다.

설계

여러 Platform을 다 대응하려면 역시 웹사이트로 만들어야한다고 생각했다.

디자인은 이미 많이 사용되는 레퍼런스 중에 내 시간을 최대한 활용할 수 있게 할 만한 것을 참고하기로 했다.

Apple에서 영감을 얻고 Pinterest의 디자인들을 참고하기로 했고, 덕분에 불필요한 디자인 고민들을 하지않아도 되어서 시간을 많이 절약할 수 있었다.

기능은 Interests라는 사용자가 작성한 콘텐츠 그리고 각 Interest에 대한 편집 Reviews 두가지로 정했다, 마치 위키처럼 한문서를 여러명이 편집할 수 있는 구조말이다.

Reviews는 전체 편집본을 나열만 하기 때문에 검색과 추천 기능도 추가해야 했다.

그리고 사용자가 짧은 글을 올리고 현재 상태도 표시할 수 있어야 한다, Facebook 처럼.

기술

이미 웹 사이트 기반으로 만들기로 생각했기 때문에 당시에 웹에서 많이 쓰이고 있던 기술들을 적어봤다.

그리고 학습 시간을 줄이기 위해 내가 해봤던 것과 유사한 기술들을 가능한 선택했다.

Stack

최종 선택된 기술들은 아래와 같다

시간 절약을 위해 SaaS 서비스들을 몇가지 더했다

이제 이 새로운 기술들을 익히기 위해 아래 책들을 읽기 시작했다.

풀타임 정규직이지만 저녁에는 시간이 있었다. 그래서 자기전까지 공부하고 잠은 6시간으로 제한해서 공부할 시간을 확보하기로 결심했다.

처음엔 1년이면 다 만들 수 있을 줄 알았다. 하지만 이 새로운 기술들을 다 공부하고 나니 12월이었다.

2018: 개발시작

2018년 12월 드디어 Visual Studio Code로 개발을 시작했다.

첫날 한일은 DevOpsServerless 등 백엔드 인프라 솔루션을 찾는 일이었다 . 나혼자 그 많은 서버들을 관리하는 것은 어려울 것이기 때문이었다.

CI/CD Pipeline for BackEnd Intra

DevOps로 자동화를 할 수 있었고 Serverless를 통해 서버관리를 할 필요가 없어질 것이다.

처음으로 한 작업은 Terraform으로 CI/CD를 구축하는 것이었다.

Development, UAT, Production 3개의 Branch를 만들고 매일 작업 한 것을 AWS CodeCommit으로 Development에 올려서 AWS CodeBuild로 자동으로 빌드되게 했다.

Frontend CI/CD 구성

local에서 테스트하기 위해 macOS, CodeBuild에서 돌아가게 Linux 환경을Terraform에 설정했다.

빌드가 시작되면 Terraform은 CodeBuild에서 실행되고 AWS로 코드를 빌드해서 올려준다.

이렇게 해서 내가 커밋할 때마다 인프라에 자동으로 계속 동기화될 것이고,

테스트가 끝나면 UAT로 병합하거나. UAT에서 Production으로 병합할 것이다.

2019: 코로나 시대

Backend 자동화 구축을 완료한 후 Frontend 작업을 시작하려고 했다.

처음으로 할 작업은 Aurelia 기반으로 프로젝트를 만드는 것이었다.

React를 선택하지 않은 이유는 MVVM 패턴 때문에 여전히 가장 많이 사용되고 있었기 때문이다.

당시에 나는 WPF를 써봐서 MVVM에 익숙했고 React를 공부하는데는 시간이 더 필요했고, 그게 Angular나 Vue 대신 Aurelia를 선택한 이유이기도 했다.

Frontend 개발을 위해 C# 대신 Typescript와 Javascript를 시작해야 했다.

다음은 기능들을 모듈화하기 위해 WebPack을 도입했고 설정을 쉽게 하기 위해 Neutrino.JS를 추가했다.

2019년에 모바일 웹이 유행해서(코로나 때문인듯) 아래 개발 방법을 적용해야 했다

관련된 핵심 기술들은 Tailwind CSSPWA등이 있는데. 나는 코드를 더 간단하게 만들기위해 Tailiwind를 도입했다.

사용자에게 Native App 같은 경험을 제공하고 싶었으나 Native를 만들시간이 없었고 PWA(브라우저에서 바로 설치되고 오프라인으로도 동작) 위해 Google WorkBox를 채택했다.

기본 구성은 마쳤고 이제 할 일은 실시간 온라인 상태를 유지하는 것이었고, 아래와 같이 구축하기로 결정했다.

먼저 HTML과 Javascript는 AWS S3에 올리고 AWS CloudFront로 가져온다.

이 과정에서 Terraform보다 쉬운 AWS Lambda를 선택하면서 조금 되돌아가야 했다.

설정을 완료하고 AWS Route 53https://immersive.community 도메인을 구입했다.

Mighty Networks에서 영감을 받았고 Immersive라는 단어에 꽂혔다.

하지만 immersive.networks와 immersive.communities는 이미 선점된 상태였다.

이제 Frontend는 준비되었고 다음은 Database다. SQL 기반은 사용해봤지만 이 프로젝트에서는 느릴 것 같아서 NoSQL을 선택했고 Serverless를 위해 AWS DynamoDB를 사용하기로 했다.

또한 Database 접근을 위해 GraphQL을 Serverless로 지원하는 AWS AppSync를 선택했다.

자원 공유(A Multi-Tenant System)

이제 시작하고 첫번째 문제를 해결할 시간이다.

어떻게 하면 사용자가 여러 커뮤니티에 가입된 상태로 서로 제한되거나 비공개된 데이터를 유지할 있을까?

쉬운 방법은 그냥 DB를 쪼개면 되겠지만 생성한 수 있는 DB 수를 초과할 수 있는 문제가 생긴다. AWS 계정 당 생성 제한이 있어서 사용할 수 없는 방법이었다.

결국, DynamoDB에 유형(type) column을 만들어서 해결하기로 했다. 각 사용자는 “user”, 커뮤니티들은 “web”으로 구분한다.

user#web_user#web를 key로 가진는 row를 하나 추가해서 사용자가 커뮤니티에 가입하는 것을 구현하기로 했다. 사용자와 커뮤니티 이름은 Unique로 만들어서 한 사용자가 여러번 가입할 수 없게 할 것이다.

커뮤니티에 가입하고 있는 사용자에 대해서만 어떤 Action을 실행하고 싶을 땐 AppSync의 DynamoDB의 Row를 가져올 수 있는 Pipeline Funtions를 사용할 것이다.

이걸로 multitenancy는 해결 했지만 여전히 산적한 문제들이 많았다.

고가용성 아키텍쳐(Highly Available Architecture)

엔터프라이즈급 시스템들은 장애를 극복능력이 있고 고가용성으로 만들어졌다. 그렇게 해서 사용자들은 일부 부분에 문제가 생기더라도 끊김 없이 시스템을 사용할 수 있게 될 것이다.

연구 결과 이 문제에 가장 최적화된 솔루션은 Active-Active Highly Available 아키텍쳐로 생각되었다. 이미 대부분 AWS의 서비스들은 고가용성이 적용되어있었는데 AppSync는 그렇지 않아서 직접 만들기로 했다.

아래와 같이 지연과 고가용성 문제를 해결했다. 모든 Region마다 AppSync API를 만들기로 결정했다. (현재는 US, Asia, Europe에만 남아있다)

고가용성 아키텍쳐 구조도

각 API는 DynamoDB에 연결해야 해서 DynamoDB도 Region마다 만들었다.

다행히 DynamoDB는 Table간 복제하고 동기화하는 Global Table이라는 기능을 제공했다. 이제 사용자가 위치에 관계없이 동기화된 내용을 보게 될 것이다.

그런데 의문이들었다

사용자가 어떻게 가까운 API(Region)에 접속할 수 있는 것이지?
만약 API 접속을 실패하면 어떻게 다음 가능한 API로 접속하게 하지?

해답은 CloudFront와 Lambda@Edge에 있었다. CloudFont가 호출자가 속한 Region의 Lambda@Edge 함수들를 호출하게 해준다.

또한 어느 Region에서 Lambda@Edge가 실행되었는지 알 수 있어서 같은 지역의 AppSync API를 호출할 수 있게 한다.

그래서 첫번째로 한 일은 AppSync를 직접 사용 하는 대신 CloudFront를 통하는 AppSync Proxy를 만드는 것이었다.

Lambda@Edge의 CloudFront Parameter에서 HTTP 호출을 뽑아내고 Region과 AppSync query를 추출해서 새로운 HTTP call을 만들려고 했다. 데이터가 반환되면 CloudFront를 통해 다시 Lambda@Edge로 넘길 것이다.

하지만 Active-Active(이중화)가 아직 해결되지 않았다. 목표는 한쪽 API가 작동안하면 다른쪽으로 넘기는 것이었다. AppSync 호출 결과가 HTTP 200이 아니면 실패한 것으로 간주해서 처리했다.

HTTP 이중화 코드

실패를 하면 모든 Regions 중에 하나를 골라 AppSync API를 다시 호출하기로 했다.

이렇게 해서 아래와 3가지 기능을 갖추게 되었다.

  • 낮은 지연
  • 지역(Region) 기반 로드밸런싱
  • 고가용성

이제 Region 기반의 API 호출과 이중화가 가능해졌다.

하지만 아직 고가용성이 충분하지 않았다 HTML이나 Javascript 같은 다른 리소스들도 적용하고 싶었다.

16개의 AWS S3 Bucket을 만들었고 Region 마다 같은 파일을 서비스해 줄 것이다.

사용자가 웹 사이트에 방문하면 브라우저가ㅏ HTTP 요청으로 HTML, JS, JSON나 이미지를 받아간다. Lambda@Edge는 이때 URL를 추출하는데 나는 걸로 Region에 있는 S3 bucket에 파일을 요청하는 HTTP를 새로 만들었다.

당연히 요청이 성공하면 파일을 줄 것이고 실패하면 위와 같이 이중화처리 될 것이다.

이 작업들에만 3개월이 걸렸다.

동적 PWA 설정(Manifest)

PWA는 엄청난 기술이다. 하지만 2019년에는 이제 막 시작 단계였다.
각 커뮤니티에 하위 도메인을 부여하기로 결정한 후 ‘홈 화면에 추가’할 때 각 커뮤니티의 아이콘으로 등록되길 원했다.

홈 화면에 추가 영상

하지만 이 PWA의 설정 파일은 하위도메인 기반이 아니었다. 이전에 CloudFront, Lambda@Edge Proxy를 만들어봤기 때문에 이번에는 각 커뮤니티에 해당하는 manifest.json(설정) 파일로 연결하는 Proxy를 만들기로 했다.

그러려면 하위도메인 마다 앱 아이콘, 이름 등을 설정한 manifest.json을 동적으로 생성해야 할 것이다.

하위도메인의 아이콘으로 추가되는 영상

이제 Frontend

이 끔찍한 작업들을 끝내고 UI를 만들 시간이 왔다. 먼저 각 커뮤니티마다 다른 Layout과 Data로 웹사이트를 보여주는 것이 문제였다.

홈 화면에서는 모든 커뮤니티를 보여줘야하고 커뮤니티에서는 그들만의 글을 보여줘야한다.

웹 사이트를 여러개 만들수도 없고 확장할 수도 없기 때문에 최대한 Control과 기능들을 재활용하기로 했다. 최대한 재활용하기 위해 모든 Control들을 4가지로 분류했다.

  • Components
  • Controls
  • Pages
  • Communities

Button이나 Input 같은 작은 것들은 Components에 넣어서 Controls에서 재활용했다. 예를들어 Profile Info Control에서 profile image, username, followers를 재사용 사용하는 것 처럼 말이다.

그리고 이 Controls들을 Page 같은 높은 수준의 Control에서도 사용할 수 있을 것이다. 그리고 다시 또 이런 Control 들은 Communities 안에 유형에 따라 정의되어 각 Community 마다 Pages를 가질 것이다.

Aurelia Router는 동적 분기(Routing)를 쉽게 해준다. 구현방법은 아래와 같다.

하위도메인에 관련 없이 웹 사이트 로딩을 시작할 때, Aurelia 컴포넌트로 구현된 아래의 두 분기(Branch)를 등록합니다.

  • Main
  • Article

main은 사용자가 https://immersive.community로 접속할 때 불러오는 페이지 입니다. 여기서는 모든 커뮤니티 목록과 거기에 속한 컨트롤들을 불러옵니다.

각 Route에 등록될 Page 요소들 준비

다른 하나는 사용자가 하위 도메인으로 이동할 때 불러오는 다른 종류의 레이아웃이다. 즉, 커뮤니티 목록 대신에 글 목록과 기능들(Publish와 Edit 같은)을 불러오는 것이다.

Aurelia와 WebPack 설정은 성능 향상을 위해 Javascript를 필요하지 않은 것은 불러오지 않게 분리해 줄 것이다.

WebPack으로 Javascript 비동기 호출

조립형 레이아웃(The Masonry Layout)

디자인은 최대한 간결해야 한다고 생각한다. 사용자가 웹사이트로 오면 우리는 다른 기능들 대신 컨텐츠에 집중한 것이다.

글들은 목록으로 보여지기 때문에 난잡하면 안된다. 그래서 글이 가져야하는 것들을 결정했다.

  • 표지
  • 제목
  • 카테고리
  • 언제 올렸는지 수정했는지
  • 작성자

Pinterest에서 Pin을 보이는 방법에서 영감을 받아 작성자가 표지의 비율을 선택할 수 있게했다. 그러기 위해서는 CSS Grid나 FlexBox는 만들 수 없는 조립형 레이아웃을 구현할 필요가 있었다.

글 목록 조립형 레이아웃

다행히도 몇가지 쓸 만한 오픈 소스들이 있었는데 Pagination이나 반응형 등은 직접 추가해야 했다.

그런데…

2019년 11월에 코로나가 터졌고. 재택 근무를 시작해야 했고 회사에 갈 필요가 없어졌다. 세계는 고통 받았지만 나에게는 시간이 더 생겨서 행운이었다.

관심사와 리뷰(Interests and Reviews)

Immersive Communities의 글 작성은 협력으로 이루어진다. Wikipedia는 물론이고 Amino Apps, Fandom.com 그리고 HubPages.com 같은 웹 사이트들은 모두 자신들 만의 방식으로 그렇게 돌아가고 있다.

한명이 글을 쓰는 것은 시작은 좋으나 글을 쓰는 사람이 여럿이 되면 링크로 다른 사람의 글로 연결하기도 한다. 기본적으로 커뮤니티는 같은 관심사를 가진 사람들이 오도록 만들어진다.

그래서 나는 두가지 글 종류를 만들었다.

  • Interests(관심사)
  • Reviews(리뷰)

관심사는 길어야 아마 5천자 정도의 짧은 글이 될 것이고 사람들은 관심을 표현할 것이다. 사람들은 특정 관심사글에 대한 리뷰와 점수를 쓸 수 있을 것이기 때문에 관심사글의 메인 화면은 그 글에 대한 리뷰 목록이 된다. 큰 차이점은 누구나 관심사를 수정할 있지만 리뷰는 권한이 있는 사람만 할 수 있는 것이다.

전에 CloudFront에서 AppSync Proxy를 만들어서 돌리기로 했던 것이 발목을 잡았다. CloudFront Query에 제한(8,192 Bytes)이 있어서 더 긴 데이터는 저장할 수 없는 문제였다.

각 글과 관심사는 좋아요나 댓글을 달 수 있고 사람들은 글이 어떻게 쓰여지고 수정 될지 논의할 수 있다. 관심사는 프로필에 추가할 수도 있다.

한해가 다 가기전에 이 기능들을 모두 준비할 수 있어서 내년에는 이 프로젝트를 끝내겠다고 결심했다.

2020: 전력 질주

시작은 잘 되었으나 팬데믹에 경제가 요동치고 물가가 오르기 시작했다. 2020에 많은 일을 했지만 여전히 할게 많이 남아있어서 내 자신을 채찍질했다.

나는 야근은 물론이고 마감을 평소보다 빠르게 맞춰야했기 때문에 내 일정을 다시 조정해야했다. 방법은 잠을 4시간으로 제한하는 것 밖에 없었다.

도쿄 지하철

내 계획은 이랬다 6 ~ 7시에 집에와서 바로 프로젝트에 착수한뒤 새벽 3 ~ 4시까지 작업한 후 잠을 잔다. 7시에 일어나서 출근을 서두른다. 물론 이러면 잠이 부족하지만 주말에 더 자면 될거라고 생각했다. 휴가와 공휴일에도 물론 동일하게 작업했다.

이렇게 새로 세운 계획대로 진행해갔다.

Markdown 편집기

글을 쓰는 사이트는 당연히 텍스트 편집이 쉬워야한다. 2020년에 Markdown이 가장 인기있는 방법으로 떠올랐기 때문에 Immersive Communities에서도 지원해야했다.

당연히 Markdown은 물론이고 HTML도 제대로 보여져야했다. Markdown-It 라는 Markdown을 HTML로 변환해주는 라이브러리가 있었는데 우리는 아래와 같은 다른 미디어들도 보여줘야하는 추가 요구사항이 있었다.

  • Text
  • Image
  • Video
  • Embeds

게다가 이미지는 인스타그램처럼 슬라이드로 보여져야했고, 이걸 하려면 Markdown과 HTML을 섞어야 했다. 편집기를 두가지 입력 형태로 분리했다 Text Field와 Media Field. 그리고 각 Field는 이동될 수 있어야했는데 Sortable.js로 쉽게 구현할 수 있었다.

텍스트의 경우 <textarea>로 충분했고 폰트는 Inconsolata Google Font를 사용했다.

Media Input이 있는 Markdown 편집기

추가로 Text를 꾸미기 위해 Bar를 만들었고, Mousetrap.js로 단축키도 만들었다. Control+B 로 Markdown의 Bold Text인 ** 를 쉽게 추가할 수 있다. Text를 입력할 때, 길어지면 자동으로 커지는 것은 Mousetrap.js 라이브러리를 적용했다.

Media는 내용에 따라 이미지, 영상, 다른 사이틀를 보여준다. 이미지 Swipe는 Swiper.js를 사용했고 영상은 Video.js를 적용했다.

이제 Media를 업로드하는 것이 문제였다. 이미지의 경우 브라우저의 File API를 사용하면 쉽게할 수 있었지만 HEIC format을 JPEG로 변환해야 했다. 서버에 업로드하기 전에 압축을 하려고 했는데 다행히 Heic-ConvertBrowser-Image-Compression라는 내가 원하는 라이브러리들이 있었다.

다른 문제는 업로드하기전에 일정 비율로 잘라내는 것이었다. Cropper.JS를 사용했는데 Safari에서는 제대로 동작하지 않아서 Container 밖으로 나가지 않게 CSS를 조정하는데 많은 시간을 허비했다. 이제 사용자가 이미지를 업로드하기전에 확대/축소, 잘라내기를 할 수 있게 되었다.

Media는 Cloudinary로 업로드 할 것이다.

이제 이것들을 글목록에 보일 시간이다. 다행히 Aurelia에 <compose> 라는 동적으로 HTML을 불러올 수 있는 태그가 있었다. 이걸로 Input 종류에 따라 Media나 Markdown들을 HTML로 변환해서 불러오기로 했다.

변환된 HTML은 CSS도 적용되어야 했다 특시 Table은 화면 크기에 따라 달라져야했다. 큰 화면에서는 가로 모드로 보여져야 하고 작은 화면은 세로로 나타나한다.

그러려면 화면 크기가 언제 어떻게 변하는지 이벤트로 알 필요가 있었는데, resize 이벤트를 가지고 있는 RxJs가 최선의 선택이었다.

데이터 입력 개선

여러 사람이 동시에 수정할 수 있어야 해서 글이 저장되는 방식을 바꿔야 했다.

글을 쓰면 실제로는 버전으로 저장될 것이고, 어떤 사용자가 어떤 글을 수정했는지 추적할 수 있어야 했다. 만약 사용자가 수정하기전에 최신버전을 불러오지 않으면 새 버전을 만들기 어려워지고 저장이 제대로 안되면 이전 버전이 보여질 수도 있다. 초안도 마찬가지다.

데이터 입력을 위해 팝업을 만들기로 했는데 팝업은 아래에 올라와야하고 안에서 Swipe도 되어야했다. 이걸 위해 다시 Swiper.Js를 사용했고 애니메이션은 Animate.CSS를 사용했다.

구현된 팝업 영상

화면 크기에 따라 크기가 변해야 해서 팝업을 만드는 것은 쉽지 않았다. 작은 기기에서는 꽉차는데 큰 기기에서는 50% 크기로 나오는 것 등의 문제가 있었다.

게다가 팔로워 목록 같은 경우는 팝업안에서 스크롤을 해야 했는데 스크롤을 하면 맨위에서 멈추지 않고 계속되어서 내용이 보이지 않게되는 문제가 생겼다.

스타일, Dimmed 백그라운드, 스크롤 제한, 팝업 밖을 눌르면 닫기 등등을 더 수정했다.

이건 애플의 Shortcut 앱 팝업을 참고 했다.

네비게이션 바

iPhone에서 영감을 받은 핵심 UI 기능 중에 하나는 네비게이션 바다. 대부분 모바일 앱들은 간단한 기본 네비게이션 바를 사용하고 있는 것을 알게되어서 iOS의 Bar를 사이트에 구현하기로 결심했다.

항상보이지는 않지만 스크롤을 내릴 때는 숨기 올릴 때는 보이는 것이다. 사용자가 스크롤을 내리면 내용에 관심을 가지지 다른 페이지로 가려고 하지는 않을 것이다. 반대로 스크롤을 올리면 현재 페이지를 나가는 방법을 찾으려는 것일 수도 있기 때문에 Bar를 다시 보여줄 것이다.

바의 4가지 버튼은 사용자가 사이트의 4가지 주요 기능으로 가게 해준다. Home 버튼은 각 커뮤니티의 페이지로 보내고, Trending은 다른 사용자의 글에 반응한 기록을 볼 수 있는 트렌딩 페이지로 보낸다. Engage 버튼은 모든 기능 목록과 커뮤니티 가입 권유 설정으로 보내고 마지막으로 Profile은 프로필 페이지로 가게 해준다.

큰 기기에서는 어떻게 할지 생각할 필요가 있었다. 큰 화면에서는 바를 오른쪽에 붙이고 움직이지 않게 했다.

실시간 배치 프로세스

Frontend 작업이 끝나서 다시 Backend를 시작했다. 복잡하지만 한번 해두면 다른 작업을 하기 수월해지는 중요한 작업이 남아있었다.

객체지향 프로그래밍에는 각 함수는 간결하고 한가지 일만 해야 한다는 관심사 분리라는 개념이 있다.

그리고 관점지향프로그래밍에서는 비즈니스 로직을 공통 관심사들로 부터 분리시켜야한다고 한다. 예를 들어 사용자 저장을 처리하는 중에도 사용자를 자연스럽게 DB에 저장할 수 있다는 것이다.

나는 이 개념을 게시판과 기능들에 적용해서 사용자에게 중요하지 않은 것들은 Backend로 옮기기로 했다.

글이 얼마나 많은 좋아요를 받았는지 추적하고 싶으면 각 글의 좋아요 수를 계산하고 그것을 지속적으로 업데이트하는 프로세스를 만들 수 있다. 데이터가 많으면 지속적으로 DB에 계산해서 넣어줘야하고 실시간 데이터 처리를 만들어서 처리할 필요가 있을 것이다.

AWS Kinesis로 새글/삭제된 수 실시간 업데이트

이것을 처리하기 위해 나는 AWS Kinesis를 선택했다. Kinesis는 많은 양의 데이터를 실시간으로 받아들일 수 있고 실시간 조회과 배치에 SQL을 사용할 수 있다. 기본적으로 Kinesis는 60초마다 또는 배치 할 데이터가 5MB에 도달하면 실행한다.

나는 들어오는 데이터를 조회, 추가, 삭제하고 매 분마다 새로운 데이터로 업데이트할 것이다. 그런데 의문이 생겼다

Kinesis에서 처음에(최초 배치가 돌기전) 어떻게 데이터를 가져오지??

DynamoDB를 선택했기 때문에 데이터가 변할때 Lambda를 실행할 수 있다. 이때 Kinesis에 데이터를 보낼 것이다. (배치도하고 실시간으로도 보내고?)

그러나 처음에 1개의 DB가 아니라 10개로 시작해서 구현하기 힘들었다. 데이터가 하나 들어오면 Lambda를 한번이 아니라 10번 돌려야 했던 것이었다.

이 문제를 해결하기 위해 복제된 데이터는 처리할 때 걸러냈다. “aws:rep:updateregion” column이 데이터가 그 Region에서 추가된 것인지 복제된 것인지 알 수 있게 해줘서 가능했다.

이 문제를 해결하고 추가나 삭제를 골라냈다. 추가로 데이터 종류(커뮤니티,글, 댓글 등)도. 이렇게 골라낸 후 INSERT, DELETE로 표시해서 Kinesis로 보냈다. 이런 방법은 Domain-Driven Design의 Domain 이벤트를 참고 했는데 어떤 Action이 발생하고 그에 따라 데이터가 갱신되었는지 알 수 있게 해줬다.

AWS Kinesis로 실시간 배치

나는 Kinesis를 보면 3개의 부분으로 나눠야 했다.

Kinesis Streams는 대량의 데이터를 실시간으로 받을 수 있게 해주고, Kinesis Analytics는 이 데이터를 조회하고 배치와 집계 할 수 있게한다. 집계가 끝나면 결과를 대량의 데이터를 세고 다른 서비스에 저장할 수 있는 Kinesis Firehose에 넣는다. 나는 S3 Bucket에 JSON으로 저장했다.

S3 Bucket에 데이터가 들어가면 DynamoDB를 갱신하기 위한 Lambda를 실행한다. 예를 들어 1분동안 5명이 한 관심사에 좋아요를 했으면 JSON에서 그 정보를 찾아서 관심사의 좋아요 개수와 좋아요 수 증감을 업데이트 해주는 것이다.

이런 시스템으로 매 분마다 커뮤니티의 통계를 누적했다.

그리고 집계를 보여줘야 할 때 복잡한 쿼리를 작성할 필요가 없이 그냥 DynamoDB에서 가져오기만 하면 되었다. 당연히 조회 속도도 빨라졌다.

Cloudinary

이제 외부 서비스를 구현할 시간이다. 구독하는게 직접 만드는 것보다 쉽다는 것을 알게되었다(당연한 것 아닌가??). 처음 구현한 서비스는 Media를 관리하는 Cloudinary이다. 반응형으로 이미지를 변환하기 위해 아래와 같은 크기로 Cloudinary에 올려놨었다.

  • 576 px
  • 768 px
  • 992 px
  • 1200 px

다양한 기기의 크기에 맞게 조정하기위해 사용한 Tailwind CSS의 설정을 따른 것이다. <image> 태그의 scrcset 속성으로 Cloudinary에서 이미지를 현재 화면 크기에 따라 불러올 것이다.

이렇게 해서 모바일 기기에서 이미지를 빠르게 불러오는데 도움이 되었다.

영상의 경우 너무 비싸서 관뒀다. 당장은 필요 없으니 … 나중에 AWS에 추가로 만들어야 할 것 같다.

Embed.ly

트위터, 유튜브 같은 유명 사이트들을 보여주기 위해 Embed.ly를 사용하기로 했는데 여러번 불러올 때 이슈가 있어서 Facebook과 트위터에서 스크립트를 걷어내는 작업을 해야 했다.

Algolia

커뮤니티, 활동, 글, 사용자 검색에 쓰려고 Algolia를 골랐다. Frontend 구현이 간단해졌다.

검색 바를 선택하면 다른 내용을 숨기고 검색어를 입력하면 현재 들어와있는 특정 하위도메인에 대한 검색 결과를 보여준다. “Enter”를 누르면 조건에 일치하는 글들을 화면에 보여준다. 나는 Pinterest 처럼 결과가 점점 많아지게 페이징도 구현해야 했다.

Algolia에 전체 문자열을 저장하지 않고서는 활동내역을 검색할 방법이 없다는 것을 알게되었고, 그 문제를 피하기 위해 각 활동에 관련 태그를 저장하기로 했다.

어떻게 관련 태그를 뽑아낼까?

답은 AWS TranslateAWS Comprehend에 있었다. 앞으로 들어갈 데이터가 많고 일일이 직접 API를 구현하기에도 벅차기 때문에 Algolia에 넣었다. 실시간 배치도 돌려야 해서 다시 Kinesis를 썼다.

구조도

이번에는 DB에 들어가는 각 데이터마다 Kinesis Data Streams로 보내고 Kinesis Firehose로 보내서 S3 bucket에 저장하는 Lambda를 실행했다.

데이터가 저장되면 Algolia로 보내는 Lambda를 실행하는데 그전에 먼저 처리를 해야 한다. 특히 활동내역을 처리할 때는 markdown-remover를 써서 Markdown을 걷어내고 순수한 문자열만 남겼다. 그렇게 얻은 문자열로 검색에 필요한 관련 태그들을 뽑아냈다.

AWS Comprehend로 쉽게 끝났지만 몇가지 언어만 지원한다는게 문제였다. 사용자가 지원하지 않는 언어로 작성하면, AWS Translate로 영어로 번역하고 태그를 뽑아낸 후 그것을 다시 원래 언어로 번역했다.

Recombee

Pinterest의 핵심 기능 중하나는 추천 엔진이 있다. 사용자가 Pin을 클릭하면 전체 화면으로 Pin을 보여주고 사용자가 보고 싶어 할 만한 다른 Pin들을 아래에 나열하는 방식이다.

이런 기능을 만들기 위해 유사한 글을 보여줘야 해서 SaaS 기반 추천 엔진인 Recombee를 사용했다.

같은 방식을 사용해서 Algolia를 사용할 때보다는 구현하기 쉬웠다. 사용자가 새로 추가할 때마다 추천이 필요할지 확인하기 위해 Kinesis를 사용해서 배치를 돌리고 Recomebee 보냈다.

추천 과정은 항상 사용자가 보고 있는 화면과 글 기반이기 때문에 화면 정보와 보고 있는 글을 Recombee로 보냈다.

Recomebee에는 사용자가 어떤 행동을 했는지에 따라 또 다른 작업도 할당할 수 있다. 예를 들어 사용자가 관심사에 좋아요하면 순위에 반영되고 커뮤니티에 가입하면 북마크에 연결되는 식이다.

이런 데이터를 가지고 Recomebee로 사용자에게 추천목록을 만들 수 있었다.

Frontend에서는 사용자가 현재 읽고 있는 글과 그 글에 대한 추천 데이터를 받을 것이고, 각 글의 하단에 보여줄 것이다. 이렇게 하면 사용자에게 관심있을 만한 글들을 보여 줄 수 있다.

Locize

글로벌 서비스를 위해 현지화도 구현해야 했다. 처음 출시할 때는 10개 국어만 지원하기로 하고 i18next 기반의 Locize라는 SaaS 서비스를 사용하기로 했다.

1개 인지 여러개인지, 수량 단위의 단어를 현지화하고 글이 만들어지고 수정되었는지 표현하는 시간도 할 것이다.

<div class="flex justify-between">
<h1 class="mx-1 text-large text-grey-light">
${ 'recommended' & t }
</h1>
</div>

영어를 기본 언어로 설정하고 모든 단어들을 구글 번역기로 돌렸다. Aurelia도 현지화를 지원해서 편했다. 번역이 끝나고 번역된 JSON 파일들을 커뮤니티 종류에 따라 나눠넣었다.

Aurelia는 번역된 문구에 자동으로 binding할 수 있는 template을 지원하지만, 글이 써지고 얼마나 지났는지 등의 시간 형식에는 변환기를 사용했다. 숫자 표기도 1000 대신에 1K로 표기해야해서 NumbroTimeAgo 같은 라이브러리들을 사용했다.

Twilio

커뮤니티는 사적인 대화를 할 수 있어야 한다. 즉 실시간으로 비공개 채팅을 할 수 있어야 한다는 것이다. 이 기능은 Twilio라는 채팅 서비스를 사용해서 만들었다.

Backend는 Twilio로 쉽게 끝났고 Frontend는 인스타그램을 참고해서 간결하게 디자인했다.

SPA 미리 불러오기(Prerendering)

검색 엔진에서 크롤링이 가능하도록 Prerender라는 서비스도 사용하려고 했는데 요금이 문제여서 직접 만들기로 했다. 이 작업을 위해 Headless Chrome API를 제공하는 Puppeteer라는 라이브러리를 찾아냈다.

이 라이브러리는 검색 엔진에 제공하기 위해 웹 사이트를 코드로 불러오고 Javascript를 실행해서 나온 HTML를 떨군다. 그래서 Lambda에서 Puppeteer를 호출하게 구현했다.

Lambda@Edge를 사용해서 접속자가 검색엔진인지 알아내서 pre-rendering하는 Lambda에 던졌다. CloudFront 파라미터 중에 ‘user-agent’를 알아내는 것은 쉬웠는데 Puppeeteer가 너무 무거워서 Lambda가 호출할 수 없었다.

그러나 Puppetter의 core만 사용할 수 있는 chrome-aws-lambda라는 라이브러리를 찾아내서 큰 문제가 되지는 않았다.

Stripe

Immersive Communities의 핵심 기능 중 하나는 수익 쉐어이다, 구독료와 광고 수익의 50%를 공유하고 있다. 창작자들에게 컨텐츠 제작뿐만 아니라 수익화도 제공해야 하는데 어떻게 구현하냐가 문제였다. Stripe를 선택해서 아래와 같이 처리했다.

각 커뮤니티의 수익 공유 시스템을 기획해서 사용자가 여러 커뮤니티를 만들고 각 커뮤니티에서 아래와 같이 수익을 얻게했다.

  • 구독료
  • 광고

구독은 구현하기 쉬웠다. 월 5, 10, 15 달러 이 3가지 구독 종료를 만들었다. 구독자는 매월 커뮤니티를 후원하고 광고를 보지 않게된다.

구독 선택 화면

광고 시스템은 월 구독과 같지만 100 ~ 1000 달러이다. 특정 커뮤니티에 광고를 원하는 회사는 지불액과 배너 광고를 설정할 수 있다.

한 커뮤니티에 광고주가 많아지면 각 페이지 전환마다 무작위로 광고가 표시된다. 광고 노출 빈도를 올리려면 지불액을 늘리면된다.

광고 설정 화면

광고주가 광고가 어떻게 동작했는지도 보여줘야 해서 다시 Kinesis를 사용해서 노출수와 클릭수를 집계했다. 이런 시스템으로 통계를 업데이트하고 보여주기 위해 Brite Charts라는 라이브러리를 사용했다.

가장 중요한 것은 실제로 수익을 공유하는 기능이었는데 이것은 Stripe Connect를 사용했다. 사용자은행 계좌를 등록해서 Stripe Express에 연결해두면 시스템이 필요할 때 송금한다.

Stripe 기반의 수익 공유 시스템

Lambda를 스케쥴 걸어서 일일 사용자를 가지고 업데이트하고 커뮤니티 주인장에게 전송해서 50%의 수익이 발생하고 있다는 것을 알게 했다.

AWS Cognito

마지막으로 구현해야 했던 서비스는 사용자 인증에 사용되는 Auth0였다. 몇가지 연구 끝에 SMS 인증으로 비밀번호를 없애기로 했다. 우리가 현재 모바일 천지에 살고 있다는 것을 생각 하면 비밀번호를 버리고 이미 다들 가지고 있는 폰을 기반으로 하는 것은 당연했다.

Auth0는 비밀번호 없이 인증하게 하기 위해 그들의 사이트로 접속해서 URL parameter를 넘겨야 했고, 가격도 사용자 수에 따르지 않아서, AWS Cognito로 직접 만들었다.

Cogito는 인증에 필요한 Lambda를 실행할 수 있어서 쉬웠다. Lambda는 회원가입할 때 사용자의 정보를 수집하는데 사용자는 핸드폰 전화번호와 등록을 위한 이름만 입력하면 된다.

비밀번호 없는 로그인 과정

로그인하는 동안 Lambda는 사용자의 핸드폰 전화번호를 받아AWS SNS로 SMS 인증번호를 발송한다. 사용가가 받은 코드를 입력하면 Cognito는 검사해서 Profile 화면으로 보낼 것이다.

당연히 사용자 인증이 되면 사용자의 데이터가 Fontend로 넘겨질텐데, 나는 그걸 암호화해야 할 것이다. 그 데이터들은 Backend에 저장되기 전에 암호화된다.

나는 사용자의 IP도 저장했다.

사용자의 휴대폰에 문제가 생길 수도 있을 것이기 때문에 나는 SMS를 Email로 바꾸기로 했다. AWS SES를 사용하니 중복으로 발송될 때가 있어서 Twilio의 SendGrid를 사용했다.

작업이 끝내고 나니 또 한해가 다 갔다. 2전년 시작한 프로젝트가 거의 끝나가고 있었다.

2021-끝이 없다

오랫동안 혼자 작업하다보면 생각하게 된다.

끝날 것 같지 않은 이 작업을 내가 계속 할 수 있을까?

답은 간단하다. 당신은 당신의 결정에 스스로 이의를 제기할 수 없고 기분에 따라 작업을 결정할 수 없을 것이다. 지금 당장 그렇게 느끼지 않아도 (그렇게 작업하다보면) 언젠간 그럴 것이다. 아무것도 안하면 아무것도 진행되지 않는다. 방법은 무슨일이 생기던 작업을 계속하는 것 뿐이다. 항상 출시해야 하는 기능과 코딩만 생각해라 그게 목표에 다가갈 수 있게 해줄 것이다.

이 프로젝트를 하는 동안 나는 3번이나 이직해야 했는데, 면접보고 와서도 계속 작업했다.

동기가 부족하면 스스로에게 질문해라

지금 그만두면 다음엔 어쩔 건데? 계속하는 수 밖에 없다. 그만 두면 되돌아 가는 것 밖에 없다. 되돌아가면 어떻게 될지 넌 이미 안다. 처음 이 일을 왜 시작했는지 생각해라.

되돌아 가는 길은 없다. 계속 나아가는 수 밖에 없다

이게 내가 이 프로젝트를 할 수 있었던 동기이다.

관리자

처음으로 돌아가서. 나는 모든 커뮤니티를 관리할 수 있는 관리자 시스템을 구축하기로 했다. 각 커뮤니티의 장들은 컨텐츠를 커뮤니티에서 삭제할 수 있다. (커뮤니티)규칙에 따라 광고, 글, 활동 등을 비활성화하거나 사용자를 추방하는 것을 의미한다.

커뮤니티 소유자는 관리자 권한을 다른 사람에게 줄 수도 있다. 또한 커뮤니티의 관리자들은 다른 커뮤니티도 관리할 수 있어야하고 다른 커뮤니티의 사용자들을 비활성화(추방?) 하거나 커뮤니티 자체를 비활성화 할 수도 있어야 한다.

관리자들이 관리를 쉽게하기 위해 나는 각 항목이 관리자들에게 보고되는 신고 시스템을 만들었다. 사용자는 사이트에서 불편하게 만드는 어떤 것이라도 신고할 수 있다.

각 사용자 권한은 Backend에서 검사하는데, 나는 AppSync에서 각 요청 마다 (권한을) 검사하는 Lambda를 만들었다.

Frontend는 Aurelia에서 제공하는 라우팅 기반 인증을 사용한다. 현재 사용자가 특정 Route로 처리될 수 있는지 아닌지 결정하는 규칙을 만들었다.

예를 들어, 당신이 커뮤니티에서 추방되면 (커뮤니티에서의) 당신의 프로필을 보지 못하는데, 이러한 시스템은 로그인하지 않은 사용자가 프로필 화면으로 가지 못하게도 해준다. 대신 로그인 화면으로 보낼 것이다.

통계 페이지(The Analytics Dashboard)

사용자에게 유용할 다음 기능은 통계 페이지이다. 각 커뮤니티의 소유자는 커뮤니티에서 얼마나 많은 활동이 일어났는지 그래프로 볼 수 있는데 이 기능은 Kinesis의 데이터를 재사용해서 Brite Charts로 그래프를 그렸다.

커뮤니티 통계 페이지

Stripe에서 구독자, 광고자, 총 수익 등도 가져와서 보여줬다.

문제는 반응형으로 디자인해서 작은 화면 큰 화면 모두에서 그래프를 보여주는 것이었다. 나는 다시 RxJs의 resize이벤트를 가져다가 Tailwind CSS에 적용했다.

보안

계획에 보안 단계도 추가하기로 해서 CloudFront에 WAF를 구현했는데, AWS 마켓에서 안전한 Traffic만 처리하게 해주는 Imperva WAF를 찾아 구독했다.

구현하기는 쉬웠는데 첫달에 지불하기에는 너무 비싸서 연결을 끊고 CloudFront가 기본으로 제공해주는 것을 사용하기로 했다.

막판에 뒤집기(The Last-Minute Redesign)

이제 남아있는 작은 문제들을 볼 시간인데, 가장 큰 문제는 DynamoDB를 설정을 바꾸는 것이었다.

처음 했던 설정은 지금 시스템 규모에 적합하지 않았다. 이게 내가 완전히 다시 설계하기로 하고 Record Id에 #구분자를 사용하기로한 이유다.

예전에 나는 Record들 구분하고 AppSync 파이프라인을 사용해서 일정하지 않게 관련된 Record에 위치 배치했고, 이것은 Kinesis와 Algolia나 Recomebee 같은 다른 서비스에도 영향을 끼쳤다.

이걸 완전히 뜯어고치는데 3개월이 걸렸다.

기록적인 폭염

도쿄의 여름은 덥고 습해서 한곳에 머무르는 것은 고역이다. (아무튼 엄청 더웠다는 얘기들…).

(너무 더워서)열차로 출근하는 것은 불가능 해서, 시간을 아끼기 위해 택시를 이용해야 했다. 그렇게 하니 잘 시간 더 확보하고 귀가했을 때 지치지 않게 해줬다.

실시간 알림

PWA는 사용자에게 푸시로 알림을 보낼 수 있는 좋은 기술이다.

알림 시스템은 다음과 같이 사용자 기반으로 구현될 것이다. 당신은 사용자가 새로운 활동을 하거나 글을 쓰면 알림을 보내야 한다.

푸시 알림의 유일한 문제는 iOS의 Safari 브라우저에서 지원하지 않는 것이었다. Native 푸시 대신에 브라우저의 알림 API를 사용하기로 했다. Backend는 새 AWS API Gateway를 만들어서 실시간 데이터를 처리하게 하고

실시간 알림 시스템

Frontend는 웹소켓으로 Gateway에 연결했다. 사용자가 새 글을 발행하면 데이터가 Kinesis로 보내지고, 배치가 돌아가서 작성자를 팔로우하는 모든 사용자 목록을 얻어서 API Gateway로 Frontend에 알림을 보내는 것이다. 그러면 Frontend에서는 웹소켓이 실행되어 브라우저의 알림 API가 실행되고 화면에 알림을 보여줄 것이다.

댓글의 경우 사용자들이 어떤 글/댓글에 참여하고 있는지 추적해야한다. 어떤 댓글을 읽지 않았는지 알게하기 위해 읽지 않음 표시도 구현했다.

이 과정들은 앱을 실행할 때 비동기로 돌아간다.

나는 뭔가 성공하거나 실패했을 때 사용자에게 알릴 때 팝업도 사용했다. 예를 들어, 글 업데이트가 실패하면 팝업 페세지를 사용자에게 보여주는 방식이다.

Frontend 유효성 검증(Validation)

Backend 검증이 끝나고, Fronend에 사용자에게 빠른 응답을 위한 검증을 구현해서 더 좋은 경험을 제공해야 했다.

Aurelia로 검증

다행히 Aurelia에 물 흐르듯 구현된 검증 플러그인 있었다. 이 플러그인은 비즈니스 규칙을 만들기 쉽게 해줬다. 예를 들어, 사용자가 입력하는 글 이름의 길이를 제한하는 같은 것 말이다.

Aurelia의 속성을 시스템에 연결해서 수집하고 UI에 검증 메세지를 보여줬고, 적절한 언어로 메세지를 보여주기 위해 현지화 시스템에도 연결했다.

마무리(Finalizing the Work)

이제 작은 일만 남았다. 로딩 표시 같은 것들을 만들어야 했는데 화면 추가로 넣고 싶지 않았다.

대신, 사용자에게 로딩 중이라는 것을 표시하고 싶어서 로딩되는 UI의 개요를 사용하고 반투명되는 애니메이션을 적용했다. Netflix 앱을 참고한 것이다.

한해가 끝나가고 있었다. 이제 메인 페이지를 작업할 시간이다. 이 페이지는 그냥 모든 커뮤니티를 보여주기만 할 것이다. 운좋게도 컴포넌트 기반의 시스템으로 만들어놔서 대부분 재사용해서 빠르게 끝낼 수 있었다.

2022-마지막 구간(The Last Mile)

그 해에끝날 예정이었다. 만들려고 했던 것을 다 만든 것인지는 모르겠지만 해야 될 것은 알았다. 내년 여름은 더 더울 것 같아서, 이번 여름과 같은 일을 반복하고 싶지 않았다.

랜딩 페이지 디자인

랜딩 페이지를 디자인하기 시작하려는데 의문이 들었다

사용자가 랜딩 페이지에 들어왔을 때 어떻게 느끼길 바라는 거지?

나는 사용자가 사이트를 너무 진지하게 보지 않고, 친근하고 친숙한 커뮤니티로 느끼길 바랬다.

나는 랜딩페이지들이 실제 사진(캡쳐?) 대신 이미지를 주로 사용한다는 것을 뒤늦게 알았다. 그래서 Adobe Stock에서 이미지들을 구매했다.

랜딩 페이지는 심플해야 하고 사이트를 빠르게 설명할 수 있어야한다. 현지화도 적용되어야 해서 모든 랜딩페이지의 제목과 부제목들을 번역했다.

랜딩 페이지

기술적인 문제는 글자에 색을 넣는 것이었는데, 다행히 번역본에 스타일을 적용하고 Markdown으로 HTML을 동적으로 생성할 수 있었다.

개인정보처리방침이나 이용약관 같은 것들은 구매(?)해서 구글 번역기로 돌렸다.

만일의 사태에 대비(Expect the Unexpected)

남은 시간은 Lambda의 로그들을 확인하는데 보냈다. 이렇게 하면 나중에 문제가 생겼을 때 도움될 것이다.

끝낼 무렵 우크라이나 전쟁이 터졌고 다시 국제 경제가 요동치기 시작했다. 하지만 나는 목표에 집중해서 계속 작업했다.

PWA 구현이 최신이 아니라서, 모든 기능이 작동하는지 확인했고 Javascript와 이미지 캐싱 개선도 해야했다. 이렇게 오프라인 기능들이 준비되고 오프라인으로도 잘 작동했다.

Backend에서 했던 작업들과 AppSync 변경 사항을들 다른 Region에도 적용해야 했다. 너무 번거로워서 개발을 시작하고 전혀 다른 Region에 반영을 안했었다(자동이 아닌가?).

환경설정도 마찬가지로 3가지 빌드를 계속 하는 것은 시간 낭비라서 마지막에서야 UAT와 상용 브랜치로 코드를 동기화했다.

마지막으로 www 없이도 사이트에 연결되게 하기 위해 https://immersive.community 도메인을 구현해야 했다.

이제 끝인가?

이때가 2022년 4월 25일 이른 아침이었다. 4년 동안의 프로젝트가 마침내 끝났다. 나는 첫번째 글을 사이트에 올리고 잠이들었다. 나는 마침내 성공했다. 다시 여름이 오기전에 모두 끝냈다.

끝내며

아이러니 하게도, 모험의 마지막 말은

이것은 끝이 아니라 시작이다

이제 시스템은 살아 숨쉬고 있다. 서비스를 알리기 위해 컨텐츠를 만들고 홍보하는 것은 새로운 모험이 될 것이다.

내가 이 여정에서 진짜로 깨달은 것은 뭘까?

물론 엄청 많다. 먼저 다시는 못할 짓이라는 것. 결과는 만족하지만 인생에서 한번 정도 있을 일이고, (이렇게)자기가 (Youtube나 Facebook보다)더 잘할 것이라는 것을 증명하려고 오버하는 것은 말도 안되는 짓이다.

나는 그저 엔터프라이즈 수준의 시스템을 한명의 개발자가 만들 수 있을지 궁금했고, 여러 기술들을 상용해서 가능함을 증명했다. 무엇보다 이 사례는 사이드 프로젝트를 하고 있거나 하려는 모든 개발자들에게 해당되는 것이다.

다른 개발자들에게도 이 방식을 추천하냐고 묻는다면? 절대아니다, 왜냐하면 더 나은 방법이 있기 때문이다. 막혔을 때 도움을 요청하지 않는 것은 빠른 방법이 아니지만, 자신의 한계는 알 수 있을 테지만. 그것(도움 요청)을 해서 성공했다면 더 쉽게 성공했을 것이다.

내 이야기가 당신이 하고 있는 것을 끝내는데 동기부여가 될 것이라고 믿는다. 아직 끝을 보지 못했다면 되돌아가면 원하는 것을 얻을 수 없다는 것을 기억하기 바란다.

만약 내 이야기에서 영감을 얻었다면, 내 유튜브 채널도 구독해주기 바란다. Immersive Communities를 만드는데 사용한 기술에 대해 자세히 설명하는 풀스택 개발 강의(영상)을 올리기 시작했다.

이 글에서 다루지 않은 것은 문제를 해결하는 접근법과 어떤 기술들을 사용해서 분석하고 설계했는지 이다. 그것은 어쩌면 단순히 기술들을 아는 것보다 중요할 수 있다. 문제에 어떻게 접근하고 생각해야 하는 지에 대한 것은 유튜브에서 자세히 설명할 것이다.

실제 시스템을 만들어본 사람에게서 프로그래밍을 배우고 지식을 공유 받는것은 개발자에게 (학습)방법이다.

유튜브에서 봐요! 읽어주셔서 감사합니다!

내 생각

원문의 길이 만큼이나 이것을 번역하는 것은 나에게도 큰 도전이었다. Medium 결제까지 했는데 이걸 번역하는 동안 다른 글은 보지도 못하고 새로운 글도 못올리니 조회수도 5천까지 올랐던 것이 3천대로 떨어졌다.

그래도 계속 했던 것은 나도 만들려고 하는 것이있어서 내용이 궁금하기도 하고 저자의 말대로 여기서 그만두면 그동안 써놓은 것이 아까워서 였다.

저자와는 달리, 나는 앱을 만들 것이라. 큰 도움은 되지 않을 것으로 보인다. 나는 예전에 사용한 Firebase로 만들어 볼 생각이다. 그래도 AWS에 다양한 서비스들이 있다는 것은 알게 되었다.

개인 앱/사이트 만드는 분들에게 도움이 되었길 바라며…

도움이 되었다면 원문에 가서 박수를 쳐주기 바란다. 👏

원문

--

--

No responses yet