Asa*_*saf 19 java usability software-design code-duplication
我最近对我在项目代码库中出现的问题越来越感到沮丧.
我正在开发一个拥有> 1M行代码的大型java项目.接口和类结构设计得非常好,编写代码的工程师非常精通.问题在于,为了使代码更清晰,人们在需要重用某些功能时编写实用程序类,随着时间的推移,随着项目的增长,越来越多的实用程序方法出现.但是,当下一位工程师遇到对相同功能的需求时,他无法知道有人已在代码中的某处实现了实用程序类(或方法),并在另一个类中实现了该功能的另一个副本.结果是大量代码重复和太多具有重叠功能的实用程序类.
我们作为一个团队可以实施任何工具或任何设计原则,以防止实用程序类的重复和低可见性吗?
示例:工程师A有3个位置需要将XML转换为String,因此他编写了一个名为XMLUtil的实用程序类,并toString(Document)在其中放置一个静态方法.工程师B有几个地方将文档序列化为各种格式,包括String,因此他编写了一个名为SerializationUtil的实用程序类,并且有一个名为static的方法serialize(Document),它返回一个String.
请注意,这不仅仅是代码复制,因为上述示例的2个实现很可能是不同的(例如,一个使用变换器API而另一个使用Xerces2-J),因此这可以被视为"最佳实践" "问题也是......
更新:我想我更好地描述了我们开发的当前环境.我们使用Hudson进行CI,使用Clover进行代码覆盖,使用Checkstyle进行静态代码分析.我们使用敏捷开发,包括日常会谈和(可能不充分)代码审查.我们在.util中定义了所有的实用程序类,由于它的大小现在有13个子包,在根(.util)类下有大约60个类.我们还使用第三方库,例如大多数apache commons jar和一些组成Guava的罐子.
我很肯定,如果我们让某人完成重构整个软件包的任务,我们可以减少一半的公用事业,我想知道是否有任何工具可以降低成本,并且有任何方法可以可以尽可能地延迟重复出现的问题.
解决此问题的一个好方法是开始添加更多面向对象.要使用您的示例:
示例:工程师A有3个位置需要将XML转换为String,因此他编写了一个名为XMLUtil的实用程序类,并在其中放置一个静态toString(Document)方法
解决方案是停止使用JVM(String,Integer,java.util.Date,java.w3c.Document)提供的基本类型或类型,并将它们包装在您自己的项目特定类中.然后您的XmlDocument类可以提供方便的toString方法和其他实用程序方法.您自己的ProjectFooDate可以包含解析和格式化方法,否则这些方法最终会出现在各种DateUtils类等中.
这样,只要您尝试对某个对象执行某些操作,IDE就会使用您的实用程序方法提示您.
你的问题很常见.也是一个真正的问题,因为没有好的解决方案.
我们在这里处于相同的情况,我会说更糟糕的是,有1300万行代码,营业额和超过800名开发人员正在编写代码.我们经常讨论您描述的同一个问题.
第一个想法 - 您的开发人员已经使用过 - 是在一些实用程序类中重构公共代码.我们对该解决方案的问题,即使是结对编程,指导和讨论,我们实在是太多了,不能有效.事实上,我们在子团队中成长,人们在他们的子团队中分享知识,但知识不会在子团队之间传递.也许我们错了,但我认为即使是结对编程和谈话在这种情况下也无济于事.
我们还有一个架构团队.该团队负责处理设计和架构问题,并制作我们可能需要的常用实用程序.事实上,这个团队产生的东西我们称之为企业框架.是的,它是一个框架,有时它运作良好.该团队还负责推动最佳实践,并提高对应该做什么或不做什么,可用什么或什么不可行的意识.
良好的核心Java API设计是Java成功的原因之一.好的第三方开源库也很重要.即使是精心设计的小型API也可以提供真正有用的抽象,并且可以帮助减少代码量.但是你知道,制作框架和公共API完全不同于在2小时内编写实用程序类.它的成本非常高.实用程序类的初始编码需要2个小时,调试和单元测试可能需要2天.当您开始在大型项目/团队中共享公共代码时,您确实创建了一个API.您必须确保完美的文档,真正可读和可维护的代码.当您发布此代码的新版本时,您必须保持向后兼容.你必须在公司范围内(或至少在整个团队范围内)推广它.对于小型实用程序类,从2天开始,对于完整的API,您将增长到10天,20天甚至50天.
而您的API设计可能不是那么好.嗯,并不是说你的工程师并不聪明 - 事实上他们确实如此.但是你是否愿意让他们在一个小实用程序类上工作50天,这个实用程序类只是帮助以一致的方式为UI解析数字?当您开始使用具有完全不同需求的移动UI时,您是否愿意让他们重新设计整个事物?还有你注意到这个词中最聪明的工程师如何制作永远不会流行或会慢慢褪色的API?你看,我们制作的第一个web项目只使用内部框架或根本没有框架.然后我们添加了PHP/JSP/ASP.然后在Java中我们添加了Struts.现在JSF是标准.我们正在考虑使用Spring Web Flow,Vaadin或Lift ......
我想说的是,没有好的解决方案,开销会随着代码大小和团队规模呈指数级增长.共享一个大代码库会限制您的敏捷性和响应能力.必须仔细进行任何更改,您必须考虑所有潜在的集成问题,并且每个人都必须接受新特性和功能的培训.
但是,软件公司的主要生产力点在解析XML时不会获得10行甚至50行代码.执行此操作的通用代码无论如何都将增长到一千行代码,并重新创建一个复杂的API,它将由实用程序类分层.当这个人创建一个实用程序类来解析XML时,它是一个很好的抽象.他给出了十几行甚至一百行专门代码的名称.此代码很有用,因为它是专门的.通用API允许处理流,URL,字符串等.它有一个工厂,所以你可以选择你的解析器实现.实用程序类很好,因为它只适用于此解析器和字符串.而且因为你需要一行代码来调用它.但是,当然,这个实用程序代码的用途有限.它适用于此移动应用程序,或用于加载XML配置.这就是为什么开发人员首先为它添加了实用程序类.
总而言之,我会考虑而不是尝试整合整个代码库的代码,而是在团队成长时分解代码责任:
你真正管理的是复杂性.最后,如果你制作一个非常通用的高级代码库,那么你就会增加新手加速的时间,增加开发人员根本不会使用你的公共代码的风险,你会因为任何改变而放慢每个人的速度有更大的机会破坏现有的功能.