Express를 사용해야 할 이유 (1) - 생태계 조사

잠시나마 사용해본 Express는 내게 React 같았다. 무엇이든 할 수 있어 보였으나 직접 하기에는 매우 불편하고, 그러다보니 REST API를 작성할 때 이런 것까지 해야 돼? 혹은 이런 기능이 없어서 불편하네 등이 많았는데 이번에 알아보려고 한다. 얼마나 많이 Express를 사용하며, 왜 Express를 사용하는지 팩트 위주로 체크해봤다.


1. Node와 Express의 장점을 헷갈리면 안 된다.

대부분의 웹사이트에서 소개하는 Express의 장점들은 Javascript, Node.js의 장점들이었다. 많은 글을 읽어보아도 Express의 장점을 소개하는 글은 많이 없었고 대부분 Node.js의 장점을 소개하고 있었다.

Express가 Node 기반인 게 큰 장점이라는 걸까… 그래서 Node.js와 같은 목적으로 생성된 프레임워크/런타임을 조사해보았다.


2. Reactor Pattern을 구현한 프레임워크/런타임

A. 역시 Node.js만 있는 것은 아니었다. Javascript를 깊게 배우고 생태계를 옮겨 탈 바에 기존에 사용하던 언어로 작업하는 게 현실적이긴하다.

Lang Sync Framework Async Framework
Java Spring Web MVC Spring WebFlux (Reactor Pattern), Vert.x (JVM 기반)
Python Flask, Django FastAPI, Tornado, Sanic, … (꽤 많다.)
Javascript - *

다른 언어에 대해선 찾아보지 않았지만 Java, Python이 점유율이 큰 언어들이므로 충분하다고 생각한다. 벤치마크를 찾아보진 않았지만 같은 패턴을 기반으로 제작됐기 때문에 실제 서비스로 구현했을 땐 성능 면에서도 비슷할 것으로 예상된다.

다만 Node.js의 장점이라면, 선천적으로 비동기 API가 장려되어왔기 때문에 비동기 API로 작성된 라이브러리 활용 면에서 낫지 않을까 생각한다.

Spring Web Flux 구조 - Node.js EventLoop과 유사

출처:


3. Node.js 백엔드 프레임워크 간의 점유율/만족도 비교

제대로 비교하기 전에 통계 자료부터 확인하자.


점유율 요약 (아래 그림):

  • Express의 점유율이 압도적이다.
  • Koa, Hapi 라는 네임드의 점유율이 꽤 낮다.
  • 서비스 개발에 가장 유리할 거라고 생각했던 Nest.js의 점유율이 13%밖에 안돼서 의문이다.

2020 점유율 순위

Hapi Koa Nest Express

물론 Express를 기반으로 하는 다른 프레임워크 등이 어느 정도 반영됐을 것이긴 하다. Nest도 처음에는 Express 기반이었으니까. 그래도 다운로드 수의 큰 차이를 보면 나머지 프레임워크의 시장성이 의심되긴 한다.


만족도 비교 (아래 그림):

  • Express는 점유율에 이어 만족도도 최상위권이다.
  • Nest.js가 5% point 정도의 차이가 있지만 준수한 편이다.
  • Koa의 만족도가 76%인 점인 이유는 장점이었던 동기식 코딩 방식인 async-await이 표준화됐기 때문임으로 보인다.
  • Hapi는 만족도가 매우 낮은 것으로 보아 사용할 수 없겠다는 생각이 들었다. (추후 조사를 해봐야겠다.)

2020 만족도 순위

출처: 2020 State Of JS (한국어 번역)


4. 왜 이렇게 Express를 많이 쓰는 걸까?

정말 Express가 좋은걸까?

다른 언어의 프레임워크를 비교해봤을 때 솔직히 좋다고 하진 못 할것 같다.


1. 단순함 (+0)

정말 많은 블로그에서 Express의 최장점을 단순함으로 꼽고 있었는데 장점보다는 목적에 가까운 것이라 생각한다. 목표에 따라 단순함은 장점이 될 수도, 단점이 될 수도 있기 때문이다. 단순함을 장점으로 꼽는 경우 둘 중 하나이다.

  • Rich Framework를 감당할 만큼 숙련된 개발자로 채우기 어려운 조직이거나
  • 애초에 큰 규모의 서비스를 작성하기 위해 Express를 사용하지 않거나

만약 서비스 개발을 위해 Express를 사용한다면 단순함은 직접적인 단점이 된다.

  • 기본적인 의존성만 담은 Boilerplate(1.4k stars)만 보더라도 같이 깔아야 할 라이브러리들이 많아 학습 곡선이 가팔라진다.

  • 처음 입문하는 경우 미들웨어들을 직접 찾는 추가적인 일을 하게 된다. (한 프레임워크 내에서 찾는 것과 대조적.)

  • Rich Framework 들에 비해 설계를 너무 근본적인 것들부터 해야 해 오히려 설계 측면에선 난도가 높다. (DI/IOC가 없고 여러 라이브러리를 비교 분석 후 사용해야 함.)

다만 적절한 Boilerplate를 찾으면 이 문제가 어느 정도 해소된다는 점과 이후 단락에서 소개할 내용들을 통해 단순함의 단점을 상쇄할 수 있다.

Node.js는 출시 후 아직까지도 작은 서비스를 만드는 데 적합하다는, 프로토 타이핑 위주라는 인식이 남아 있는 것 같고, 그런 용도로 채택하여 단순함이 종종 장점이 되는 것 같기도 하다.


2. Express Middleware (+0)

어떤 언어, 프레임워크로 웹 개발을 하더라도 Express에 미들웨어에 해당하는 계층에서 확장성을 가져가는 것은 기본이지 특별한 기능은 아니다. 또한 Express에서 제공하던 자체 Middleware들은 모두 Connect 미들웨어 라이브러리옮겨갔다. Next.js에서는 이 미들웨어들을 지원하는데, 그럼 다른 프레임워크에서도 의도하기만 하면 재사용 할 수 있는 셈이다. (의존성이 req, res, next 인자 밖에 없으니.)


3. Community (+3)

Express는 꽤 많은 사용자 풀을 보유하고 있다. 이미 사용자가 많아 검색을 통한 문제 해결이 비교적 원활하다.

아래는 StackOverFlow 트렌드인데 koa(js), hapi(js)는 태그로 잡히지도 않아서 비교가 불가능했다. 이는 생태계 조성이 거의 전무하다는 뜻인데 koa나 hapi는 출시된 지 시간이 지났음에도 이정도이며 특히 Hapi는 정말 작은 사용자 풀을 보여준다(사용하지 마세요).

StackOverFlow Trends: Express vs Nest vs Next


4. Async-await을 workaround로 쓸 수 있다. (+1)

Express v5 부터는 Response Handler 및 Middleware에서 async/await을 사용할 수 있지만 아직 Release 되지 않은 관계로 사용할 수는 없다.

Express QnA 이슈의 답변이다.

Q. How to use async/await in express 5?

A: There is one main difference between v4 and v5 when it comes to async/await and promises in general. In v5, if you return a promise from a response handler (or middleware), if that promise rejects and is not handled elsewhere, then Express will handle the error. It handles the rejection by passing the rejection reason to next for you.

v4에서도 async-await을 쓸 수 있는데, 아주 간단한 미들웨어 express-async-handler로 한 번 감싸주면 된다. (원리는 이 설명 참고) (같은 원리로 Promise도 처리 가능)

1
2
3
4
5
6
7
8
9
10
11
12
13
// find a user by id
router.get(
'/:id',
asyncHandler(async (req, res) => {
if (req.user.id === req.params.id) {
return res.status(403).send(FORBIDDEN);
}
const user = await UserRepository.findUserById(req.params.id);
if (!user) return res.status(404).send(NOT_FOUND);

res.json(user);
}),
);

5. Koa나 Express나 둘 다 개발은 하지 않는다. (+0)

Koa나 Express나 발전을 멈춘지 좀 됐다.

KoaJS는 2013년에 시작해 제너레이터 기반으로 미들웨어를 쉽게 작성하기 위해 나온 프레임워크인데, async-await 표준이 2017년 초부터 Node.js에서 공식적으로 지원되면서 그 의미가 퇴색되지 않았나 생각이 든다.

Express 역시 Documentation 위주의 유지보수, v5를 6-7년 째 안 내고 있긴 하다. (14, 15년도 쯤까지만 일한듯)


5. 서비스 개발 측면에선 NestJs가 더 낫지 않을까? (추후 보강 예정)

Express, Koa는 현재 사실상 유지보수가 되고 있지 않다. 프로젝트에서 돈을 벌지 못하기 때문인 것으로 보이는데, 기업 스폰서가 없으며 프레임워크도 간단해 기술 지원이 불가능해 수익 모델이 없다. (Hapi는 Walmart에서 사용 중이긴 하지만 너무 마이너하다. 왜 인기가 없을까?)

NestJS는 구조가 Angular의 영향을 받았다고 돼있지만 Spring과 유사한 구조와 개발자 경험을 제공한다고 생각하며, Spring은 그 기능과 복잡성을 통해 기술 지원으로 돈을 벌고 있기 때문에 NestJS가 이 모델을 구현한다면 긴 시간 유지보수를 해나갈 수 있을 것 같다.


정확히 무슨 벤치마크를 했는진 모르겠지만 성능 측면에서 NestJs-Fasitfy[현재 버전]가 Express보다 낫다고 한다. (출처)

Framework Req/sec Trans/sec Req/sec DIFF Trans/sec DIFF
Nest-Express 15370 3.17MB +4.38% +4.23%
Nest-Fastify 30001 4.38MB +2.20% +2.23%
Express 17208 3.53MB +8.38% +8.31%
Fastify 33578 4.87MB +6.55% +6.53%

NestJS에 대해선 추후 더 조사하려고 한다.


TODO

1. NestJS

NestJS는 다루는 양이 방대하기도 하고 앞의 리서치에서 시간을 너무 많이 사용해서 따로 시간을 내서 리서치하진 못 해서 다음 기회에 꼭 하도록 한다.

2. Fasify

한 번 조사해봐야 할 것 같다. async-await도 지원하며 제대로 관리되고 있는 것 같다.

아래는 README에 게시된 벤치마크인데 성능도 역시 좋고.

Framework Version Router? Requests/sec
Express 4.17.1 15,978
hapi 19.1.0 45,815
Restify 8.5.1 49,279
Koa 2.13.0 54,848
Fastify 3.0.0 78,956
-
http.Server 12.18.2 70,380

3. HapiJS

Hapi도 개발이 계속 진행 중이고 Nest처럼 Rich한 Framework를 목표로 하는 것 같고, Walmart에서 실제로 사용하면서 주도적으로 개발하다가 작년 중순부터 Community-driven으로 간다고 한다. 성장 가능성이 꽤 있는 것 같아서 시간이 나면 조사하면 좋을 것 같다. Facebook이 React를 만들어 프론트엔드 생태계를 많이 바꿔낸 것처럼.

4. Express In Action (2016)

이 책을 좀 더 읽어보고 Express의 가치를 발견하다면 정말 좋을 것 같다.

5. 기타

Promise, Async-await이 성능이 CPS 패턴에 비해 느리다는 의견이 종종 나왔는데 왜 그런지 확인해보기

D2에서 Node.js는 Socket.IO 때문에 떴다고 하던데 정말인지 확인해보기

Express를 사용해야 할 이유 (1) - 생태계 조사

https://jsqna.com/ejs-1-why-express/

Author

Seongbin Kim

Posted on

21-01-19

Updated on

21-02-02

Licensed under

댓글