요즘 블레이저 관련한 글들이 점차 늘어 나고 있는 것 같습니다.
그런데, 용어가 약간 씩 섞여 있는 느낌이라, 몇 가지 정리를 해봤습니다.
레이저 (Razor)
비 html 소스 코드를, html 문서에 삽입하는 문법을 가리킵니다. ‘@’ 가 식별 마크로 사용됩니다.
닷넷 사용자 입장에서는 이 문법을 통해 html 문서에 C# 코드만 삽입할 수 있는 것으로 생각하시겠지만, 사실 특정 언어에 종속되지 않은 기술입니다.
파서만 정의하면, 얼마든지 다른 언어에도 적용이 가능한데, 마소가 안 할 뿐이죠. (하면 배신입니다)
레이저 페이지(.cshtml)
레이저 문법을 통해 C# 코드가 삽입된 html 문서입니다. C#-Razored Html Document 이 가장 적정한 표현일 것 같습니다.
레이저 요소(.razor)
흔히들 "블레이저 요소"로 언급하는 경우가 많으나, 공식 명칭은 “Razor Component” 입니다.
레이저 컴포넌트는 레이저 문법으로 선언한 커스텀 html element 이라 할 수 있는데, 레이저 페이지와 형태적으로는 동일하지만 재사용성을 강화시킨 것입니다.
C#-Razored Html Element 이 가장 적정한 표현일 것입니다.
레이저 요소는 html 요소이기에, 당연히 html 문서에서 사용될 수 있고, html 문서에는 레이저 페이지도 포함됩니다.
이름이 말해주듯, 요소이기 때문에, 가급적 작게 작게 정의해서 여러 프로젝트에 두루 두루 쓸 수 있도록 하는 것이 좋습니다. 이를 위해서 레이저 라이브러리 프로젝트가 있습니다.
블레이저 (Blazor)
화면을 갱신하는 게 주 임무인 자바 스크립트가 요체입니다.
블레이저 웹어셈블리
wwwroot/_framework/blazor.webassembly.js
함께 다운로드되는 Webassembly 바이너리와 데이터를 주고 받는데, Webassembly가 C# 코드를 실행시킵니다. 즉, 프로젝트에 삽입된 실행 코드는 사용자 PC의 브라우저에서 실행됩니다.
보시다시피, 블레이저 웹어셈블리는 전통적인 프론트 엔드의 실행 방식과 유사한데, 웹어셈블리를 실행하는 일반적인 방식합니다.
다만, 코드 작성 방식에 있어서, 전통적인 프론트 엔드와 차이점이 있습니다.
전통적인 프론트 엔드 코드는 그 자체로 로컬에서 실행 가능한 형태입니다.
그러나, 블레이저 웹 어셈블리는 실행에 필요한 파일(Webassembly 바이너리 포함)들을 프레임워크가 가지고 있는데, 서버에서 배포되는 시나리오만 지원합니다.
그냥 로컬에서 소스 코드 작성하고, 블레이저 개발 도구가 파일들을 프로덕션만 해주면, 바로 로컬에서 실행해 볼 수 있는데 말이죠. 이 경우 핫리로드도 필요 없습니다. 브라우저만 새로고침하면 되니까요.
(혹시 이렇게 하는 방법을 알고 계신 분이 있다면, 댓글 달아 주세요)
블레이저 서버
blazor.server.js
SignalR(웹소켓)을 통해 서버와 데이터를 주고 받습니다.
즉, 프로젝트에 삽입된 실행 코드는 서버에서 실행됩니다.
이는, 변수 하나라도 모두 서버에 저장되어 있음을 의미합니다.
닷넷 문서에서는 이를 "stateful"하다고 표현하는데, 상태(state)는 웹소켓이 끊어지지 않는 한 유지됩니다.
웹소켓(SignalR)의 개시부터 종료까지의 기간을 “circuit” 이라고 부르는데, 이는 웹 프로그래밍에서 일반적으로 사용되던 용어인 유저 세션, TCP/IP(Http) 세션들과 구분하기 위한 것입니다.
써킷을 기반하다 보니, 블레이저에서는 상태 관리(state management)가 중요합니다.
블레이저 (서버 스크립트) 자체는 웹소켓을 통해 서버에 보관된 상태와 실시간으로 동기화되지만, 이 상태를 바탕으로 UI 동기화는 자동으로 되지 않기 때문입니다.
이는 MVVM 에서 PropertyChanged 이벤트가 호출되지 않으면 뷰가 업데이트 되지 않는 것과 동일한 이치입니다.
그러나, 거의 대부분의 시나리오에서는 자동으로 통지되게끔 설계되었는데, 수동으로 처리해줘야 할 경우가 있습니다. 문제는, 수동 처리 케이스에 공교롭게도 인증과 관련한 케이스가 포함된다는 것이죠.
프로젝트 템플릿에 포함된 코드는 이런 부분에 관한 보완책이 있지만, 커스텀 인증을 구현하는 경우 이부분에 대한 대책을 마련하는 것이 좋습니다.
블레이저 서버 프로젝트는 Asp.Net Core의 다른 UI 프레임워크처럼, full stack 코드로 짭니다.
참고로, 전통적인 웹 프로그래밍에서는 프론트 엔드와 백엔드는 별개의 앱이기 때문에, (동일 시스템에서 실행되더라도) Http 프로토콜로 통신을 하지만, 풀스택 코드는 둘 사이에 Http 통신을 위한 코드가 존재하지 않기 때문에, 코드의 구조와 구현이 간단합니다.
프로젝트 디자인 가이드
전통적인 웹 프로그래밍 방식에서는 프론트엔드와 백엔드가 각각 작성됩니다.
여기에 익숙한 분들 중에, 블레이저 프로젝트를 생성할 때 습관적으로 웹 API 프로젝트를 생성하는 경우가 있는데, 사실 그렇게 할 필요는 없습니다.
블레이저 서버
블레이저 서버 앱은 Asp.Net Core 를 기반하는데, 이는 모체가 웹 API 프레임워크입니다.
레이저 요소를 통해 UI를 제공하는 것도, 웹 API를 통해 데이터를 제공하는 것도 단일 앱에서 구현 가능합니다.
따라서, 시스템 구조 상 반드시 필요한 경우가 아니라면, 웹 API를 추가하는 것은 설계 오류거나 자원의 낭비일 확률이 높습니다.
블레이저 웹어셈블리
웹어셈블리 프로젝트와 웹API 프로젝트를 결합하는 경우도 있는데, 웹 어셈블리의 코드의 테스트 목적이 아니라면, 블레이저 서버를 선택해서 풀스택으로 개발하는 게 더 효율적입니다.
블레이저 웹어셈블리는 이미 운영 중인 백엔드나 API에 접속하기 위한 프론트 엔드를 작성할 때 가장 적합합니다. 즉, 닷넷이 가장 빈약했던 분야인 프론트 엔드를 위한 기술입니다.
한계
현대 프로그래밍에서 웹의 비중은 누구도 무시하지 못합니다.
아시다시피, 웹 프로그래밍은 프론트엔드와 백엔드로 구별됩니다.
그런데, 백엔드 서비스나 클라우드 서비스들이 클릭 몇 번으로 백엔드를 구성하고 운영할 수 있도록 발전하고 있습니다. 거기에 점점 저렴해지기까지 하고 있죠.
이러한 환경은 백엔드를 자체 개발하는데 소요되는 기회 비용을 높여 놨고, 그 결과로 벡엔드 기술의 수요 또한 줄어 들었다고 할 수 있습니다. 여담이지만, 그 결과로 그 많던 소비자 용 워크스테이션들이 사라졌겠죠.
그런데, 닷넷은 이러한 환경에 반하는 풀스택 웹앱 도구에 집중해 왔고 이러한 경향은 블레이저 서버까지 유지되어 왔고, 앞으로도 계속 될 것 같습니다.
즉, 인기가 없는 개발 방식을 위한 개발 도구에 집중하고 있는 것이죠.
VS, 윈도우, SQL 서버 등을 팔아야 하기에.
여기에, 프론트 엔드 기술을 등한 시 해왔습니다. 그나마, 이제 막 블레이저 웹어셈블리가 나왔지만, 웹어셈블리를 기반하기에 초기 로딩 시간이 길어 사용자 경험이 좋지 못합니다. 요즘 같은 세상에 로딩 다이얼이라니…
물론, 레이지 로딩과 같은 보충 기술이 있으나, 보충은 보충일 뿐, 전통적인 프론트 엔드의 성능에 비빌 수준은 아닙니다.
닷넷의 풀스택은 비싸고, 프론트 엔드는 사용자 경험이 좋지 못하다는 약점이 있습니다.
닷넷이 풀스택에 대한 집착을 버리고, 좀 더 경쟁력 있는 프론트 엔드 기술을 발표하지 않는 한 닷넷의 전반적인 부진은 개선되지 않을 것입니다.
만약, 닷넷이 전통적인 프론트 엔드의 약점 - 낮은 시스템 자원 활용 능력 - 을 보완해주기만 한다면, 정말 매력적인 도구가 되지 않을까 합니다.