与其它领域相比,Web 开发更像是一个全栈化的工程,其使用的技术基本上涵盖了目前大部分应用所需。
分类
从端的职能来说,整个 Web 开发流程大致可以分为产品设计、前端、后端、测试及运维部署,其中产品设计又可以细分为功能性的需求设计和实现性的架构设计。
产品设计
产品设计是一个很重要的环节,它决定着一个产品的价值(> 价值是在价值的交换过程中得以体现的
),即其是否可以最大程度地满足市场需求。换句话说,从一开始,你需要确保开发出来的产品不是所谓的“屠龙之术”。
在进行功能性的需求设计时,要以实际需求为导向,界定产品适用范围,不应盲目追求大而全。如此,在进行后续架构抽象的时候,才能有的放矢。架构设计要充分考虑预采用技术栈的成熟性、健壮性及开发难度,力求保证产品的稳定性、易维护性、可扩展性。
前端开发
在现有 Web 生态下,无论多么新奇的前端技术,最终目的都是生成可供 Web 浏览器正确渲染的页面。让我们来简单回顾一下前端领域的发展历程(详细可参考 《 [[前端浅谈]] 》)。
最初的 Web 应用就是一个简单的页面 - http://info.cern.ch/ ,由浏览器渲染一份同样简单的 .html
文档生成。如上所述,现阶段我们可以认为前端开发的终点就是 HTML 技术。
后续发展过程中,我们使用 CSS 为 HTML 元素添加了样式,更进一步使用 JavaScript 为其添加了更加丰富的交互。
之后的所有前端概念都是围绕 HTML + CSS + JavaScript
展开的了,如封装了基础 JS API 的 jQuery、Underscore.js、Loadsh.js,又如可转译为 JavaScript 的 CoffeeScript、TypeScript,可转译为 CSS 的 Sass、Less 等等。
在 ES6 之前,JavaScript 没有原生的模块化标准(详细可参考《 [[模块化编程]] 》),但是随着前端项目复杂度的增加,其模块化的迫切性与日倶增。NodeJS 为 JavaScript 家族带来了基于 CommonJS 规范的模块化方法,但是它是运行在 Node 平台中的,并不能直接被浏览器使用。老规矩,转译,最终目的生成浏览器引擎可以直接解析的 JavaScript 。Grunt、Browserify、Gulp、Webpack 等一系列流程管理、打包工具及其配套的插件生态就是干这个的。甚至于后来将样式文件,图片等静态资源文件也抽象化成了模块,一股脑地全塞在了里面。
开发者们是永不满足的,因为懒,Angluar、React、Vue 等响应式框架开始涌现,并在短时间内受到人们的广泛推崇。再然后,好像就没什么新鲜事儿了,其实本来也不是多新鲜的事儿。
所有的一切都开始于 HTML + CSS + JavaScript
,经过一翻折腾,最终又回到了原点而已。折腾当然不是白费的,它极大程度提高了开发者们的效率和热情,降低了项目开发的难度,使项目运行稳定且易于维护。
后端开发
前端和后端是怎么界定的呢?
早期的 Web 开发领域,用户通过浏览器访问某个站点,浏览器通过用户的请求从相应服务器获取网页文件并渲染出来。所有的资源都是放在服务器端的,只是在用户请求的时候,通过网络传递过去。浏览器作为客户端,某个角度来说其本身并不是 Web 开发的产品,它只是 Web 产品得以呈现的平台宿主。
如前所述,随着页面的复杂度越来越高,便分离出来了专门编辑页面的开发人员(虽然最初的时候往往是由同一个开发者兼职)。开发响应服务的人员通过某种方式识别编辑好的页面模板,将必要的信息(数据)注入到模板中,最终转译为浏览器可识别的页面文件,供用户请求。
再后来,AJAX 异步请求诞生了,用户可以通过局部更新页面来获取自己想要的信息了。现在,大体流程变成了下面这样。
用户在初次请求的时候,从服务器端获取到足够的页面文件,并将相关的资源存储在客户端,如此,在不需要从服务端获取新的信息数据的时候,整个交互过程都只是发生在客户端了。不需要通过网络传递信息数据,自然也就不需要网络了,我们可以称之为可离线使用的 Web 应用。
当客户端页面需要更新的数据的时候,我们并不需要重新从服务器端获取页面文件,只需要拿到必需的数据(目前多以 JSON 格式传递),并在客户端更新页面即可。
如此,现代后端(前后端分离后)的职能渐渐明确了 - 为客户端提供所需的信息数据。
通常情况下,后端开发人员通过网络或其他方式获取到客户端请求,通过一系列方式解析请求,转发请求到相应的处理逻辑,并将最终处理好的数据响应给客户端,便完成了整个过程。问题来了,如下:
- 通过什么方式解析请求?
- 如何转发请求到相应的处理逻辑?
- 怎么编写相关的处理逻辑程序?
- 数据都存储在哪儿?
- 如何传递数据?
- ……
我们以常见的后端开发来描述一下大体的过程。客户端(用户)发来的请求,由 Nginx 统一接收(此时 Nginx 便是服务端代理,也就是所谓的反向代理),部分静态资源直接响应给客户端,动态资源则转发给相应的服务端程序(如 Tomcat)来处理。
正向、反向,都是从用户的角度出发来看的。
不妨就以 Tomcat 来举例,其支持运行适配相应版本 Servlet API 的 Java Servlet 程序,用以接收处理转发自 Nginx 的请求。是的,核心的服务端面程序逻辑都是写在 Servlet 中的。Servlet 负责接收请求,并从数据库获取相应数据,最终生成客户端请求所需的数据,响应给客户端。
前端有一系列针对 HTML + CSS + JavaScript
的“魔改”,后端也出不了这个圈,Spring 家族生态就是干这个活的。我们不需要自己去编写一个又一个的 Servlet 程序,只需要关注具体的处理逻辑就好了,Spring 最终会动态生成 Servlet 程序供 Tomcat 使用。
Spring 的核心是什么?IoC(控制反转)和依赖注入。不要被这些陌生的抽象名词吓到了,其本质不过是把本来需要开发者手动维护的模块体系全部交由 Spring 去动态完成罢了。
看,无论是直接编写 Servlet ,还是通过 Spring ,亦或是其他方式生成 Servlet ,最终都会回归到响应基本的信息数据这一点。
测试及运维部署
接口测试多数是由开发人员通过编写测试代码完成的。这里的测试,主要是指功能性测试,即产品应用整体是否达到了设计要求,是否运行稳定。
一切都没有问题,就由运维人员部署到指定的服务器上,运行发布。
总结
纵观 Web 开发的技术分支多如牛毛,但其核心本质不过了了。我们要抓住本质,去理解、把握主要技术栈的实现原理,才能更好地了解现存技术,面对或是开发新的技术栈。