自从ASP.NET问世以来,我一直很欣赏人们对困境的看法。
在经典ASP中,代码层很少。 ASP页面包含HTML和脚本组合。 COM组件包含业务逻辑和DAO基础设施。 ASP页面本身很混乱,但一切都在一个地方。
ASP.NET的代码隐藏了代码,这很好。控件允许我们在表示层上更加面向对象。这些都很好。
这是我的问题。我进入的许多项目都是企业Web应用程序,但并非所有复杂的项目,例如10个左右的网页/用户界面,大量的数据库交互等等。这些过去常常是一块蛋糕。现在我经常会遇到5到10层代码来创建一个相当简单的网页。这些可能包括ASP,代码隐藏,控制类,DTO类,ORM对象,然后还有一些其他人只是因为它而被抛出。
除了要访问数据库的5-10层之外,还有许多用于存储普通数据的自定义对象,而不是使用POCO(普通的旧CLR对象),例如集合。要理解这些对象,通常需要追溯包含3个或更多级别对象和接口的继承层次结构。
以下是关键所在:以前,我查看了1个ASP页面并说了1或2个小对象,一些SQL查询,这些完成了工作并且维护和理解起来相当简单。
现在,对于同一页面,可能会有50个或更多对象,在自定义命名空间中传播数百个对象。
我问你,代码工匠,这是进步吗?是否有些人对他们有趣的新设计模式玩具有点过分了?有幸福的媒介吗? 有没有办法有效地使用设计模式而不创建如此多的对象,使得意大利面条代码变得比旧的程序范例更糟糕?
请分享您的想法。
答案 0 :(得分:19)
撇开组织需要这些抽象级别的可能性(不太可能,但确实发生),开发人员(特别是在非敏捷的企业/企业环境中)添加太多层次是非常常见的抽象。它发生在经典的ASP上,.NET让它变得更容易。我们这个职业的大多数人都有过于复杂化的自然倾向,需要纪律和积极的思维来克服这一点。
此外,许多平庸的开发人员错误地认为,最大化抽象层和模式使用会使他们成为更好的开发人员。
最后,许多平庸的开发人员被教导他们应该使用图层,抽象和模式,但是没有足够好地教授知道如何,何时或为何。所以他们进入一个项目思考“好吧,我知道我应该在这里有一些层......”你可以想象出来的是什么。
最终,最佳实践的“最佳实践”是尽可能简单地编码直到遇到真正的问题,这会妨碍您前进。很多时候,你应该在你的工具箱中有一个模式或最佳实践,这对于任务是正确的,就像你有一个正确的螺母扳手一样。最佳实践和模式是工具 - 你不会拿出锤子并开始摆动,直到你有一个需要砸的钉子。与软件开发类似。
答案 1 :(得分:12)
有些人architecture astronauts,他们会坚持认为这些图层都是必需的,除非你包含它们,否则设计绝对是垃圾。
另一方面,人们把这一切都放在一边,只是将代码全部放在一起:它很简单,对,为什么不在代码隐藏中填充到列表框中的SQL查询呢?控制?
你已经确定了宇航员版本的问题,执行简单任务就太复杂了。
第二种方法的问题在于,虽然它适用于小型小应用程序,但这些应用程序倾向于成长为大型应用程序,然后全部崩溃。您花费大量时间反复修复相同的错误,因为相同的查询或代码片段已根据需要进行复制/粘贴,并稍作修改,并在任何地方传播。
当然,有一个中间立场。根据你问的是谁,究竟是哪个谎言会有所不同......但它就在那里。
建立一个理智的业务层是实现这一目标的一个很好的一步。这应该是一个层,它提供了系统中对象的最简单视图,并且不包含面向公共的数据库相关的东西(除了可能告诉业务层如何到达数据库的Connection对象)。这将您的所有逻辑合并到一个地方,因此项目的ASP部分只是将抽象的“User.LoadAll()”方法连接到显示用户列表的表。 ASP应用程序应该没有任何线索,如果它是从数据库,Web服务,或只是一堆组成的东西读取...它只是与业务层进行对话。
在业务层下,你可以直接查询,你可以使用ORM,你可以建立一个更深层次的数据访问层来完成这些事情。好处是这个决定完全由业务层包含(你可以如果需要,稍后更改它,而不会影响业务层的公共API)。
现在处理用户的任何查询都包含在User对象中..如果您对加载权限的方式有错误,可以在一个地方修复它。
我刚刚进行了一次迁移,就像我上面描述的那样(在代码隐藏中使用SQL,在不同的表示 - 业务 - 数据源(ORM)层中使用ASP),这很棒。虽然它确实增加了一些层次来获取实际信息,但是一旦业务方法起作用,其余代码就可以工作。修复错误很简单,并在任何地方修复它。接近结束时,很快就会出现这样的情况:当您需要获取用户可以运行的报告列表时,有人已经为此编写了一个业务方法(User.GetReports()),之前,您可能永远不会找到它,如果它已经完成 - 如果你很幸运,它被写成一个函数而不仅仅是内联代码。
答案 2 :(得分:4)
我参与了在相反方向上做得很差的项目(200多MB源树没有设计模式)。相信我,这也不是正确的解决方案。代码变得无法维护,开发人员绊倒的旧代码等等。
另一方面,回答有关设计模式的问题:
不,这不是进步。是的,有些人会过火。可能有一种幸福的媒介,但我认为它需要世界的设计模式让我们冷静一点。
我尽量让解决方案变得简单。这可能涉及设计模式......或者可能不涉及;它确实无关紧要,只要它有效,并且易于维护。重要的是......设计模式不是解决不良代码的灵丹妙药。仅仅因为一个人使用设计模式并不意味着一个人的代码写得很好。不幸的是,太多的开发人员被教导(或相信他们自己):如果他们使用设计模式,他们的代码质量更高;这不一定是真的(我认为,定期不是这样)。
顺便说一句:如果您想要一个优秀的过度设计示例,请查看CruiseControl.NET托盘应用程序的源代码。这是一个极好的设计模式演示(老实说,Thoughtworks作为一个整体是一个很好的演示)。
答案 3 :(得分:3)
我认为您所看到的大部分内容可能是正式的业务层和数据层代码。在这种情况下,代码应该遵循明确定义的模式,以便明确的是什么,(更重要的是)为什么。如果不是这样,你就不会看代表性的ASP.NET代码。
与您关于易于关注Classic ASP的争论相反,我发现任何规模的经典ASP网站很快就会成为未记录的包含文件的迷宫,因此很难确定函数的实现位置或者变量声明。
主要的是ASP.NET在帮助开发人员安全地重复使用代码方面比经典ASP做得好得多,所以当他们利用它时不要感到惊讶。
现在,这并没有真正解决您对分层设计过度使用的顾虑。真的,我认为这取决于具体情况。如果您的网站是唯一系统访问数据库并且它不是那么大,那么可能它太过分了。但即使在这种情况下,大多数数据和业务层代码都可以由ORM解决方案编写,这是一件好事,因为这样的代码通常没有错误,可以被推到你的某个黑暗角落修订系统,忘记了。然后,当(不是“如果”)网站成长为可以实际利用精心构建的数据层的东西时,此代码已经到位以支持它,而且生产或维护成本非常低。
另一方面,如果您的网站与企业报告软件或用于管理的Windows桌面应用程序共享数据库的访问权限,或者几个小型应用程序与同一数据库通信,则可能所有这些“额外”代码都可用一个目的。编写数据和业务层代码的一个重要原因是,这些代码可以在与数据库通信的每个不同系统之间共享,这样这些代码就可以在一个地方实现。也许这是为小型网站编写的大量代码,但在这种情况下,它不是为该网站编写的。它是为网站 - 以及其他几个应用程序 - 运行的环境而编写的。
答案 4 :(得分:3)
对我来说,问题源于过多的文章,其中作者没有花时间来解释解决方案的上下文。
为一家中型企业编写业务应用程序的人如果要锁定某些技术,那么构建应用程序的方式与为向其他公司销售软件的供应商工作的人不同。
因此,对于那些想要做“正确的事”的缺乏经验的开发人员,我认为过度工程是一个容易陷入的陷阱。
然后还有其他人只希望每个项目都“完美”。我不知道该怎么说这些家伙。我从来没有足够的时间或预算来使任何项目“完美”。
答案 5 :(得分:2)
我认为在Classic ASP中使用我熟悉的设计模式会很困难,因此在这方面我们领先于游戏。
虽然我没有在ASP.NET中使用MVC实现,但我的理解是它解决了许多问题,因为它更加直接和简单。
答案 6 :(得分:1)
您所命名的所有工具和技术的目的是在快速变化的业务需求的世界中管理复杂性。 “复杂性和快速变化的业务需求”是否代表了应用程序所在的世界?
答案 7 :(得分:1)
我认为这是一个更高层次的一般原则的例子。
就像我们以前在小学时使用的剪刀一样,圆形的尖端和钝的边缘。你不能很好地削减,但你也不能轻易地(或任何其他人)。
任何有力的东西都会带来更大的利益和更大的潜力......否则。
微软非常值得他们提供具有较低入门门槛的工具,所以任何老程序员都可以相对快速地完成一些有用的工作。但是由于它们的简单性,有时它们不能很好地扩展,并且你需要升级到更复杂的工具集 - 但是学习如何正确有效地使用新东西是值得的。所以你的问题很好,因为这是“先了解它”过程的一部分。
答案 8 :(得分:0)
这是进步而不是进展。我们使用的新工具的使用情况可能是这里的问题,因为有些可能过度构建而其他可能正在构建,例如,一切都在从标记到数据库逻辑到业务逻辑的代码中,只是为了将它们保持在一起。
在某些情况下,可以在某些地方使用设计模式作为解决问题的好方法。例如,在之前的作业中,有些设备需要支持一些常用命令,因此我为每种类型的设备构建了一个适配器类和一个类,可以很好地解决问题。设计模式帮助的另一个例子是使外观模式隐藏外部系统如何运行的一些细节,以便有一个共同的内部功能列表来支持。
答案 9 :(得分:0)
感谢所有评论到目前为止。为了澄清一点,在经典ASP中我们使用的是VB组件,这自然限制了我们使它们过度复杂化的能力,从某种意义上来说它很简单。
我喜欢Rex的回复“最终,最佳实践的”最佳实践“是尽可能简单地编码,直到遇到阻碍您前进的真正问题。”
这听起来与我听到的另一个相似的是“过早优化是所有邪恶的根源。”
在此之后,如果我们将所有总线逻辑放在代码隐藏中然后将其移动到共享库中,那么我们发现哪些代码真的会被多个页面使用呢?例如,如果它是一个页面,您可以拥有代码隐藏中的所有内容。如果有两个页面共享一个逻辑,则创建一个组件。如果两个组件使用SQL Server,则创建一个新组件以简化SQL查询等。
我也很喜欢Dana在构建自定义应用程序与单个应用程序之间的区别。如果1000个其他人将使用它,那么拥有一个完整的API是一回事。将相同的能量投入到一次性应用中可能是浪费时间。
“建筑宇航员”是一个过度工程化趋势的伟大术语!
许多人表示存在中间立场,我认为(希望)这就是我们都在寻找的东西!也就是说,C#使我们能够rocket science,但是这个级别可能只需要5%的时间。我认为这个问题更加恶化的事实是,现在大多数采访者都喜欢你在所有的火箭科学中都非常熟悉......
我想提出的另一个相关问题是:如何使用POCO(.NET提供的)对象在ASP.NET体系结构中存储数据。我已经看到一些架构为每种类型的数据交换创建一个新对象。仅仅创建一个集合对象(比如列表)并将其称为“此数据”,“那个数据”等不是更简单吗?
答案 10 :(得分:0)
根据我的经验,你根本不使用自定义数据库对象会更敏捷。在较旧的.NET版本中,您可以传递DataTable对象。在.NET 3.5中,您可以使用LINQ免费获得强大的类型。
令人惊讶的是,一些开发人员花费75%的时间从数据库中检索数据。没有任何自定义代码,哪个.NET完美无缺。使用标准库,您会发现有更多时间来解决业务问题。