为什么我分离关注数据库/业务对象/ Web服务,让我编写更多代码?

时间:2009-07-04 17:10:14

标签: design-patterns architecture

我已经阅读了很多关于软件设计的书籍,而且越来越多我想知道我在业务对象和序列化之间分离关注点所学到的东西是否会让我更有效率。

我受域驱动设计的影响,所以当我设计我的业务类时,我不会考虑持久性。与我的数据库/ Web服务技术/缓存技术相关的唯一对象被封装在具有良好域接口的存储库后面。

为了说明,对于传统的应用程序数据库< - > web服务< - > RIA,我设计了我的业务类帐户和员工。 然后,如果我想从数据源获取帐户,我创建一个IAccountRepository,并实现查询或将帐户添加到我的数据源的方法。

要向我的应用程序添加缓存功能,只需创建一个实现IAccountRepository并包装真实存储库的代理类,然后将其注入我的IOC容器中。

为了实现数据库存储库,我使用ORM从我的数据库模式创建类,然后使用create a translator将数据库类转换为业务类,这样我的业务类就与我的数据库模式分离。 / p>

我还为我的Web服务创建专用数据协定类,然后Web服务使用转换器将业务对象的聚合从Web服务角度转换为其数据表示。

当我创建我的RIA应用程序时,我再次设计了自己的域模型,但这次存储库实现使用Web服务而不是数据库(以及翻译器)。

对于WPF开发人员,我创建了我的ViewModel和我的View。

我曾经这样编程。

但是,当我的老板来时说:你可以在这个表格中添加一个字段...... blah blah blah 我必须:

  1. 更新我的数据库
  2. 更新我的数据库翻译器
  3. 更新我的业务对象
  4. 更新我的网络服务翻译(服务器)
  5. 更新我的网络服务翻译(客户端)
  6. 更新我的业务对象(客户端)
  7. 更新我的观点
  8. 对于WPF专家,请更新我的ViewModel
  9. 我越来越想将业务对象与数据库访问技术和Web服务技术或序列化技术结合起来。

    这样我就不再需要维护翻译了。 例如,为什么不在业务对象上使用这些技术的属性/注释?是的它带来了一些禁忌,是的,我需要在我的字段上获取/设置,即使我希望我的属性是只读的,是的,我的业务模块将具有外部依赖性。 但我认为这将导致更少的代码和更可维护的系统。

    我的存储库的实现将是微不足道的,并且不会依赖于翻译。

    虽然我看到以这种方式编写代码的优点,但我总是对这样的代码感到内疚。在我的业务对象上添加5个属性/注释以及我的数据访问技术/ Web服务技术/序列化技术,我感到非常内疚,我觉得这不对。

    为什么我的关注点分离数据库/业务对象/ Web服务,让我编写更多代码?

    你有其他选择吗?

9 个答案:

答案 0 :(得分:6)

你的个人生产力不是重点。

关注点的分离是通过使其可用,可维护和适应性来增加您生成的软件的

如果这会让你写更多代码,我很抱歉,但你的时间通常只是使用,维护和调整你所写内容的终生成本的一小部分。

关注点的分离主要是为了降低终身总体拥有成本。它与你的个人生产力没什么关系。

如果你的老板要求你进行普遍的改变......那么......它很普遍。对不起,这很普遍。


修改1

您的软件的是人们使用生成的值。

“这是代码的纯洁/美丽吗?对我来说,价值在于简单性和可读性。”它既不是。这是将代码应用于现实世界问题所创造的价值。

如果代码难以维护,调整或使用,则会使代码贬值。如果代码易于维护,调整或使用,那么从代码中获取全部价值的障碍就会减少。

与使用它的价值相比,开发代码的时间很短,成本很小。此外,您的开发时间比维护或调整成本更低。

修改2

普遍的变化是构建软件的不可避免的后果。没有 - 没有练习 - 可以阻止你的老板做出破坏你的建筑的改变。

如果您有一个图层,那么几乎任何更改都会破坏该图层。

如果您有3层,7层或n + 1层,您的老板总是可以要求进行多层突破的更改。

这个想法是MOST的变化是孤立的。没有什么能够确保所有变化都是孤立的。

答案 1 :(得分:4)

在设计应用程序时,抽象级别应该提供价值。他们不应该只是因为这是一种“最佳实践”。某些应用程序具有丰富的域模型,并受益于抽象层。但是,如果没有太多逻辑,那么非常以数据为中心的应用程序可能不需要那么多层。

我见过一些应用程序定义了与每个对象相对应的多个层,其名称与EmployeeDL,EmployeeBL,EmployeeUL层完全匹配。没有任何对象添加任何值,只是将层之间的值从用户界面传递到数据库。这毫无意义。

我发现在处理具有更丰富域模型的应用程序时,更改可能会影响多个层,但很少像将UI中的值通过多个层传递到数据库一样简单。如果没有抽象级别,中间的业务逻辑将更加难以实现。

在一天结束时,最重要的是选择符合应用程序需求的架构,以满足其复杂性和可维护性。

答案 2 :(得分:3)

可维护的应用程序是一种维护成本低的应用程序。如果常见的更改需要很长时间,那么这不是一个可维护的应用程序。

要问的关键问题是,与技术变化相比,常见功能请求是多少。

如果您每3个月更改一次首选技术集,那么您将永远没有时间实施新功能,因此您的架构是最佳的......

答案 3 :(得分:2)

我也有同样的经历,我在学校里学到的很多关于抽象和“东西”分离的东西让我的代码变得越来越复杂。

我开始意识到,当你的内聚力很高时(你的课程非常小而非常重要),你具有高耦合度。通过进一步简化每个单独的类,每个组件本身将变得越来越无用;为了获得简单的功能,您需要管理这些简单的“内聚”对象之间的复杂交互。

然后,简单的任务将变得复杂!考虑用Java读取文件,我不记得怎么做(我必须多次这样做),而且我不想再这样做了。

在Python中它很简单:

for line in open("filename"):
    # do something with line

我不是说关注和抽象的分离是不好的,只要做得很好。

IMO,鉴于你重构,即使它是意大利面,它总是更好用“正常工作”。

答案 4 :(得分:2)

你肯定写了太多代码。添加单个字段不应该是一个8步骤过程。

  1. 为什么不使用NHibernate?你可以直到拥有真正的领域模型和“数据库翻译器”(现在)是一个简单的FluentNHibernate练习。

  2. 有一些非常强大的框架可以以相对透明的方式组合步骤4-6。 WCF(恐怖!)。

答案 5 :(得分:1)

这是关于前期投资。正确构建内容所需的时间总是大于构建正常工作所需的时间。 DDD的一个重要内容是,您可以抽象出很多管道并将其用于可以重复使用的开发框架,这样您就不会对其他项目进行高额的初始投资。您可以抽象存储库,工作单元,域对象等的基础。此外,您可以获取实际的数据库功能并将其作为提供程序实现,这样您可以编写一次并为下次工作选择正确的数据库,或者如果您需要更改域对象的后备存储。

正确解决其关注问题的解决方案具有一些非常高效的功能 - 例如它具有高度可测试性,更易于扩展,更易于重用,更易于调试,更易于修改以及更易于扩展。能够看到域如何在代码中流动是一种匆忙,并且能够向利益相关者描述一个概念,或者让他们完成代码工件正在执行的概念,这对于黄金来说是值得的。

对于我的开发人员,起初我很难销售SOC和DDD的概念。除了可测试性,易于调试以及技术资源和利益相关者之间的统一语言之外,许多好处要么在初始部署之后出现,要么根本不出现。例如,您可能不需要向外扩展(例如,围绕您的服务包装外观并将它们放在另一台服务器上以通过Web服务托管REST-ful API),但知道您可以是一种非常非常棒的感觉。

我理解你对涟漪效应的恐惧。说实话,总会出现某种波纹。通过正确设计的存储库,您可以将纹波的大小隔离到几个位置。由于您似乎使用的是.NET(基于WPF注释),因此您可能需要查看.NET Domain-Driven Design with C#: Problem - Design - Solution。虽然我不同意样本中100%的实现,但它确实说明了这种方法的实际效果。

答案 6 :(得分:0)

您使用的是哪些工具?我从来没有听说过如此高度的非自动化废话。我几乎不相信你的问题是真的。你在客户端使用“业务对象”做了什么?

您谈论的是耦合数据访问,业务和Web服务层。这正是的地方!

您的商家实体应与您的商家使用的实际实体相匹配。如果他们碰巧与您的数据库一对一地映射,那么这是巧合。 Web服务提供的业务服务不应该像业务实体上的方法那样精细,因此,不应该直接映射。

绝对是这样的,越来越多的这种应该通过适当的代码生成自动化,但它永远不会是免费的。你将支付一件事,或者你将支付另一件事。在一切都直接映射到数据库的环境中,一旦你将一个表分成两个或三个,你就会突然改变一切。我并不是说只添加一列。

小心你所要求的!

答案 7 :(得分:0)

分离这些东西的重点是

  • 一个开发人员单件工作
  • 每件都可以更容易进行单元测试

除非您有8位开发人员(为了匹配您的八块饼),并且正在编写单元测试代码以匹配生产代码,否则您的安排就会过度。

答案 8 :(得分:0)

还要考虑使用抽象层,这些抽象层可以通过简单的传递实现,但在需要时可以覆盖。

数据库视图就是一个很好的例子 - 我通常让app-layer仅通过视图(由_v后缀清楚地表示)引用数据库表而不是直接引用表名。这些通常引用单个表,每个只有2行DDL。这可以快速创建并易于维护 - 但也可以扩展为在应用程序,orm和amp;之间提供翻译。数据库。

另一个例子是python中的属性 - 你的代码可以直接引用类或实例变量,而不是总是通过setter&干将。然后,如果您需要在类中的变量和访问它的代码之间进行转换,您可以定义一个被调用以传递变量的属性函数。这对调用程序透明地发生。

因此,在这两种情况下,您都可以获得抽象层的值,但只能添加代码和放大器。当你真正需要灵活性时,你需要工作。