代码重新生成的问题与解决办法
由于目前无法生成软件的全部源代码,所以需要先生成能生成的,再逐步扩大能生成的范围,最终实现生成全部的源代码。拿下厨作比方,厨师还是人,生成代码的机器人打下手,从简单的活做起,洗菜、切菜,并跟着人类厨师学厨艺,最终学会做菜的全流程。
所以,在实现最终目标前的相当长的时间内,需要做好人与机器人的配合工作。这就是说,需要先由机器人生成代码后接着由人继续添加或修改代码。并且长期处于机器人与人配合完成工作的阶段。
理想状态下是,一开始设计好全部的数据表结构,然后机器人生成一遍代码后,剩下的就全是人的手工编码工作了。实际情况不会那么理想。总是在某些时候,需要添加表、添加字段或修改字段,从而需要重新生成代码。拿添加新字段作为例子。新生成的文件有新添加的字段,原来的文件却有人工添加和修改的代码。如何合并才能既保留人的劳动成果,又有新添加的字段的代码?
可能有人要说,既然代码已经被人改了,那么添加字段时,也应该由人来改。这就失去了由机器人生成的代码具有高质量的优势。比如添加一个字段需要修改20处代码,如何保证人工修改的这20处是正确的?如何确保没有漏了修改某处(第21处)?实际的项目,边做边接收需求,持续收到反馈,持续改进,时不时添加表、添加/修改字段,尤其是添加字段,是普遍现象。如果代码生成器仅仅能在新建表时生成一次,则实用性大打折扣。严格来讲,没有实用性。所以,我曾经也说过:不支持重新生成的代码生成器,只是一个玩具。
第二种解决办法是,将重新生成前后两份代码,通过对比工具进行对比由人工合并。这是目前比较常见的解决办法。既能在添加字段等修改表结构的情况下,享受到代码生成器的优势,也能兼顾人工修改的代码不被覆盖。缺点是每次重新生成,都要人工操作合并工具,效率比较低下。如果能自动合并,或在大部分情况下能自动合并就最好了。
第三种解决办法是,在模板中划好人工修改的区域,即标记供人工修改代码区域的起止位置,当重新生成代码时,读取人工修改的区域写到新生成的文件中,从而实现两者的合并。此办法也是目前应用比较多的办法。缺点是划定了人工修改的范围,实际情况需要修改的代码,并不总是在划定的范围内。所以超出划定范围的修改,会被覆盖,为了解决这种情况,又得使用第二种解决办法中的办法来合并。
第四种解决办法是,将上一次生成的代码保存起来,在重新生成新代码后就有三份代码,分别是:1.人工修改后的代码,2.上次生成的代码,3.重新生成的代码。自己实现一个工具,对比2和3的差异,并将差异应用到1中,从而得到合并的代码。目前的git合并不同人对同个文件的不同修改,也是这个思路。好像叫“三路合并”吧,不太确定。在多数情况下,可以自动合并。少数情况下,出现(真正的)冲突,才由人工来处理。这种办法我本人还暂未动手实现。
目前用得比较多的是"第二种解决办法“。于是会碰到另一个问题,生成后的代码会被IDE进行格式化,从而改变了换行,即某些代码行由于太长而被IDE自动换行。从而在重新生成时,会出现多处的不同,为人工合并带来了更多的工作量。这些被自动换行的代码行还可能与人工修改的代码或重新生成后有变化的代码行重叠,从而给人工合并带来了麻烦和困难。
解决这个问题,我目前采取的办法是让生成的代码,尽可能与IDE格式化后的一致。也为此改造了生成引擎,加入自动换行的逻辑。Eclipse的自动换行效果非常好,我本人非常喜欢。它不是简单地每个单词平等对待,到了换行处只是让单词不被断行即可;而是考虑了单词与单词之间的关系,从关系最疏远的地方进行断行,从而使断行后的代码有更佳的阅读效果。比如两个参数: int abc, String def,这里涉及4个单词,分别是int, abc, String ,def,它们的关系是int与abc亲近,String与def亲近,可以简单地表示为(int abc), (String def),所以断行时,会优先在逗号处断行,然后才考虑在空格处断行。
public static PageInfo<PixDepartmentPlanTreeDTO> toPixDepartmentPlanTreeDTO(PageInfo<PixDepartmentPlanTree> pagedList) { // 不太好的断行 } public static PageInfo<PixDepartmentPlanTreeDTO> toPixDepartmentPlanTreeDTO( PageInfo<PixDepartmentPlanTree> pagedList) { // 比较好的断行 }
实际情况,一行代码的单词之间的亲疏关系非常复杂,与语法紧密相关。所以在生成时也得走相同的计算逻辑,才能生成正确的断行。而且由于在模板中需要加入单词之间的亲疏关系,模板中的代码变得臃肿、不直观,影响阅读。为了尽可能地减少对阅读的影响,仅在大概率发生断行的语句中添加单词的亲疏关系。客观讲,某些看起来不长的模板代码行,实际可能由于某个某几个变量名字比较长,导致生成的代码需要断行,从而,无法为需要自动断行与不需要自动断行之间划清界限。不如各位看官,是否有好的解决办法?
有人说,代码生成后不需要人工修改,则一行代码比较长也不要紧,不需要格式化。这个逻辑是对的。只是前面说过,我们将长期处于机器人与人配合完成工作的阶段。
如果使用了上面说的“三路合并”算法,把IDE的自动断行也当作是人工修改的一部分,在一定程度上可以解决这个问题。
博主简介:佘焕敏(shé),洋名 Billy Sir。
关注编程基础技术,并致力于研究软件的自动化生成。 对编程规范化、面向对象的极致使用也有着浓厚的兴趣。 同时非常希望能够写程序到65岁。
只有工匠精神,才能把常人觉得单调乏味的代码,当作作品雕刻成艺术品。
重点:这里几乎每一篇文章,都是我认真创作的,凝结了心血。写作从来都不是一件容易的事,对从小语文不好的我而言,是难上加难。而且,你发现没有,文中没有广告。这篇文章介绍了为什么要写这些文章。
![微信赞赏码](https://img2022.cnblogs.com/blog/33556/202211/33556-20221101085333455-1717538163.png)