业务开发过程中的思考和实践系列一:自描述软件DSL

原创
2024/01/17 20:09
阅读数 98

我们知道80%的工程师在80%的时间都在维护或迭代遗留项目。而绝大部分遗留项目的业务、产品和技术文档都是匮乏的。最近我重新接手部分业务需求的开发工作,我遇到的第一个问题就是在文档匮乏的情况下从”Shit Mountain“代码中梳理清楚业务逻辑。

在客户端同学的协助下,我大概定位到新需求涉及的几个API接口,然后顺藤摸瓜从API接口声明到业务服务实现捋了一遍,勉强熟悉了这部分业务逻辑,然后如履薄冰地写代码,期间和产品经理多轮沟通,再和客户端同学联调,最后通过测试同学测试,总算顺利完成需求交付。

但经过这一轮折腾后,我想:有没有更好的方式让新接手的工程师可以更快熟悉并上手项目。最直观的想法是看文档,但众所周知文档有以下问题:

  • 很少有项目会维护文档,或者维护完整的文档(绝大部分情况)
  • 随着时间推移,项目文档很可能会过期,很少项目会持续迭代更新文档
  • 项目的业务文档、产品文档和技术文档可能出现不一致甚至自相矛盾的情况(非结构化的文档很容易有这类问题)
  • 项目文档如果没有很好地分门别类,检索、阅读费时费力

文档这条路不通,我想到DDD(领域驱动设计)通过定义领域、子域、聚合根、实体、值对象、领域事件等概念为业务逻辑提供了一套清晰通用的描述语言。那是否可以借鉴DDD的思想,为软件制定一套描述性强的DSL,最终为软件生成一份自描述的规格说明呢?

答案是肯定的。调研发现有一个名叫SysML的MBSE建模语言,详细可以参考这篇文章 SysML建模在系统开发生命周期的应用。SysML包括九种图(包图、需求图、活动图、序列图、状态机图等),它是软件统一建模语言UML的一种扩展,用于表示系统开发中的所有活动。SysML建模语言固然很好,但太重(早期SOA的理念也很好,但协议规范过于冗长、复杂最终鲜为人知)不便于在实际项目中照搬。至此,思路就很清晰了,设计一套简化版的SysML DSL,这套DSL的特点如下:

  • 以自然语言编写,可读性强
  • 只描述软件的关键功能、功能对应的用例、功能对应的页面、页面用到的接口、页面交互和接口流转。业务领域模型、内部系统/模块关系、数据模型、状态机等属于各端自己需要关注的,不需要在这套DSL中描述
  • DSL天然结构化,便于和开发框架集成

基于以上特点,在ChatGPT的帮助下,我编写了一个Petstore的DSL Demo,如下:

# 整体功能描述
系统 Petstore {
    描述 "Petstore是一个在线宠物商店系统,提供宠物管理和订单管理功能。用户可以查看所有宠物,添加新宠物,更新宠物信息。同时,用户可以查看订单历史,创建新订单,以及更新订单状态。"

    功能 宠物管理 {
        用例 查看所有宠物
        用例 添加新宠物
        用例 更新宠物信息
    }

    功能 订单管理 {
        用例 查看订单历史
        用例 创建新订单
        用例 更新订单状态
    }

    # 页面和接口描述
    页面 宠物列表 {
        使用用例 查看所有宠物
        使用接口 /api/pets 获取宠物列表
    }

    页面 新增宠物 {
        使用用例 添加新宠物
        使用接口 /api/pets/add 添加宠物
    }

    页面 订单历史 {
        使用用例 查看订单历史
        使用接口 /api/orders 获取订单历史
    }

    页面 创建订单 {
        使用用例 创建新订单
        使用接口 /api/orders/create 创建订单
    }

    # 页面交互和接口流转
    交互流转 {
        页面宠物列表 到 页面新增宠物 通过事件 选择宠物 -> 跳转 {
            接口流转 接口 /api/pets 获取宠物列表 到 接口 /api/pets/add 添加宠物 通过事件 完成添加 -> 更新宠物列表
        }
        页面新增宠物 到 页面宠物列表 通过事件 完成添加 -> 刷新列表 {
            接口流转 接口 /api/pets 获取宠物列表 -> 刷新列表
        }

        页面订单历史 到 页面创建订单 通过事件 创建新订单 -> 跳转 {
            接口流转 接口 /api/orders 获取订单历史 到 接口 /api/orders/create 创建订单 通过事件 完成创建 -> 更新订单历史
        }
        页面创建订单 到 页面订单历史 通过事件 完成创建 -> 刷新历史 {
            接口流转 接口 /api/orders 获取订单历史 -> 刷新历史
        }
    }
}

建议:

  • 上面DSL Demo中的描述和功能和用例需要测试或开发同学手动维护,可以只维护关键功能,变化频率不高,维护成本相对可控
  • 页面和接口描述、页面交互和接口流转的变化频率较高,为了便于维护可以借助SDK自动生成,0维护成本
  • 可以为上面DSL提供一个简单的管理后台,提供可视化及增删改等维护功能
  • 如果使用了Swagger等API管理平台,上面的管理后台还可以与其打通
  • 公司如果有自研开发框架,可以基于这个DSL生成脚手架代码

END

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部