Github의 기능상의 부족한 점 중 하나는 컨텐츠 관리가 어렵다는 것입니다. Github에서 파일의 위치와 컨텐츠 자체를 수정을 위해 견고하지만 다소 단순한 수준의 인터페이스만 제공하고 있습니다. 더 쉬운 컨텐츠 관리를 위해 prose, siteleaf, jekyllcms 등의 컨텐츠 관리 서비스가 등장하였습니다. 대부분의 서비스는 편집 기능만 제공하는 아쉬움이 있었고, OS 탐색기처럼 범용적인 기능을 제공하지 않는 점이 조금 아쉬웠습니다.
각각의 CMS(Content Management System)에 부족하다고 생각된 기능은 다음과 같았습니다.
어떤 서비스는 한글 지원 이 안되는 경우도 있었습니다. 개인적으로 또는 개발자들의 프로젝트 과리에 도움을 주기 위해 위에 나열된 기능과 탐색기를 포함한 새로운 CMS를 개발하기로 결정하였습니다. BSide는 Github 온라인으로 컨텐츠를 수정 및 관리할 수 있게 도와주고, 다양한 Jekyll 템플릿 제공 및 Github 정적 사이트를 생성을 지원하는 Github CMS 입니다.
먼저 서비스를 만들기 전에 몇몇 서비스를 벤치마킹 하였습니다. 대부분의 서비스는 서버 파트의 비중이 낮았습니다. 또한 별도의 Database를 두지않고 OAuth 인증만 하도록 설계되었습니다. 여러가지 이유가 있겠지만 서비스 자체가 Browser의 기능성과 Github API만으로 충분히 구현 가능해서 그런 것 같습니다. BSide 역시 서버 기능을 최소화 하였습니다.
아래는 Gitlab IDE와 Prose를 비교한 표 입니다.
서비스 | 트리 뷰 | 트리 조작 | 업로드 | 탭 | 임시 저장 | 프리뷰 | 원본비교 | 서버 통합 |
---|---|---|---|---|---|---|---|---|
Gitlab IDE | 지원 | 지원 | 지원 | 지원 | 지원 | 없음 | 지원 | 높음 |
Prose | 지원 | 없음 | 없음 | 없음 | 지원 | 부분(마크다운) | 지원 | 낮음 |
BSide을 구성하는 주요 컴포넌트는 다음과 같습니다. 제한된 시간에 각 컴포넌트 개발을 위해서는 라이브러리가 필요합니다.
Workspace와 컴포넌트는 자식 컴포넌트를 특정 흐름으로 묶을 수 있어야 합니다. SPA는 이러한 모듈 및 컴포넌트 간의 분리 및 통신을 쉽게 구현할 수 있는 아키텍처 입니다.
Angular는 Enterpise 수준의 기능성 및 애플리케이션 모듈화, 테스트, Lazy-loading을 지원하는 SPA 프레임워크 중 하나였습니다. 또한 Typescript를 기본적으로 지원하고 있습니다. 그래서 Angular 프레임워크와 라이브러리를 조사하여 서비스를 개발하기로 결정하였습니다.
지난 몇년 간 Typescript의 발전으로 견고한 웹 애플리케이션을 개발 할 수 있게 되었습니다. Typescript는 개발 생산성을 향상에 도움을 줍니다.
서버는 Rest API 개발 및 단위 테스트를 수행할 수 있으며, 자료가 많고 익숙한 프레임워크를 선택하는 것이 좋다고 생각하였습니다. 따라서 기존에 몇번 다뤄봤던 Spring Boot를 선택하였습니다. OAuth 인증이나 기본적인 데이터 교환만 할 것이므로 클라이언트 서버간의 통신은 Rest 스타일로 충분했습니다.
좀더 구체적인 아키텍처를 그리기 위해서는 각 컴포넌트가 어떤 역할을 하고 서로 상호작용하는지 생각해볼 필요가 있었습니다.
소프트웨어의 복잡성 및 유지보수 비용을 줄이고 위해서 각각을 패널을 컴포넌트 단위로 나눠서 개발할 것입니다.
이런 상황 일때 각각 컴포넌트간의 통신은 생각보다 복잡해질 수 있습니다. 예를들어 왼쪽 탐색기, 위쪽 탭, 가운데 에디터를 각각을 개발한다고 가정해보면 객체 간의 통신은 피할 수 없으며, 어떤 일관된 인터페이스가 필요한 것을 알 수 있습니다.
예를들어 왼쪽 탐색기 변경에는 추가, 삭제, 선택, 이름 변경이 있고, 탭의 변경에는 추가, 삭제, 선택 등이 있고, 에디터의 변경에는 내용 수정 등이 있을 수 있으며, 어떤 이벤트가 발생했을때 다른 컴포넌트에 메시지를 보낼 필요가 있습니다. 즉, 아래와 같이 한 컴포넌트가 다른 여러 컴포넌트에 side effect를 주는 방식으로 동작할 것입니다.
모든 컴포넌트가 이벤트의 소스가 될 수 있고, 이벤트 핸들러 간에 순서가 필요할 수도 있습니다. Component Interaction 가이드를 참고하여 이벤트 기반의 통신 방식을 생각해 보았습니다.
Angular가 지원하는 컴포넌트간 기본적인 통신(상호작용) 방식에는 자식 컴포넌트의 Input/Output을 활용하는 방식, 자식 컴포넌트의 인스턴스를 변수에 바인딩하여 조작하는 방식, 별도 서비스를 이용하여 채널을 만들어서 통신하는 방식등이 있습니다
Service를 기반으로 통신을 하되, 이벤트를 순서대로 브로드캐스팅하는 방식을 생각해 보았습니다. 이는 먼저 발생한 이벤트를 먼저 처리하는 것을 보장할 수 있습니다. 하지만 이벤트 수신자가 UI 변경 이벤트로 인해 다시 이벤트를 발생시키면서 컴포넌트간 루프가 발생할 수 있습니다.
따라서 되도록이면 수신자는 자신의 상태만 변경하고 UI 변경으로 인해 같은 이벤트를 다시 발생시키지 않도록 하는 등의 코딩 규칙이 필요합니다. 또한 자기 자신이 이벤트 수신자와 발송자가 같은 경우 추가적인 이벤트 발송하지 않는 규칙이 추가되어야 합니다.
이 방식은 비교적 구현이 쉽고 이벤트 간 브로드캐스트 순서를 보장하기 때문에 안정성이 있습니다. 큐와 이벤트를 구현한 특정 서비스를 두고 각 컴포넌트에서 구독하는 형식으로 구현됩니다.
OAuth에 대한 지식이 없어도 oauth-flow와 같은 가이드 덕분에 쉽게 구현할 수 있었습니다. OAuth 에 필요한 난수를 서버에서 생성하고, 사용자가 Github에서 인증을 하도록 만듭니다. BSide로 리다이렉트 되는 과정에서 제공된 code(인가코드)를 Github에 전송해 accesstoken을 요청합니다. Github에서 제공하는 OAuth 인증의 자세한 스펙은 https://tools.ietf.org/html/rfc6749#section-4.1 에서 확인할 수 있습니다.
Windows에 내장되어 있는 파일 탐색기 처럼 구조를 쉽게 조작할 수 있는 트리 컴포넌트가 필요하다고 생각하였습니다. 기본적으로 Angular Material을 전체 프로젝트에 적용하고 있으므로, 먼저 Angular Material의 Tree를 고려해봤습니다. 트리 표현은 가능했지만, 드래그 앤 드랍 기능을 제공하지 않았습니다. 또한 한번에 모든 요소(element)를 생성하기 때문에 트리 구조가 거대할때 굉장히 애플리케이션을 느리게 만드는 문제가 있었습니다. dynamic, partially 와 같은 lazy-loading 예제가 있지만, 그 외 기능성이 부족합니다. 그 외, 오픈소스 중 angular-tree-component가 Material Tree의 기능을 포함하며, 안정적이며 드래그 앤 드랍을 포함한 커스터마이징 기능을 포함하는 것으로 보였습니다. 또한 공식 메뉴얼의 내용도 풍부했습니다.
특징
게시판 목적이 아니므로 HTML 기반의 rich 에디터는 제외하였습니다. BSide는 완전한 IDE가 될 수는 없지만 최소한의 쓰기 작업을 위한 기능을 가지면 좋겠다는 생각을 했습니다. monaco 에디터는 vscode 사용자에게 익숙하며, 풍부한 내장 API 및 언어 하이라이팅을 제공하므로, 추후 확장성을 고려했을때 좋은 선택지 였습니다. 하지만 monaco은 모바일을 지원하지 않기 때문에 별도 모바일용 에디터가 필요했고, 모바일에서는 easymde를 사용 하기로 결정하였습니다. easymde는 가볍게 마크다운 에디터 및 마크다운 프리뷰로 사용하기 좋았습니다.