vlambda博客
学习文章列表

Java业务代码脚本引擎JAVS项目简介

一、背景

1.1 缘起

在天画-codeMaker的V3预览版的开发任务中,有几个任务是与细化代码生成相关的,比如在调用时序图中增加if,else,for循环等程序控制语句,基于Java语法构建生成。但是实际上经过一段时间调研之后在调用时序图中增加这些无疑会导致整个调用时序图变得混乱,同时充斥着各种细枝末节,这种构建方式还不如手写代码来的快。所以在调用时序图中快速细化相关的核心逻辑将变得非常困难。因而需要找到一个更好的方式来在代码编写前进行核心代码流程的设计,在需要的时候细化,不需要的时候构建粗粒度的逻辑即可。因此我在构建细粒度版本的plantUML 调用时序图文档的过程中得到了一些灵感,何不如把时序图里的调用元素全部去掉用伪代码的方式来来表达工程代码方法内部的核心逻辑呢?于是就慢慢构建出了Javs。

1.2 命名

在模拟构建了一段时间之后,我准备给这个项目起一个新的名字,要求要简洁而且够酷,另外就是跟java有关。所以就找到了关于贾维斯的描述: 比喻智能,贾维斯(J.A.R.V.I.S.)是美国漫威漫画旗下人工智能。全称为Just A Rather Very Intelligent System(只是一个相当聪明的智能系统) 这里就简化了下命名为Javs。当然其本质上的全名也可以是JavsScript。相当于Java的JavaScript。这么命名当然也不想去蹭什么热点或者搞什么噱头,所以我还是希望它叫Javs。未来如果厉害了JavsScript可能就是它的大名了。

1.3 意义

我初步构建这个项目的时候首先是觉得这肯定很有趣,也很酷,所以也搜了下编译器相关的内容比如LLVM或者Clang等。但是目前还想不了这么远,Javs当前还处于很初级的阶段。当然对别人来说这可能没有什么意义或者有点不切实际,但是我觉得如果很有趣的话倒不妨了解下。

二、需求与价值

2.1 需求

构建出Javs并不是空穴来风,所以其在规划阶段要解决的就是核心方法内部的生成逻辑,同时基于简单的语法定义来构建出业务流程在伪代码文档上的体现。

2.2 设计价值

在构建过程中发现Javs可以做下面的一些事情,所以这里简单梳理了下:

  1. 伪代码描述核心业务服务执行流程
  2. 辅助天画-codeMaker细化代码生成
  3. 方便并行开发
  4. 面向文档编程,文档即代码
  5. 精简Java原生代码的繁琐设计
  6. 架构师资深开发辅助设计核心代码逻辑

三、设计理念

3.1 以模型为中心

初步构建Javs引擎的时候也查阅了面向模型编程的一些文章,同时面向模型编程也有很多工具框架,另外就是与DDD和编程思想有关了。这里不说这么多,而是让Javs通过PlantUML 领域模型文档来编写文档中定义的方法内容。至于方法内容需要的实体,服务,数据都是由模型来进行引用。举个例子如下:

  1. plantUML DOC内容:
  2. Javs内容
func saveOrder(bo){
    do = bo.convertdo   //用bo引用BODOConvert转换接口(mapstruct实现)
    row = do.mapper.insert()  //do代表OrderDO,既数据库实体对象,让do引用mapper资源,然后引用insert方法
    return row == 1;   //这里是直接用Java原生语法来编写的,区别在于是否有;,如果用Javs语法来表达的话就是下面的内容:
    //ret row == 1
}
  1. Java内容
public Boolean saveOrder(OrderBO orderBO){
    OrderDO orderDO = OrderConvert.getInstance().bo2do(orderBO);
    int row = orderMapper.insert(orderDO);
    return row == 1;
}

从上面可以看到Javs对整个函数命名进行了一些简化,所以Javs用领域模型文档当作蓝图来编写方法伪代码的。更核心的内容就是让模型去主动引用其他Mapper,Factory,Service类,那么我们的核心业务流程在每个类方法中都可以表达出来而不受制于Java语法的限制,命名上也减少很多心智负担。

3.2 简洁的语法

Javs在语法方面确实主要是参考Java的,当然也简单看了下其他语法规则或者关键字。Javs在语法上的精简还是希望开发者敲最少的代码,表达最合适的业务语意。下面通过一个小小的案例来看一下,如下PlantUML类图:对应的Javs代码如下:

func add(a,b){
   ifnull(a){
        return b;
   }
   ifnull(b){
      return a;
   }
   return a + b;
}

func decrease(a,b){
   ret  a - b
}


func join(a,b){
   ifempty(a){
       return b;
   }
   ifempty(b){
       return a;
   }
   ret a + b
}



func  mult(bo){
    ifnull(bo.first){
       ret bo.second
    }
    ifnull(bo.second){
       ret bo.first
    }
    ret bo.first * bo.second
}


func multIf(a,b,c){
    ifnull(a) -> ifnull(b) -> ifnull(c) -> ret false
    return true;
}

对应的Java原生代码如下:

package com.tianhua.javs.core;

import com.tianhua.javs.core.bean.CalBeanBO;
import org.apache.commons.lang3.StringUtils;

import java.util.Objects;

/**
 * Description:
 * date: 2022/4/16
 *
 * @author shenshuai
 * @version 1.0.0
 * @since JDK 1.8
 */

public class CalculateService {
    /**
     * 加法函数
     *
     * @param first
     * @param second
     * @return
     */

    public Integer add(Integer first, Integer second) {
        if(Objects.isNull(first)){
            return second;
        }
        if(Objects.isNull(second)){
            return first;
        }
        return first + second;
    }

    /**
     * 减法函数
     *
     * @param first
     * @param second
     * @return
     */

    public Integer decrease(Integer first, Integer second) {
        return first - second;
    }

    /**
     * 字符串拼接函数
     *
     * @param firstStr
     * @param secondStr
     * @return
     */

    public String join(String firstStr, String secondStr) {
        if(StringUtils.isEmpty(firstStr)){
            return secondStr;
        }
        if(StringUtils.isEmpty(secondStr)){
            return firstStr;
        }
        return firstStr + secondStr;
    }

    /**
     * 对象乘法
     * @param calBeanBO
     * @return
     */

    public Integer mult(CalBeanBO calBeanBO) {
        if(Objects.isNull(calBeanBO.getFirst())){
            return calBeanBO.getSecond();
        }

        if(Objects.isNull(calBeanBO.getSecond())){
            return calBeanBO.getFirst();
        }

        return calBeanBO.getFirst() * calBeanBO.getSecond();
    }

    /**
     * 多级if 嵌套
     *
     * @param x
     * @param y
     * @param z
     * @return
     */

    public Boolean multIf(String x, String y, String z) {
        if(StringUtils.isEmpty(x)){
            if(StringUtils.isEmpty(y)){
                if(StringUtils.isEmpty(z)){
                    return false;
                }
            }
        }
        return true;
    }
}

对于javs来说,你不需要操心外部Jar包引用和Java关键字语法,这些都在javs解析引擎内部做了处理,尤其是诸如ifnull,ifempty等。关于javs关键字,语法和使用说明会在下一篇文章中重点介绍,敬请期待。

3.3 支持面向过程,面向函数,面向模型编程

javs本身是依托Java语法构建,未来也希望可以支持解析翻译为其他语言,这样的话javs本身就成了伪代码语言,需要一个翻译引擎。所以这样的话在后面的迭代实战中是有希望支持上述编程理论和模型的。

3.4 高度可扩展

四、整体组成内容

在构建Javs的时候javs语法和javs解析引擎是相互迭代生成的,用最合适的语法或者写法习惯来表达相对细粒度的内容。所以需要单独把Javs本身的语法关键字等与解析引擎分开来看,那这里简单介绍下Javs目前的组成内容。

4.1 JavsScript文档

在构建Javs引擎的时候也意识到了需要介绍Javs本身是什么东西,有什么样的语法规则,怎么使用的等等。类似于使用文档或者说明书,所以这里也需要花费一定的时间来书写文档。

4.2 JavsScript解析引擎

目前对于Javs的整体项目来说,只有JavsScript解析引擎,这个解析引擎也可以认为是翻译引擎,将Javs代码按语法规则和关键字等进行转译,最终翻译为Java原生代码。所以javs解析引擎构成了整个项目的核心内容。

五、演进路线

关于未来的演进规划这里也简单谈一下,如果你对这个项目感兴趣可以跟进研究或者与我讨论。未来Javs或许会火的哦。

5.1 JavsScript关键字和文档

首先需要将JavsScript关键字和语法规则等相关的开发文档,使用文档等完善起来,这为后续的开源社区和贡献者讨论提供了一些基础物料。

5.2 JavsScript引擎

对于Javs解析引擎来说目前的第一版只是硬性的进行了解析和替换,所以未来可能会进行重构,同时补全所有java关键字场景和Javs自定义关键字等场景。

5.3 javs文件编辑开发插件

对于javs文件来说,其扩展名就是.javs,这与.java仅仅是一字之差,但是也有不少区别。当然为了让javs更容易使用所以这里也需要开发一个javs文件编辑的插件,可以在eclipse或者idea 中安装并编写javs function。

六、总结

本篇内容总体介绍了javs项目的背景起源,以及其大概的工作原理,javs函数长啥样等等。在后面的文章中将介绍下javs语法关键字和javs文件的整体组成元素以及Javs解析引擎的核心架构内容,敬请期待。