浅谈渐进式框架

echosoar 原创发表于 2020/06/02 11:45:57
所谓渐进式,我理解它的含义主要是只做自己该做的事情,不做不该做的,能够在需要其功能的时候可以方便的插入到原有的大系统中;同时没有很强的强绑定用户的特性,比如依赖注入、装饰器等能力都可以由用户选择性使用;类似于Vue等前端框架,可以仅在页面中某一个DOM节点上面进行使用,其他的地方还可以用原有的jquery。

渐进式框架的好处

渐进式框架提供自底向上的增量开发,给用户更多的可选择项,而不是必须选项,用户可随意在原有的大系统中插入,那么就方便在原有架构体系内尝试使用新框架来解决问题,而无须担心切换框架导致的工程量和学习成本大幅度上升;同时对于框架快速拓展用户来说有很大的优势,使用户能够快速试错,仅仅几行简单的代码就能用上这个框架,能快速地得到试用反馈,如果有兴趣可以继续探索更多更高级的特性,这也能够让使用者在这个过程中逐渐的体会到其与传统编码方式的优势所在。有很多时候用户并不认可你告诉他的,他只坚信他所感受到的。
用户是有选择倾向的,有的人就是不喜欢某一种编程方式,如果一个框架仅提供了全家桶功能,大部分功能都是required,无法让用户关闭其中某些讨厌的方式,那么用户就会讨厌这个框架,大多数人并不会因为某些优势的存在而爱屋及乌,一般会殃及池鱼而选择不使用这个框架。要在任意一个方面满足一个人是很难的,但是在满足他需要的同时可以没有他不喜欢的,这相对简单。

渐进式框架是怎样的

框架概念弱化,框架类库化

midway框架所做的事情实际上是把一些class注册到IoC容器内,之所以是class是因为其注册的逻辑是通过装饰器来实现的。
其实装饰器可以认为是一个高阶函数,传入一个函数,根据函数的执行返回结果,例如:
import { 
    inject, 
    provide,
    getIoC,
    getContext,
    getResult,
    IContext
} from '@midwayjs/faas-progress';

// inject 用来加载已注册到IoC的函数,接受俩参数,IoC id 和 当前event
// provide 用来将函数注册到IoC,接受俩参数,function 和 IoC id,IoC id默认为 handler function Name

const handlerFun = async (...events /* 原始event */) => {
    
    // context上下文是根据触发器event来创建的,保证了每次请求的context隔离。
    const context = getContext(events /* or context */);
    
    // 其实这里的注入就是一个动态require过程
    // 因为是函数,没有实例化过程,inject其实就是从全局Map上面获取
    // 也可以使用 inject('ioc id', context) 的形式
    // 相当于bind 这样调用testFunc时就无需传入context
	const testFun = inject('ioc id');
    
    // 也可以用非IoC方式
    // const testFun = require('../../testFun');
    
    const result = await context.hsfClient.invoke(...);
    context.body = await result.asyncMap(res => {
    	return testFun(context, res.id);
    });
    
    // 可以使用框架提供的结果处理器,也可以自己手写
    //return getResult(context);
   
    return {
    	isBase64encoding: true,
        data: Buffer.from(JSON.stringify(context.body))
    };
};

// 使用中间件
export const handler = middleware(handlerFun, ['middlewareName']);

// 注册到ioc容器
provide(handler, 'ioc id');
当入口代码加载后,就会执行provider方法,那么就会触发全局的自动IoC索引,当所有代码均require后,那么provide其实就注册完成了。

特性强可替代性

midway的特性就是IoC,但是在渐进式编程里面这个特性应该交由用户来选择要不要使用,比如说 inject 和 provider,用户也可以不使用,而使用 import 的方式来加载函数,并没有任何问题。

框架的所有功能,包括跨平台的抹平能力都交由用户来选择是否使用,每种能力用户都可以不使用,选择其他的方式。

示例

完全使用 midway faas
import { inject, provide, getContext, getResult } from '@midwayjs/faas-progress';

const handlerFun = async (...events /* 原始event */) => {
    const context = getContext(events);
	const testFun = inject('ioc id', context);
    const result = await context.hsfClient.invoke(...);
    context.body = await result.asyncMap(res => {
    	return testFun(res.id);
    });
    return getResult(context);
};

export const handler = middleware(handlerFun, ['middlewareName']);

provide(handler, 'ioc id');
使用部分
import { getContext } from '@midwayjs/faas-progress';
import testFun from '../../testFun';
export const handler = async (...events) => {
    const context = getContext(events);
    const result = await context.hsfClient.invoke(...);
    const body = await result.asyncMap(res => {
    	return testFun(context, res.id);
    });
   	return {
    	isBase64encoding: true,
        data: Buffer.from(JSON.stringify(body))
    };
};