全栈开发应该更容易
简化堆栈
联络
结论
一开始,我们只有全栈开发人员。我们用一些PHP或Ruby On Rails在后端实现了所有功能,然后在前端运行一些jQuery ,这样就完成了。
但时代变了。现代 Web 应用需要丰富的用户界面,而这些界面已无法再在后端渲染。
因此,我们切换到“单页应用程序”模型,其中前端完全管理用户界面。
至于后端,它被简化了,因为它只需要管理领域模型和业务逻辑。
问题是我们现在必须连接前端和后端,而这正是事情变得复杂的地方。
我们构建了一个 Web API(REST、GraphQL等),这显著增加了我们的代码大小并导致重复我们的域模型。
实际上,这就像构建两个应用程序而不是一个。
因此,我们增加了开发人员的数量,由于整体复杂性,我们将他们分为前端开发人员和后端开发人员。
如果你是半栈开发人员,你只能做一半的工作,并且要花很多时间与负责另一半的人沟通。
如果你是一名全栈开发者,那你就是真正的英雄。你可以用更高效、更令人满意的方式,从头到尾实现一个功能。
划分前端和后端开发人员会降低生产力并破坏所有的乐趣。
但说实话,如今成为一名全栈开发人员实在太难了。
理想情况下,我们应该像最初那样,全部采用全栈架构。但要做到这一点,我们需要大幅简化整个架构。
简化堆栈
对于最简单的项目,可以使用“无后端”解决方案,例如Parse、Firebase或Amplify。但是,当业务逻辑超出 CRUD 操作范围时,效果就不太好了。
八年前,一个名为Meteor的项目问世了(这在软件工程领域可谓是永恒)。它的主要理念是简化前后端之间的通信,在当时颇具革命性。可惜的是,这个项目已经过时了,已经不再适合如今的环境。
最近,两个项目引起了热议——RedwoodJS和Blitz.js 。它们都致力于简化前后端之间的通信,但方法有所不同。
RedwoodJS 简化了 GraphQL API 的实现,并将React和Prisma整合在一个自以为是的框架中。
Blitz.js 也是一个使用 React 和 Prisma 的框架,但它基于Next.js构建,并致力于消除对 Web API 的需求。
这些项目正朝着正确的方向发展——简化全栈应用程序的开发——我希望它们能够成功。
但让我介绍一下我在这个领域的尝试——一个名为Liaison的项目,我已经做了一年半了。
联络
我创建 Liaison 时怀着一种执念 — — 尽可能地扁平化堆栈。
典型的堆栈由六层组成:数据访问、后端模型、API 服务器、API 客户端、前端模型和用户界面。
通过 Liaison,堆栈可以被视为重新统一前端和后端的单一逻辑层。
问题在于,每一层都会导致更多的代码分散、知识重复、样板和意外的复杂性。
Liaison 通过允许您在单个逻辑层中组装应用程序来解决此问题。
跨层继承
使用 Liaison,可以从后端继承前端。它的工作方式类似于常规的类继承,但跨越了在不同环境中运行的层。
从物理上讲,我们仍然有单独的前端和后端,但从逻辑上讲,我们得到了一个统一整个应用程序的单层。
当从继承自后端类的前端类调用方法时,执行发生在方法实现的位置——在前端还是后端——对于方法的使用者来说并不重要。执行环境被抽象了。
让我们看看使用 Liaison 后,全栈“Hello, World!”会是什么样子。
首先,这是后端:
import {Component, attribute, method, expose} from '@liaison/component';
import {ComponentHTTPServer} from '@liaison/component-http-server';
class Greeter extends Component {
@expose({set: true}) @attribute() name = 'World';
@expose({call: true}) @method() async hello() {
return `Hello, ${this.name}!`;
}
}
const server = new ComponentHTTPServer(Greeter, {port: 3210});
server.start();
这是前端:
import {ComponentHTTPClient} from '@liaison/component-http-client';
const client = new ComponentHTTPClient('http://localhost:3210');
const Greeter = await client.getComponent();
const greeter = new Greeter({name: 'Steve'});
console.log(await greeter.hello());
注意:本文重点介绍堆栈的架构方面,因此如果您不完全理解代码,请不要担心。
在前端运行时,hello()
会调用该方法,而在后端执行则可以看作是一个实现细节。
前端的类Greeter
的行为与常规 JavaScript 类类似,并且可以扩展。例如,我们可以hello()
像这样重写该方法:
class ExtendedGreeter extends Greeter {
async hello() {
return (await super.hello()).toUpperCase();
}
}
现在,当hello()
方法被调用时,执行会在前端和后端同时发生。但同样,执行发生的位置可以看作是一个实现细节。
从开发人员的角度来看,前端和后端是一个整体,这使得一切变得更容易。
数据持久性
大多数应用程序都需要存储数据,而这里的事情也可以大大简化。
这个想法并不新鲜,数据库可以用ORM抽象出来,而这正是 Liaison 所遵循的方法。
简而言之,Storable()
mixin 为你的数据带来了持久性。例如,以下类:
import {Component} from '@liaison/component';
import {Storable, primaryIdentifier, attribute} from '@liaison/storable';
class Movie extends Storable(Component) {
@primaryIdentifier() id;
@attribute() title;
}
要创建并保存Movie
,您可以执行以下操作:
const movie = new Movie({title: 'Inception');
await movie.save();
要检索现有的Movie
,您可以执行以下操作:
const movie = await Movie.get({id: 'abc123'});
再次强调,这里没有什么新东西,它类似于任何使用活动记录模式的 ORM 。
Liaison 的不同之处在于,ORM 不再局限于后端。跨层继承机制使得 ORM 也可以在前端使用。
因此,从概念上讲,我们仍然有一个结合前端、后端和数据库的单一逻辑层。
用户界面
在典型的应用程序中,用户界面和领域模型是完全分离的。几年前,这样做是有充分理由的,因为用户界面本质上是由命令式代码构成的。但现在我们有了一些函数式 UI 库(例如带有 hooks 的 React),将用户界面和领域模型结合起来成为可能。
Liaison 允许您将路线和视图作为模型的方法来实现。
以下是如何定义路线的示例:
import {Component} from '@liaison/component';
import {Routable, route} from '@liaison/routable';
class Movie extends Routable(Component) {
@route('/movies') static List() {
// Display all the movies...
}
@route('/movies/:id') static Item({id}) {
// Display a specific movie...
}
}
如您所见,路由只是与模型方法相关联的 URL。
以下是如何实现视图:
import {Component, attribute} from '@liaison/component';
import React from 'react';
import {view} from '@liaison/react-integration';
class Movie extends Component {
@attribute() title;
@attribute() year;
@attribute() country;
@view() Home() {
return (
<div>
<this.Heading />
<this.Details />
</div>
);
}
@view() Heading() {
return (
<h3>
{this.title} ({this.year})
</h3>
);
}
@view() Details() {
return <div>Country: {this.country}</div>;
}
}
视图只是一种根据模型的属性返回某些内容的方法,返回用户界面元素根本不是问题。
由于视图已绑定到模型,因此您可能不需要使用状态管理器(例如Redux或MobX)。@view()
装饰器确保在属性值更改时自动重新渲染视图。
因此,我们将用户界面封装在域模型中,这样就少了一层需要担心的事情。
结论
我坚信扁平化堆栈对于使全栈开发更容易实现至关重要。
Liaison 允许您在两个物理层(前端和后端)中构建全栈应用程序,它们集中在一个逻辑层中。
使用尽可能少的层来启动一个项目会更容易,但这并不意味着您必须以这种方式构建所有项目。
对于某些项目来说,将应用程序分解成更多层可能是一个好主意。例如,将数据访问与后端模型分离,或者将用户界面与前端模型分离可能会很有用。
不用担心。跨层继承机制允许您在保持单个逻辑层的同时增加物理层。
如果你不擅长面向对象编程,Liaison 肯定不会让你喜欢。但请不要因为觉得面向对象编程的组合模型不好而拒绝它。JavaScript 类可以函数式定义(例如mixins),因此具有极强的组合性。
查看Liaison 文档,开始构建一些东西,然后让我知道您的想法。
本文最初发表于Hacker Noon。
鏂囩珷鏉ユ簮锛�https://dev.to/mvila/full-stack-development-should-be-easier-2i2p