01-Why Nestjs
引言
我真的很爱Nestjs,那是一种很纯粹、很理性的爱,四年了,我每天都在用它......哦,不对,是我们都在用它。
四年前,在那场剑拔弩张的技术选型会议上,经过十几轮Battle,楼主力排众议将Nestjs推向边缘计算平台的大舞台....
Why NestJs?
屏幕前的你或许也参与过技术选型,搞软件开发技术选型无非就是下面列举的,老哥们看看你们属于第几种?
单枪匹马梭哈型
不超过5人、规模非常小的技术型公司(公司地址大多是某公寓1号楼1单元7层404室),你作为其中一员多面手,承担了软件生命周期的全过程管理角色.....选哪个技术,你说了算.
唇枪舌战battle型
楼主所在的公司稳坐某行业的头把交椅,公司内部开发人员无论从数量和成分来说都相当之复杂,可谓是各路武林好汉聚集,每个人都一身绝活....
有一众干了几十年驱动协议开发的C++大伯、信奉Spring为天下第一框架的Java爱好者,当然还包含一批学了几天Nodejs就自封为全栈的前端开发者....在这样的公司,做任何的技术选型,都会得罪人。很多时候,还没等你开口,就有人反对.......
对,你没看错,这种团队里是没有一言堂。那楼主作为团队里唯一一名具备Java、Nodejs、C++(大学期间研究过几个月)、前端这4种技术栈的全能型储备总工(好吧,还有一个已经服役了20年的正式总工)
借助自己与生俱来的胆识力、智慧力、表达力,以及对人情世故的拿捏,通过下面几个维度的数据分析,成功碾压说服了他们...
资源占用
楼主参与的是大型的分布式边缘计算平台,边缘计算两大特点:计算快、资源占用少。我们开发的服务不仅要能运行在云端,要必须支持在内存不到8G的设备盒子里,你们知道现在JAVA程序有多大吗?但凡是跟Spring家族沾点边的,起步1个G内存....
下图是我们用Nestjs开发的A服务和用Springboot开发的B服务的资源对比(A比B服务业务更复杂,代码量更大)
虽然,我真的很爱Java,楼主现在具备的编码思想、设计理念很多都是Java给予我的,但是我们做技术的,尤其是我这种总工级别(储备型嘿嘿),理性与合理是我们头上的一把刀,时刻约束着我。
业务分析
在我们平台内包含了非常多的服务,真正提供边缘计算能力的服务我们选的是C++这种更底层、计算效率更高、资源占用更少的语言,而剩余的无状态管理类服务对计算能力要求不高,更多的是操作系统IO的读写。
Nodejs这门语言就特别适合做无状态、IO读写、少量计算型后台服务的开发。楼主曾经实测,2核CPU、4G内存的资源背景下,一个Nodejs进程(叫服务也可以)读数据库并响应给客户端这么一个简单的场景,吞吐量可达到XXX次....这是何等的卧槽....
注意:这里出现了几个关键词,计算型服务、无状态服务、操作系统IO、吞吐量(详见本文后面的码农集合)
人情世故
有人的地方就有江湖,有程序员的地方就有鄙视链。这句话不是我说的,我也是听别人说的。
通过上面2项的分析,Nodejs已经全方位碾压了Java语言。虽然楼主公司的程序员都是自认为能发明框架的牛逼人物,但是“时间紧、任务重”,这6个字我想屏幕前的你肯定不陌生。
楼主必须选一个合适的Nodejs框架,来提升团队开发的效率、可维护性,再加一些人情世故。其实,楼主大可以选择Express这个好像最流行的框架,为什么?因为它流行啊。可是,我们毕竟是一个团队,团队开发一开始就必须把规范和约束制定好
Nestjs相对Express,在规范约束方面大出一个Vue.....为啥?因为...还是看图吧,楼主的确是个喜欢画图的人...
Express有没有规范?当然也有,但是更多的是属于文档约定规范。约定式的规范就会有人不遵守,而框架自身规范,好吧,你不遵守的话,你代码都跑不起来。
不可否认JS语言非常灵活,比如下面这段非常飘逸的代码:
javascript
代码解读
复制代码
function getMen(response){
let arr=[];
let obj = response.data;
let user = obj.user;
user.forEach((j)=>{
if(j.sex == 1){
arr.push(j)
}
})
return arr;
}
楼主凭借十几年的经验,大概能猜到arr里面的数据,但是具体包含哪些字段,可能只有写代码的老哥自己知道,这段代码如果不运行,神仙都不知道arr是个什么鬼?
这也是为什么很多JAVA、C++程序员不喜欢JS的原因,因为太黑盒了....但是,Typescript来了!!!
当我在技术选型会上秀出下面的代码时,大家都直呼卧槽,这不就是JAVA写代码的方式吗?
javascript
代码解读
复制代码
type MyResponse={
data:Obj
}
type Obj = {
user:Array<User>;
};
type User={
sex:UserSex,
age:number,
name:string
};
enum UserSex{
man=1,
women=2
};
function getMen(response:MyResponse):Array<User>{
let arr:Array<User>=[];
let obj = response.data;
let user = obj.user;
user.forEach((j)=>{
if(j.sex == 1){
arr.push(j)
}
})
return arr;
}
尤其是下面的代码出现的时候,甚至有人流出来激动的泪水,特么不就是Springboot么?哥,听你的,就选Nestjs
typescript
代码解读
复制代码
@Controller('users')
class UserController{
@Get()
async getAll(){
return [];
}
}
看到这里,很多从前端转过来的同学可能会比较懵逼,你听哥一句话:不怕。有些人可能还去专门学习typescript之类的,我告诉你,根本不用!你就关注我,我会在潜移默化中让你掌握typescript。
至于代码里面的 “@Controller”,好吧,你们经常群里是不是会 @XXX
懂了吗,就是提醒Controller这个人,请注意查收群消息,有个叫users的来了,把它登记下.....
结语
好了各位朋友,你们今天能看到这篇文章,其实应该感谢我的一位同事XX,接下来我会用时序图来还原下整个事件,没错,这就是我个人的写作风格,关注我,你会发现你的设计能力、编码规范、画图能力,甚至包含英语都会全方面的提升.
码农集合
欢迎大家来到码农集合,作为惯例,楼主会在每篇文章的末尾给各位补充一些软件行业的小知识,我会用图形化的方式将复杂的事情给你讲明白,好了,let's get started!
计算型服务 VS IO密集型服务
首先,屏幕前的你接触的99%的后端服务都属于IO密集型或者说IO型居多,你都谈不上密集。
所谓IO就是操作系统的输入input和输出output,操作系统里面所有磁盘上文件的读写、网络数据的传输都属于IO行为。
举个例子,你用nodejs封装了一个方法,该方法打印你本地电脑F盘的“精选图片”。这就是IO操作
typescript
代码解读
复制代码
//示意代码
const fs = require('fs');
fs.readdir('F:/精选图片', (err, files) => {
if (err) throw err;
console.log(files);
});
既然气氛已经烘托到这了,我就顺道给大家讲一下Nodejs的IO是怎么实现的,其实非常简单。请看下图:
如果你能看懂上面这张图,那么下面Nodejs官方给出的架构图,你也就理解了
屏幕前的你,学到了吗?是不是很好理解
无状态服务 VS 有状态服务
说到状态,我拿DOTA这个游戏来举例(LOL游戏也适用):
请问,1分钟恢复之后,你现在几级?什么装备?如果DOTA服务器是有状态服务,那么当恢复后,你的装备与等级与崩溃前保持一致,如果是无状态,好吧,你白玩了10分钟....
但是,你们接触到的90%的后端服务都属于无状态服务,数据都持久化存储在磁盘上(数据库、文件等),如果服务突然挂掉,客户端调用服务接口无非是无法连接而已
吞吐量
吞就是吸进去input,吐就是吐出去output。吞吐量一般来说衡量某个后端服务单位时间能处理的业务量。各位都开车走过高速公路吧,看看下图你就明白了:
同时刻有6辆车,但是理论上实际只能每秒过3辆车
好了,各位老铁,我真的累了,一口气写了这么多,不知道你们是否喜欢“码农集合”这个扩展板块,如果喜欢,请留言给我,我会继续在后续文章里给大家多讲讲这些理论,带你们多见见世面....ok
作者:秦人阿超
链接:juejin.cn/post/738965…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。