背景&闲聊
(说起来好久没好好写过博客了,进到主页看到之前挖的坑没怎么填,我的内心居然毫无波动。一个是工作比较忙没啥精力更新,一个是沉迷原神hhhh)
最近同事离职,开发任务短期内变多,接手项目得快速的阅读代码、填坑、修bug,还得开发新功能。面临的问题:1.面对未知项目代码,快速分析、理清逻辑依赖、上手开发新功能/修复bug。2.简化工作中重复/规律性极强的操作
下班后不由得开始思考,有没有一种工具/方法能简化我日常的工作,让我专注于更有价值的事情上,而不是照着设计文档人肉翻译到Java代码。
看着床头一摞毕业后从未怎么翻过的书,里面有一本Model-Driven Software Engineering,大概意思是描述和设想了一套和目前主流完全不一样的软件开发流程,和近些年火起来的中台和低代码有点关系。上学时候觉得定义1:1的代码模型还不如直接写代码来的快,软件可视化蓝图的效果停留在机械的翻译java代码到思维导图的阶段。工作了几年发现大部分”重复”工作都是基于M1(model)层的,想做变革就得上升到M2(meta-model)甚至M3(meta-meta-model)才有可能。上网搜了搜相关资料发现了这个文章 https://blog.csdn.net/chljapan/article/details/88874430。看起来感觉很有意思,当时上学时候学习的MDSE,如今居然有人真的实现落地了一个执行引擎。项目代码:https://github.com/chljapan/KayaSmart/blob/main/README_ZN.md
尝试按照文档操作了下,发现的问题:这个方案使用了GME来做模型,在尝试下载安装的时候win10下会直接失败。并且看截图界面并不像个现代工具,并不符合我的审美。万里长征失败于第一步hhhhh。借鉴、改进kaya流程的想法也随之而来。因此对EMF相关技术做了部分调研,调研涉及的技术、项目都在后面记录了,有的翻译了一点官方文档的描述,有的懒得翻译只贴了网址。有能力来研究这些相关技术的人,必然是高手(除了我),想必也并不需要我来给出翻译hhhh。总体原则是能用图形界面的用图形界面编辑,否则考虑文本编辑。尽可能少写”代码”,找成熟或已有的方案组合使用来解决问题。
无奈的是,MDSE虽然发展了这么多年,但资料相比主流编程语言、AI、大数据之类的来说简直少的可怜,官方文档的描述也并不能完全相信用于指导学习,只能参考,甚至不得不翻源代码来解决问题。同时国内有能力做灵活的M2设计开发的人太少了,更不要说再限定在后台开发领域了。虽然近几年出现了不少号称低代码的平台,但都是各有各的限制,目前没看到一个完全通用的,看起来和前几年吹的中台更接近一些。个人认为,大部分应该都是堆人力堆出来的,掌握M2核心抽象设计技术的人应该不会轻易在网上露面。
根据调研得到的结果,反复阅读官方文档后,我尝试使用ecore tools制作了元模型,使用默认的树形编辑器尝试制作了模型,使用Acceleo做了代码生成。虽然只是生成几个包和几个简单Java类,但这让我对MDSE又重拾了信心hhhh。反观CS/SE的发展历史和编程语言的进化史,每一次的进化无一不是更加抽象、隐藏了更多细节,同时隐藏的细节部分交给机器(一般都是编译器)完成。
在制作过程中,好奇心驱使我打开了ecore和自定义的模型文件看了下原始内容,结果不出意外是XML格式的,里面引用对象时使用的语法也类似于xpath(此处存疑,不知道是不是xpath,但能看懂含义),果然上学时候好好学习还是有用的,当时没啥用的东西现在居然用到了hhhh。也就是说dtd和xslt之类的技术,在本次计划中也能派上用场。如果没有合适的工具,自行解析xml是一个绝对能达成目标的兜底方案。
在主流程demo走通了之后,因为自带的eclipse插件编辑模型太繁琐了,尝试使用sirus制作个图形化编辑器来方便使用。面临的问题就是需要自行编写odesign定义元模型到UI的映射定义。在尝试搜索寻找可复用的odesign例子时,无意间发现了一个MTM的github项目(https://github.com/tuiSSE/sirius-meta-editor),参考论文是A Generative Approach for User-Centered, Collaborative,Domain-Specific Modeling Environments。阅读了一部分发现居然有人做了个全套的工具集CINCO,并且还是web-based。人家不光做了全套的工具集,还借助M3的MTM做到了自动化生成所有配套工具,虽然目前还没下载完,看了下协议是eclipse public的,感觉可以直接拿来使用或改造。
这个论文值得好好阅读,个人认为人在SE过程中最大、最有价值的部分就是设计,这也是为什么科班教学课程的名字一直都是面向过程程序设计(C)/面向对象程序设计(Java/C++),编程语言的学习只是次要的,根据计算机底层原理设计程序如何执行才是重点。MDSE提出了这么多年,随着AI的发展,感觉距离完美的MDA越来越近了,只做设计这个目标有生之年有望达成。
目标
短期目标:通过简化的图形化/文本化编辑,持久化domain模型,自动生成数据库Entity、项目框架、通用/自定义业务逻辑等代码,减少后台业务的重复开发劳动
长久的目标,使用最佳的MDSD实践、不再编写代码
相关技术调研记录
Eclipse Modeling Framework (EMF)
元模型技术支持,主要是ecore,用于构建EMF model
https://www.eclipse.org/modeling/emf/
https://www.eclipse.org/modeling/emf/gettingstarted.php
https://eclipsesource.com/blogs/tutorials/emf-tutorial/
Eclipse Extended Editing Framework (EEF)
Graphical Editor Framework(GEF)
提供通用的模型编辑能力框架 图形化编辑功能基础能力
Sirius
基于EEF的图形化workbench生成,用于制作自定义EMF model的编辑器
https://www.eclipse.org/sirius
https://wiki.eclipse.org/Sirius/Tutorials/BasicFamily
自动生成参考文献 https://ieeexplore.ieee.org/document/9447062
参考项目https://github.com/tuiSSE/sirius-meta-editor
https://github.com/tuiSSE/sirius-meta-editor-architecture2sirius
graphiti
https://www.eclipse.org/graphiti/
glsp 图形化编辑协议,支持vscode
https://www.eclipse.org/glsp/
ecoreTool
基于sirius 提供自定义ecore模型的可视化化编辑,
https://www.eclipse.org/ecoretools/doc/index.html
Xtext
https://wiki.eclipse.org/Xtext
Xtext 是用来开发第三方文本型DSL的框架/工具,仅仅需要使用Xtext的EBNF(扩展的Backus-Naur范式)描述你自己的DSL语法,生成器会自动创建分析器、抽象语法树元模型 (基于EMF实现) 、完整的Eclipse文本编辑器
这个框架集成了来自Eclipse Modeling的以下技术:例如EMF, GMF, M2T 以及一部分的EMFT. 使用Xtext开发可以很快的得到反馈,以至于给存在的DSL增加特性只需很短的时间, 更新更复杂版本的编程语言可以被轻易实现,语言的开发从未如此简单
CINCO
使用MGL(Meta Graph Language)定义元模型,CINCO自动生成图形/文本编辑器的eclipse插件
https://cinco.scce.info/
https://cinco.scce.info/assets/documents/cinco-manual.pdf
CINCO 提供了多种语言来定义图形化DSL的元模型
- Meta Graph Language MGL模型定义了模型的每个组件以及他们之间的关系
- Meta Style Language MSL描述了MGL中节点、边、容器的形状和外观
- CINCO Product Definition CPD 组合多个MGL来生成一个CINCO产品
pyro
CINCO的插件, 支持让CINCO生成定义模型的网页版IME
https://pyro.scce.info/
https://pyro.scce.info/assets/documents/pyro.pdf
Pyro使用CINCO元插件扩展来生成其他环境下的产品,基于CPD和它引用的MGL和MSL,Pyro基于基于web领先的技术提供和本地应用相同的用户体验
- JointJS 基于SVG的图形可视化和交互,开发者为 Client.IO (JointJS).
- Dart 面向客户端的开发语言,开发者为Google (Dart Lang).
- Angular 前端的单页应用框架,开发者为Google (Angular).
- AngularDart web应用框架 (AngularDart)
- DyWA 动态web应用程序框架在OOP上下文环境中提供了快速原型设计以及类型和对象的动态松散耦合管理
DIME (DyWA Integrated Modeling Environment)
开发web应用的集成建模环境
https://scce.gitlab.io/dime/content/introduction/
TODO:这里面有现成的对数据流和控制流的建模,可以考虑想办法找到它的ecore直接继承、扩展、修改、参考借鉴等
Object Constraint Language
声明式语言(Declarative),用于约束和查询模型上的元素
https://help.eclipse.org/latest/index.jsp?nav=%2F65
OCL Project
https://projects.eclipse.org/projects/modeling.mdt.ocl
该项目提供了符合 OMG 标准基于EMF模型的实现
- 为解析执行OCL约束和EMF上的查询定义了API
- 为OCL抽象语法模型定义了Ecore和UML的实现,包含对已解析的OCL表达式的序列化
- 提供了用于分析和转换OCL表达式的抽象语法树模型的API
- 提供了可扩展的客户端API,可用于语法分析器的自定义解析和执行环境
OCL分析器基于LALR生成,该项目提供了如下特性
- 提供交互式OCL终端来执行模型上的查询
- 提供嵌入Ecore元模型的OCLinEcore Xtext 编辑器
- 提供完整的OCL编辑器完善OCL文档来补充元模型信息
- 提供基础的OCL编辑器,用于独立的OCL表达式
OCLinEcore & OCLinEcore Editor
https://wiki.eclipse.org/OCL/OCLinEcore
Ecore编辑器可以方便的维护一系列的OCL约束,但它作为OCL 的IDE来说显然有一些局限性
- 需要考虑维护EAnnotations
- 在Properties View下OCL表达式难以阅读
- 无法检测到OCL的语法和语义错误
OCLinEcore Editor 克服了这些问题,可以支持嵌入式的维护ecore的Annotation
安装方法,选择“OCL Examples and Editors”安装即可
注意编辑器比较新(看文档已经是8年前的了,还新??),这里做的是名字引用的验证而不是他们的类型验证,这个还在实现中(有生之年系列?)。如果有一些错误误报的话,需要直接保存并重新打开编辑器。OCLinEcore文本可以在语法、语义校验和自动提示的帮助下来编辑
空格和OCL注释将被存入Ecore EAnnotations中,如果你不想保存注释,在右侧选择另存为OclInEcore即可
OCLinEcore参考严格的OCL表达式和OMG语法语法推断,但完整的实现 TBD(多半是鸽了)。示例编辑器中的语法目前还存在争议,在Helios版本后的发布中可能被修改
papyrus
https://www.eclipse.org/papyrus/index.php#applications
https://www.eclipse.org/papyrus/documentation.html
Eclipse Papyrus是一个 UML工具,它提供了非常高级的基础设施用于定制化工具
UML designer
基于sirius 提供通用UML图的可视化编辑
http://www.umldesigner.org/
使用标准的 UML2 元模型 , 提供了方便的方法来融合UML和自定义领域模型. 你可以扩展已有的定义来无缝同时使用自定义模型和UML,你可以根据需要修改每一个图形
https://www.eclipse.org/papyrus/index.php#applications
Model Transformation 模型转换,低精度EMF model转化为高精EMF model
https://www.eclipse.org/modeling/transformation.php
acceleo
自定义代码生成器 需要ecore model和代码模板
https://www.eclipse.org/acceleo/overview.html
https://wiki.eclipse.org/Acceleo/Getting_Started
总体思路
1.通过对常用概念建模,制作自定义元模型M2 、低精M1、高精M1
工具:EcoreTool、OCLinEcore Editor、UML Designer、CINCO
插件开发不重启eclipse
https://dzone.com/articles/reload-your-plugins-without
https://wiki.eclipse.org/FAQ_How_do_I_make_my_plug-in_dynamic_aware%3F
https://wiki.eclipse.org/FAQ_How_do_I_make_my_plug-in_dynamic_enabled%3F
CINCO支持引用外部ecore:
https://gitlab.com/scce/cinco/-/wikis/Meta-Graph-Language#nodescontainer-that-reference-model-elements-defined-in-arbitrary-ecore-metamodels
2.(可选)通过低精model转化为高精model 或借助Sirius控制model的实现精度
3.完成代码框架和常用类的生成
工具:acceleo、OCL
独立运行方法 https://stackoverflow.com/questions/1714778/programmatically-running-emf-code-generation
call Eclipse from the command line. Something similar to this:
0 1 2 |
eclipse.exe -noSplash -data ${workspace_location} -model -edit -editor -tests -application org.eclipse.emf.codegen.ecore.Generator ${genmodel} |
This command will start Eclipse silently and will generate mode code (-model
), edit plug-in (-edit
), editor plug-in (-editor
), and the test plug-in (-tests
). Leave out any of these parameters if they are not needed.
4.手动剩余实现代码
具体实现路线
1.原始的Ecore
ECoreTool + Acceleo
2.扩展Ecore定义
参考 https://blog.csdn.net/cuxiong8996/article/details/107155073
进度
20210911 路线1
目前通过Sirius EcoreTool生成ecore+genmodel元模型和插件、通过编辑器插件生成模型、通过acceleo生成代码流程已走通
元模型公开:https://github.com/956237586/hyldesigner
acceleo代码模板公开:https://github.com/956237586/hyldesigner-codegen
问题:Sirius EcoreTool的Eclipse版本和Acceleo的Eclipse版本不一致,通过最新Eclipse手动安装插件会提示错误,有依赖是冲突的
20211023
之前Demo一般都会用Todo-App来做,近些年都换成realworld了,所以我也用realworld来作为这种开发方式的Demo。
realworldDemo公开:https://github.com/956237586/realworld-mdd
其实实现方式和正常编程没啥区别
1.按API文档定义按我自己的风格正常手写一遍实现,包括测试用例
2.建立个src-gen文件夹使用同样的包名,调整codegen和meta-model的定义,把codegen生成的代码放这里。
3.通过git或idea对比文件变动,让codegen生成的代码在不丢失可读性的前提下和手写的代码完全一致or逻辑等价
4.重复1-3,直到整个项目完成
目前已经成功实现了api请求参数和返回值的自动生成、Controller骨架生成
而在生成Controller实现逻辑的时候遇到了困难。接口的实现逻辑从底层来看整体可以划分为控制流和数据流,数据流就是例如各种Payload、Dto、Entity之间的的转化代码,控制流是在这些变化的基础上增加跳转、组合逻辑。因此无论怎么抽象都绕不过控制流和数据流的建模,而这部分目前无论怎么抽象都是很复杂的。会直接导致编辑模型时要提供的信息量无限接近于文本形式的代码,反而不会提高效率or简化开发过程,甚至会起到反作用。控制流和数据流的框架代码可以考虑自动生成,而实现过程的完整建模如前面所说的原因不再打算继续做无用功。
观察了已有的实现方案,例如DIME,它是提供给非技术人员用于实现后台服务的,所以它实现了完整的图形化。图形的编辑方式目前主流是拖拽+修改属性,根据我的经验这种方式在通用任务编程任务中并不好用。反而必须得是限定到某一类小任务上,图形化的优势才能发挥出来。而作为专业后台开发,面对多变的复杂业务流程时以这种形式阅读/检索/编辑”代码”并不会更高效,可能会适得其反。DIME的官方demo效果如下图。
因此下一步计划设计plugin架构来支持用户编写的代码和自动生成的代码相互调用,只把重复的实现部分交给自动生成,复杂控制流的编写依然需要采用原来的方式进行编码。
在这里其实常见的设计模式都可以使用,而不同场景下的plugin需要选择合适的设计模式。
https://github.com/956237586/realworld-mdd/blob/master/src/main/java/cn/hylstudio/mdse/demo/realworld/service/login/impl/BizLoginServiceImpl.java#L91
0 1 2 3 4 |
checkLoginRequestPayload(payload); UserLoginRequestDto userLoginDto = convertPayloadToRequestDto(payload); UserLoginResponseDto userLoginResponseDto = doLogin(userLoginDto); return convertUserToLoginResponse(userLoginResponseDto); |
可以看到登录主流程可以分为4个阶段:这其中除了3以外,都有非常强的规律,我们分别来讨论
1.参数检查 https://blog.hylstudio.cn/archives/841
2.参数解析、转换
3.主登录流程doLogin
4.登录结果转换
参考资料
书籍来源
Model-Driven Software Engineering in Practice
Eclipse Modeling Framework 2nd Edition
文献
Creation of domain-specific languages for executable system models with the Eclipse Modeling Project
A Generative Approach for User-Centered, Collaborative, Domain-Specific Modeling Environments
Pyro: Generating Domain-Specific Collaborative Online Modeling Environments
A Tutorial Introduction to Graphical Modeling and Metamodeling with CINCO
值得关注的作者 国外有 Philip Zweihoff, Bernhard Steffen, Stefan Naujokat几个大佬,国内的 chljapan(github看到的,不知道真名)、刘建斌教授
概念定义 https://en.wikipedia.org/wiki/Meta-Object_Facility
xsd持久化问题参考 https://www.cnblogs.com/demonrain/p/3559525.html
学习笔记1,发现是翻译自Eclipse Modeling Framework 2nd Edition,直接参考原文
目录https://blog.csdn.net/u012521340/category_7023464.html
学习笔记2
目录 https://blog.csdn.net/kevinz26/category_325754.html
0 Comments