2019-03-02

2014年,我第一次参与了桌面端的软件开发项目。从惴惴不安到坦荡对待。2015年中,帮助设计了新版的CAD软件架构,那个时候,我们几个人都没有过架构大型桌面端软件的经验,参考着各种资料摸着石头过河。直到架构稳定下来,我们也废弃了不少原有的设计,不断的重构、重写花费了大半年的时间,不得不承认这中间有部分的时间是因为我们的经验不足、错误的设计导致的。今年我又参与了一个新的3D CAD项目,处于初始阶段,软件的架构需要重新实现。我也有更多的信心了。不过按照人月神话的作者经验,错误设计之后容易“过度设计”的。需要注意。我也需要对CAD/CAM或者说是桌面端软件架构设计做一下总结。
  CAD/CAM 软件实现过程中,难度最高的当属各种计算集合的算法了,而最复杂的,当属界面交互操作相关的设计。一旦UI层设计不好,将会把不良影响逐渐传递到底层。类似软件一般有几大模块:UI,3D 显示,三维交互,Undo/Redo,scripting,文件处理,报表生成,嵌入式设备通信与管理,各算法模块,Log。一般情况下,十余人甚至二三人十人的协同开发,分为四五个小组,大的项目如maya,估计有专职开发者几十人。不做好架构设计,组员就会遇到问题,架构上对各个组件的限制,可能组员经常就跑向组长,说因为系统设计的限制,做这个功能很麻烦,或者一个人进行功能开发,却容易改动另外一个人负责的功能。 UI模块
 好的UI lib是非常重要的。我一直推荐Qt的原因倒不是因为Qt的代码质量好、设计好,而是Qt是一门比C++更高级的语言啊(应该是可以这么说的)。语言表述能力的增强,才是解决问题的最高效途径。假如有一天,计算机程序构建可以接受自然语言输入,那么我们能简单的完成这些编程任务了。
2D、3D显示
  我们一般需要一个渲染引擎,二维显示中,这种需求不是很大,我们可以自己实现一个简单管理引擎。三维渲染引擎,一般基于OpenGL或者DirectX接口。但是,对于CAD/CAM这样的程序,选择OpenGL即可。可跨Windows/Linux平台,Mac OS将来只支持Apple自己的Metal接口。不需要同时支持DirectX接口。OpenGL的确很难以使用,但是,对于渲染团队而言,也并不是难点。OpenGL的下一代标准是Vulkan,接口繁杂,但是,整体上更容易理解并使用。对于三维引擎,我们一般有两种选择:1,选择OSG、OGRE这样的第三方引擎;2,自己写一个。对于新项目,我反对自己实现渲染引擎。对于已经稳定的项目,并且对于渲染算法有较多的定制,当然最好是使用自研的渲染引擎。我并不推荐封装很高层的lib。就如我一个同学的想法,机器学习也可以不用学习,到时候调用别人封装好的lib就可以了。当然可以,但是,代价是你将失去对底层的控制能力。
二维、三维交互
  对于二三维交互,我们一般需要拦截二三维窗口的事件。这一般不难,可以建立一个抽象的Operation层,多个Operation都能拦截二三维窗口的事件。二三维渲染线程,还有可能存在的算法线程,与UI层(其实就是Operation)的通信,就是最大的问题。这里也是MVC模式体现最明显的模块。 因为Qt的signal/slot能够非常的解决耦合、多线程异步通信问题,我们可以让Operation模块、渲染模块、算法模块都依赖于QtCore。这比自己实现多线程通信要简单、稳定的多。
算法模块
  因为算法模块的独立性较强,有算法团队专人负责,一般不需要担心对于模型的侵入。但结合到程序中时,为了数据访问、交换的方便、算法的高效性,可能选择直接使用主程序中基础的数据bean,这样就耦合了。这种选择需要结合算法的独立性、主程序对该算法模块的性能要求来决策。
Undo/Redo
  这个模块需要使用command设计模式。基本上是冗杂的工作,需要小心谨慎。command 的 execute()、unexecute()的配对操作,一定不要有所遗漏。command最好记录操作,而非记录之前的数据。我们一般不需要担心多次计算的精度问题。
脚本嵌入
  脚本嵌入中有两大问题:接口暴露、内存管理。与单纯的C++接口设计不同,跨语言的接口设计更需要小心设计。所幸,脚本模块对于原系统来说是非侵入性的。其他模块一般不对它产生依赖。对于脚本语言,不要使用过多的高级特性,尽量让接口足够底层,足够简单。因为,通过嵌入的脚本完成的工作本身不会很复杂。 推荐看一下《C++ API设计》这本书。关于API设计,特别是C/C++ API设计,以后单独总结。
文件处理
   对于标准交换格式文件的读写,最好使用第三方lib。需要定义好接口,底层读取写入算法实现可以随时被替换掉。对于项目所需要存储的自定义数据,我们一般有两种保存格式:文本格式;二进制格式。这便是序列化与反序列化。对于Java、Python这样的程序,对于对象的序列化有语言的直接支持。但是,对于C/C++,只能自己写代码完成。boost库支持C++ class 序列化,有入侵式与非入侵式。当然,最好是选择非入侵式的方式。避免其他模块对于boost产生依赖。序列化能够很好的解决数据bean 持续变动的问题。因为,我们基本上不可能一次性的设计好数据结构。而且,随着算法模块持续演进,必然需要对于数据bean做出修改。另外一种方式是采用文本方式保存数据bean。一般来说,我们最好设计好接口,二进制、文本方式都需要支持。
报表生成
  报表生成一般需要保存为word、excel、PDF、HTML、cvs、txt等格式。各个软件对于报表生成的要求不一,有的软件或许只需要输出一些cvs、excel即可,数据比较标准,有的软件可能要求输出PDF、HTML,甚至还需要截取三维显示的内容,光报表生成可能就需要两三人负责开发。但是,报表模块一般只读内部数据,在接口设计上,多使用const。对于多种报表生成器,需要定义好接口。对于数据成员的访问,使用好Visitor模式,避免为了报表从class中提取数据,而增加一些用途不大的接口,导致代码臃肿。
网络通信
  最好不要使用原生的接口来实现网络通信功能。因为我们是在实现应用程序,而非lib。支持跨平台的网络通信lib 是最好的选择。通信模块一般不是重点,也不会专门调人开发维护。使用lib的好处就是稳定,且有资料可查。对于公司内部项目而言,重要的上层通信协议。对于协议的设计,要做好不断迭代并拓展的准备。
Log
  log模块的作用是非常重要的。因为C++程序内部错误导致crash的情况比较多,且C++程序多交付给第三方使用,重现步骤就会变得比较困难。log是帮助修复bug的重要信息来源。对于简单的应用,可以使用同步log,但是,对于CAD/CAM程序,线程可能较多,就需要异步log了,避免计算的线程与磁盘读写的阻塞问题。对于所需日志较为详细时,可能需要通信模块支持,建立日志服务器,避免占用磁盘。

关于错误。我们曾经犯过不少错误。编程相关的决策错误大抵是不会导致软件项目失败的,特别是在当前这种互联网公司持续运营项目的模式下,多数程序在服务端服务端运行。软件开发团队会持续的迭代项目。每次交付的内容也是阶段性成果,对外交付的是服务。不像二三十年前,软件交付并分发出去之后,迭代改进只能等到下个版本了。所以,对于我们软件开发者的压力也小了些。但是,对于需要对外交付的软件,则需要格外小心。
  关于UI lib的选择,不要选择MFC或者C#的WinForm或者WPF,或者其他小众的UI lib。最好需要Qt。因为,偏工业软件并不需要在UI 显示效果上有很高的要求,即使是Maya,2011年之后也是采用Qt技术实现UI的。用户最在意的是软件的核心功能,炫酷的样式或者交互只是锦上添花。
  对于,模块之间接口暴露程度。越是偏上层,越没有必要隐藏模块内的数据结构。需要隐藏的东西最好设置protected或者impl 实现。对外提供指针,而非id或者某种handle。之前吃过这个亏,非常大的亏。我从最开始时便反对这种方案,奈何没有作用,用handle代替指针给后续两年的开发过程带来非常多的bug。所谓的解耦,并不是把自己的模块隐藏起来,解耦的目的也不是为了将来有一天重新实现某模块,并替换掉老的模块。这不现实。解耦,是为了在后续开发过程中,发现某模块内设计不合理,能以很小的代价进行修改,对其他模块的影响也能尽量的少。
  对于,C++版本以及 std、boost是否选用问题。我觉得,对于新创项目,还是尽量选择新版本C++以及 std、boost,它们的质量比我写的代码质量好太多了。须知,编译器也是有bug的。之前项目中,我帮助发现了一个由vc12 foreach 语法糖导致的bug。而且,对于这种偏上层代码,我们不需要担心其他开发团队依赖于本项目的问题。lib带来的依赖冲突问题基本上不需要考虑。
  对于,脚本嵌入,最好选用Python。Lua真的不适合CAD/CAM项目。虽然Lua语言本身小巧,容易操纵,但Lua语言本身的表达能力偏弱,使用者较少,第三方lib的广泛性以及成熟程度都不及Python。我们在之前的项目就犯过这个错误。
  对于第三方lib的选择,非核心算法模块,或者将来自己的程序肯定会修改实现方式的功能,如果有第三方lib,就尽量使用。最大的原因在于自己写的代码,非常有可能在质量上比不过经过锤炼的第三方lib。所谓的学习成本,还是很低的。并且,一个人的学习,可以形成文档,第二个人完善文档,之后其他人的学习成本就会低很多。
  对于各种方便的、取巧的方法,如使用全局变量,需要保持警惕。须知,Nothing comes for free。使用起来简单,但是,用多了,就会导致忽略模型正确的class 层次关系,对重构模块或者项目带来很大的难题。不要为了避免重复构造关键对象而使用单例模式(基本上单例与全局变量总是一起出现)。不要过分担心软件设计里面的问题,还没有遇到耦合问题,就考虑对各模块解耦;还没有遇到性能问题,就考虑优化而对模型层次关系做出修改 ,这些做法都矫枉过正了。
  关于自动化测试,CAD/CAM软件一般难以进行自动化测试,因为对于二三维窗口的业务操作,很难录制脚本。而且,由于操作交互变化较多,即使实现了脚本录制的方案,录制的脚本有效期也不会持久。这都导致自动化测试工作难以开展。我们可以利用内置的脚本语言,对于主流程做简单的测试,避免录制交互操作,而是使用脚本替代完成,让脚本直接调用内部接口。这便要求各个模块尽可能多的暴露接口给脚本模块。
  在详细设计阶段,一定要做好UML图。并且需要专人负责持续修改。让团队成员对于项目的整体架构保持熟悉。强调一点,《道德经》有言”无名天地之始,有名万物之母“。对于命名,拥有决策权的各组长一定要控制好。尽量避免缩写,避免***Manager这样的模糊不清的表述,避免歧义。

P.S. 2018四月份开始写的东西,到现在才写完,真费劲。可能行文很杂乱吧,本来也不是一次成文,从笔记里面提炼出来的总结而已。

如果有任何意见,欢迎留言讨论。

[ 主页 ]

COMMENTS

CAD/CAM 软件架构总结相关推荐

  1. 基于CAD/CAM的三维控件

    CAD/CAM超级三维控件,本控件以dll.so提供 实现的功能简述如下: step.iges. stl等常用三维格式模型文件的展示,效果如下: 在左侧树状视图中,可以看到该零件的各个构成部件,取消该 ...

  2. 开源项目推荐:CNC+CRC/SoftPLC/OpenCASCADE/CAD/CAM

    <开源项目推荐:CNC+CRC/SoftPLC/OpenCASCADE/CAD/CAM>

  3. matlab画孔斯曲面,CAD CAM技术基础:第五讲 孔斯曲面

    <CAD CAM技术基础:第五讲 孔斯曲面>由会员分享,可在线阅读,更多相关<CAD CAM技术基础:第五讲 孔斯曲面(33页珍藏版)>请在人人文库网上搜索. 1.CAD/CA ...

  4. 手工编程是指利用计算机完成,西安交通大学17年3月课程考试《CAD CAM》作业考核试题...

    B. 下层结点可与几个上层结点连接 C. 上层结点只能与一个下层结点连接 D. 上层结点与下层结点间没有连接关系 正确答案: 29. 计算机集成制造系统简称为( ) A. CAE B. GT C. C ...

  5. cad应用程序的组件中发生了未经处理的异常_什么是CAD/CAM?

    与许多其他行业一样,牙科技术的生产阶段也越来越自动化.由于牙科实验室工作的价格已成为治疗计划和治疗的主要因素,因此自动化可以在西欧和美国等高薪地区实现更具竞争力的生产. 现在,计算机技术的进步使高性价 ...

  6. CAD/CAM/CNC行业常用功能解决方式

    CAD/CAM/CNC行业常用功能解决方式 进行线切割的时候通常需要得到几何上的点:如何是直线段比较容易,但是对于圆弧.椭圆.曲线就需要调用专用的函数来解决了. 1.  得到Polyline(多义线) ...

  7. 计算机辅助设计在口腔医学中的应用,椅旁CAD/CAM技术在口腔修复中的应用

    CAD/CAM(computer-aided design and computer aided manufacturing)是指口腔修复体的计算机辅助设计与计算机辅助制作.椅旁CAD/CAM技术使得 ...

  8. 《SolidCAM+SolidWorks 2014中文版数控加工从入门到精通》——第1章 SolidCAM基础 1.1 CAD/CAM基础...

    本节书摘来自异步社区<SolidCAM+SolidWorks 2014中文版数控加工从入门到精通>一书中的第1章,第1.1节,作者:赵罘 , 杨晓晋 , 刘玥著,更多章节内容可以访问云栖社 ...

  9. CAD/CAM/CAE基础(一) 概论

    文章目录 基本概念 什么是CAD/CAE/CAM CAD的主要研究内容 CAE的主要研究内容 CAM的主要研究内容 CAD/CAE/CAM系统集成 功能模型图 材料加工中的CAD/CAE/CAM 铸造 ...

最新文章

  1. python访问memcached
  2. Spring Security第2部分–密码加密,自定义404和403错误页面
  3. postgresql 遍历字符串数组_每日一道编程题(348):1005.K次取反后最大化的数组和...
  4. redis 中一个字段 修改map_CTO 指名点姓让我带头冲锋,熬了一个通宵,终于把Redis中7千万个Key删完了...
  5. WsusAgent检测脚本
  6. UI设计实用素材|2020动画将占据中心舞台
  7. linux脚本制定java堆大小_Java使用比堆大小更多的内存(或正确的Docker内存限制大小)...
  8. 结合element-ui封装的一个分页函数
  9. github 建立博客
  10. 2012-8-1复选框全选
  11. 有线电视维护服务器,东方有线电视 网络服务器 设置
  12. 女孩子没有事业就只能痛苦
  13. Si5341时钟芯片使用说明
  14. java一道多线程题,子线程循环10次,主线程接着循环100次,如此循环50次的问题
  15. 使用SSH密钥连接阿里云linux服务器
  16. 解决微信企业号和公众号无法调用摄像头拍视频的问题
  17. 2022.11.05 第六次周报
  18. mysql驱动下载mac
  19. 20岁,他来武大读博!
  20. SAP WM初阶LS07冻结Quant

热门文章

  1. AR、MA、ARMA和ARIMA模型------时间序列预测
  2. linux如何连接手机传文件,Ubuntu和手机通过蓝牙互传文件
  3. Linux远程ssh破解
  4. MJKDZ PS2手柄控制OskarBot小车(一):Arduino串口发送数据
  5. JavaWeb | HTTP 协议请求与响应格式
  6. Asterisk manager API(AMI)文档(中文版)
  7. Rust(9):枚举类型
  8. 即时配送行业黑马 闪飞侠2022正式起航
  9. python做菜单_python实现三级菜单
  10. 18种为你的网站引流的好方法