如何在MATLAB中可视化项目结构?

53

我得到了数千行Matlab代码的所有权,其中有一些长达900多行的函数以及几个目录充满了function_name.m文件。很难弄清楚每个函数在做什么(或与何相关)或找出依赖关系。你会建议使用什么来可视化函数结构,例如哪些函数被调用以及以什么顺序调用?


如果codegears公司开始针对Matlab源代码开发他们复杂的CASE工具,那将是很好的。浏览庞大的过程化Matlab代码关系可能会非常痛苦。我建议慢慢开始更新源代码,至少开始利用现在支持的面向对象编程。 - jxramos
7个回答

44

将代码移植到NumPy。

(开个玩笑。)

通常在Matlab中,一些文件被编写成函数,而另一些则被编写成脚本。脚本用于加载要处理的数据并将其输入函数进行图形绘制等操作。

为了组织代码,可以从顶层脚本开始查找执行加载、绘图、处理等操作的函数。将脚本放置在一个顶级目录中,然后尝试将函数根据其用途分离到子目录中。将函数的依赖项放置在同一子目录下。尽可能使得每个目录中的代码都不依赖于父目录(或者是表亲目录)中的任何代码。

每当确定一个函数的功能和参数时,请编写文档注释。

这假设编写代码的人是明智的。如果不是这样,Matlab会让你很容易地把所有东西都塞进一个目录中,并且让所有东西都依赖于彼此,形成一个不稳定的代码堆栈,因此你可能需要进行大量的重构。


14
哈哈,我完全同意你回答中的第一句话! :-) 当涉及代码组织时,Matlab 相当可怕。 - Olivier Verdier
3
@Olivier - 真的。这是其中一个主要缺点。但另一方面,它并不真正适用于大型应用程序。它更多地是为了快速和简便使用而设计的。 - Rook
7
这句话的意思是:“这个东西是有目的的吗?我一直认为它既不像编程语言,也不像数学公式,而更像两者都不擅长的尴尬的孩子。” - ehdv
4
如果您认真考虑“将其移植到NumPy”,我会投两次赞成票。 - dsimcha
2
addpathrmpath。很遗憾。 - ptomato
显示剩余2条评论

14

我在MathWorks的不同角色中曾多次处理这个问题。以下是我为大型MATLAB代码所采取的做法:

  1. 备份,最好备份两份!
  2. 全选,按Ctrl-I进行智能缩进。
  3. 全选,按Ctrl-J进行注释换行。
  4. 如果我想用纸质方式- 打印所有文件,并准备一套荧光笔- 手动跟踪、突出显示长期变量和重要的函数调用。

~~~ 或者 ~~~

5 如果我感到幸运,就开始在调试器中运行代码,一次执行一行(也会跟踪用户编写的子函数)。

此时,我可以通过控制结构的典型流程进行跟踪。我可能不知道每个部分具体是如何实现的,但我有一个相当清晰的思路。

通常,我的目标是找到一个bug,解决它并继续进行。你的目标可能完全不同。这是我多年来用来快速理解数百个不同的MATLAB代码的方法。


1
+1 对于 ctr-i 快捷键 - Semjon Mössinger
抓住它,牛仔道格!我喜欢你的风格,非常果断、干练,能够迎难而上。干得好 B-) - jxramos

14

你的代码是否具有良好的帮助文本?如果是这样,m2html将是一个很好的帮助工具,因为它允许你创建链接的HTML帮助文本以便于浏览。

此外,它还允许你制作依赖图,这有助于更好地理解如何组织代码。


m2html非常棒 - 谢谢 - Benjamin Oakes
获取跨目录的完整依赖关系图有点不明显,但在常见问题解答中有解释 http://www.artefact.tk/software/matlab/m2html/faq.php - aka.nice

8

7

以下是Matlab编程规范的一些建议:

  1. 使用addpath避免文件混乱,并协助函数分类

  2. 将功能脚本分解为section_或设置条件运行,这也有助于插入/拔出模块和重复使用或引用代码。

  3. 使用配置文件打开和关闭选项

  4. 了解构造的架构设置以及操作方式的概述
  5. 保留状态/自述文件(将自己视为新用户,如何帮助使其成为新用户自己模块或解决方案的一部分?如果您回到3个月前的代码中感到迷失或无法跟踪-则存在问题。)我的建议:保持日志以完善您对维护艺术项目的想法。不断完善您的技艺!
  6. 对于方程式,使用LaTeX进行文档记录(并将其保存在名为documents的附近文件夹中,确保它们易于访问和跟踪-如果您必须在驱动器上使用“搜索”,则项目管理存在问题)
  7. 将代码分解为短模块以进行本地化和更短的代码,减少滚动,代码将更容易跟踪。
  8. 使用有意义的变量和函数名称(Java风格似乎不错,例如'backedupDataForVerification'),不要吝啬缩短单词,否则您以后会受到影响。
  9. 在设计时,重新思考是否应该使用函数,脚本或OO(面向对象)
  10. 不要匆忙进行过早的优化,对于速度而言,Matlab并不是最佳选择。如果您真的必须这样做,请保留未经优化的版本以进行侧边阅读比较,故障排除和调试将不会更少。
  11. 始终始终始终注释您的代码。永远不要用没有时间作为借口,否则您以后会浪费更多时间。
  12. 对于差异化,考虑设置新节点进行代码修改,例如设置树来区分版本。

  13. 使用单独的文件夹进行输入/输出、图像、中间结果等。

  14. 使用时间戳跟踪您的版本

  15. 与他人共享您的代码,如果他们发现很难维护、使用或修改,请重新考虑如何改进您的构建。


3
我同意大多数有关Matlab不太支持现代软件源代码结构的评论,但我认为只要稍加约束,就不难强制实施自己的结构。
将您的源文件组织成一个目录层次结构,就像您为使用其他编程语言编写的任何程序的源文件一样。如果您愿意,可以选择自己的结构,不必坚持一个层次结构。使用setpath命令(或者叫什么鬼名字)告诉Matlab在您工作时在哪里查找m文件。
熟悉Matlab分析器工具,它可以提供调用图(不是非常图形化,更像gprof的调用图),这对于解密意大利面条式代码有所帮助。
当然,我们所有的m文件都在存储库中,并且我们从中提供服务。我们在网络驱动器上保留了一个专用工具箱,所有用户都可以直接调用该工具箱中的“发布”代码。

7
我不同意Matlab缺乏支持。它只是不强制要求你按照特定结构组织代码 - 你需要有条理。 - Marc
1
一些功能可能尚未就位,但我们可以组织并增强自己的可追溯性实用程序。从根本上讲,该系统是由人构建的,我们可以添加自己的附加组件。 - Ursa Major

3

备份一切是正确的。创建原始源代码树的纯净tarball,然后将其全部放入源代码控制中,以便您可以跟踪和回滚更改。

查看Matlab的depfun()和depdir(),它们可以检测静态依赖项。它可以帮助您查看Matlab函数之间的依赖关系。通过在所有文件上使用“depfun -toponly”并进行一些字符串操作,您可以构建一个立即依赖性列表,并将其放入GraphViz文件中以生成代码库调用连接的大型有向图。图中的集群可能是分割代码的好地方。(编辑:请参见Jonas的解决方案;看起来m2html为您执行此操作。)

如果您有很大的自由度来重写代码,请考虑将其中一些代码重写为对象,使用无状态实用程序类作为打包相关功能的方法,并提供一些封装的私有函数和类方法。我曾经使用过这种方式组织大型Matlab代码库,效果还不错。在经典Matlab中,类是某些类型包的唯一方法。我相信Matlab的新OO系统也支持命名空间。

如果您不想将代码转换为OO,则可以将相关函数组织到子目录中。这有助于至少为源代码浏览组织它。

所有函数都应该有Matlab标准帮助文本格式的一些文档,包括H1行。如果没有,请将您在那里学到的注释放在那里。然后使用“contentsrpt”工具自动生成类或目录的目录文件。

祝你好运。


1
请查看有关m2html的注释。它可以为您生成依赖关系图。 - Marc
什么是Matlab中“无状态实用类”的定义?你能给我指一些文档吗? - memyself
1
有趣!这里是那些方法的更新... depfun 将在未来的版本中被移除。请使用 matlab.codetools.requiredFilesAndProducts 替代。 - jxramos
@memyself,_无状态实用类_是一个只包含一堆静态函数而没有成员数据的类。请参考《大规模C++软件设计》第73页... “幸运的是,自由函数总是可以分组到一个仅包含静态函数的实用类中。结果的内聚性不一定是最优的,但它确实降低了全局名称冲突的可能性。” - jxramos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接