许多“小"组件有哪些缺点? [英] Specific down-sides to many-'small'-assemblies?

查看:73
本文介绍了许多“小"组件有哪些缺点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在计划进行一些工作,以将Dependency Injection引入当前的大型单片库中,以期使该库更易于单元测试,更易于理解,并且可能更加灵活.

我决定使用 NInject ,我真的很喜欢Nate的座右铭:做一件事情,做好事" "(措辞),在DI的背景下似乎特别顺利.

我现在一直想知道的是,是否应该将当前单个大型程序集拆分为多个具有不相交特征集的小型程序集.这些较小的程序集中的某些程序集将具有相互依存关系,但彼此之间的依赖关系却远非如此,因为代码的体系结构已经很松散地耦合了.

请注意,这些功能集也不是小事,它们本身也不是很小...它包含诸如客户机/服务器通信,序列化,自定义集合类型,文件IO抽象,通用例程库,线程库,标准日志记录等内容.

我看到一个先前的问题:什么是更好,很多小程序集,还是一个大程序集?这类问题解决了这个问题,但是粒度似乎更细,这使我想知道那里的答案是否仍然适用于这种情况? >

此外,在接近该主题的各种问题中,一个常见的答案是,装配过多"装配会导致未指定的疼痛"和问题".我真的很想具体地知道这种方法可能带来的不利影响.

我同意在只需要1个组件之前添加8个程序集是一件痛苦的事",但是对于每个应用程序都必须包含一个大型的整体库也不是完全理想的...加上8个组件是一件很麻烦的事情.你只做一次,所以我对这个论点几乎没有同情心(即使我起初可能会和其他所有人一起抱怨).

附录:
到目前为止,我还没有找到针对较小的程序集的令人信服的理由,因此,我认为我现在将继续进行,好像这不是一个问题.如果有人能用可验证的事实想到充分可靠的理由来支持它们,那么我仍然会非常有兴趣了解它们. (我会尽快添加赏金以提高知名度)

编辑:将效果分析和结果移到单独的答案中(见下文).

解决方案

我将为您提供一个真实的示例,其中许多(非常)小的程序集的使用产生了.Net DLL Hell.

在工作中,我们有一个庞大的本地开发框架,该框架长牙无牙(.Net 1.1).除了常用的框架类型管道代码(包括日志记录,工作流,排队等)之外,还存在各种封装的数据库访问实体,类型化的数据集和一些其他业务逻辑代码.我并没有参与该框架的最初开发和后续维护,但确实继承了它的使用.正如我所提到的,整个框架产生了许多小的DLL.而且,当我说很多的时候,我们说的是100以上-而不是您提到的可管理的8个左右.更复杂的问题是,这些程序集都经过了简单的签名,版本控制,并出现在GAC中.

因此,快进了几年,随后又进行了许多维护周期,结果是,对DLL及其支持的应用程序的相互依赖性造成了严重破坏.在每台生产机器上,machine.config文件中都有一个巨大的程序集重定向部分,该部分确保无论请求什么程序集,Fusion都会加载正确的"程序集.这源于重建依赖于已修改或升级的每个依赖框架和应用程序程序集所遇到的困难. (通常)会竭尽全力确保在修改装配时不对装配体进行重大更改.装配被重建,并在machine.config中创建了新的或更新的条目.

在这里,我会停下来听听巨大的collective吟声和喘息声!

这种特殊情况是不采取行动的后代.确实,在这种情况下,您将陷入一种完全无法维护的情况.我记得我刚开始使用它花了2天的时间就可以针对该框架进行开发,以解决我的机器问题-解决了我的GAC和运行时环境的GAC之间的差异,machine.config程序集重定向,由于编译时版本冲突由于直接引用组件A和组件B而导致错误的引用,或者更可能的版本冲突,但是组件B引用了组件A,但是版本与我的应用程序的直接引用不同.你明白了.

此特定方案的真正问题是程序集的内容过于精细.而且,这最终导致了相互依存关系的纠结.我的想法是,最初的架构师认为这将创建一个高度可维护的代码系统-只需重建对系统组件的很小改动即可.实际上,事实恰恰相反.此外,对于已经发布在此处的其他一些答案,当您达到如此数量的程序集时,加载大量程序集确实会导致性能下降-肯定是在解析过程中,尽管我没有经验证据,但我想我会猜到在某些极端情况下,运行时可能会受到影响,特别是在反射可能起作用的情况下-在那一点上可能是错误的.

您可能会鄙视我,但是我相信程序集存在逻辑上的物理分隔-当我在这里说程序集"时,我假设每个DLL一个程序集.归结为相互依赖.如果我有一个依赖于程序集B的程序集A,我总是问自己是否需要在不使用程序集A的情况下引用程序集B.或者,这种分离是否有好处?通常,查看如何引用程序集也是一个很好的指标.如果要将大型库划分为程序集A,B,C,D和E.如果90%的时间引用了程序集A,因此,您始终必须引用程序集B和C,因为A依赖于程序集B和C ,那么将程序集A,B和C组合在一起可能是一个更好的主意,除非有一个令人信服的论点允许它们保持分离. Enterprise Library是这种情况的经典示例,您几乎总是必须引用3个程序集才能使用库的一个方面-但是,对于Enterprise Library而言,它具有在核心功能和代码之上进行构建的能力重用是其架构的原因.

看看架构是另一个很好的准则.如果您有一个很好的干净堆叠的体系结构,其中您的程序集依赖项为堆栈形式,请说垂直",而不是"web",当您在各个方向上都具有依赖项时就开始形成"web",然后分离程序集在功能边界上有意义.否则,请考虑将其整合为一体或重新架构.

无论哪种方式,祝你好运!

I am planning out some work to introduce Dependency Injection into what is currently a large monolithic library in an attempt to make the library easier to unit-test, easier to understand, and possibly more flexible as a bonus.

I have decided to use NInject, and I really like Nate's motto of 'do one thing, do it well' (paraphrased), and it seems to go particularly well within the context of DI.

What I have been wondering now, is whether I should split what is currently a single large assembly into multiple smaller assemblies with disjoint feature sets. Some of these smaller assemblies will have inter-dependencies, but far from all of them, because the architecture of the code is pretty loosely coupled already.

Note that these feature sets are not trivial and small unto themselves either... it encompasses things like client/server communications, serialisation, custom collection types, file-IO abstractions, common routine libraries, threading libraries, standard logging, etc.

I see that a previous question: What is better, many small assemblies, or one big assembly? kind-of addresses this issue, but with what seems to be even finer granularity that this, which makes me wonder if the answers there still apply in this case?

Also, in the various questions that skirt close to this topic a common answer is that having 'too many' assemblies has caused unspecified 'pain' and 'problems'. I would really like to know concretely what the possible down-sides of this approach could be.

I agree that adding 8 assemblies when before only 1 was needed is 'a bit of a pain', but having to include a big monolithic library for every application is also not exactly ideal... plus adding the 8 assemblies is something you do only once, so I have very little sympathy for that argument (even tho I would probably complain along with everyone else at first).

Addendum:
So far I have seen no convinging reasons against smaller assemblies, so I think I will proceed for now as if this is a non-issue. If anyone can think of good solid reasons with verifiable facts to back them up I would still be very interested to hear about them. (I'll add a bounty as soon as I can to increase visibility)

EDIT: Moved the performance analysis and results into a separate answer (see below).

解决方案

I will give you a real-world example where the use of many (very) small assemblies has produced .Net DLL Hell.

At work we have a large homegrown framework that is long in the tooth (.Net 1.1). Aside from usual framework type plumbing code (including logging, workflow, queuing, etc), there were also various encapsulated database access entities, typed datasets and some other business logic code. I wasn't around for the initial development and subsequent maintenance of this framework, but did inherit it's use. As I mentioned, this entire framework resulted in numerous small DLLs. And, when I say numerous, we're talking upwards of 100 -- not the managable 8 or so you've mentioned. Further complicating matters were that the assemblies were all stronly-signed, versioned and to appear in the GAC.

So, fast-forward a few years and a number of maintenance cycles later, and what's happened is that the inter dependencies on the DLLs and the applications they support has wreaked havoc. On every production machine is a huge assembly redirect section in the machine.config file that ensures that "correct" assembly get's loaded by Fusion no matter what assembly is requested. This grew out of the difficulty that was encountered to rebuild every dependent framework and application assembly that took a dependency on one that was modified or upgraded. Great pains (usually) were taken to ensure that no breaking changes were made to assemblies when they were modified. The assemblies were rebuilt and a new or updated entry was made in the machine.config.

Here's were I will pause to listen to the sound of a huge collective groan and gasp!

This particular scenario is the poster-child for what not to do. Indeed in this situation, you get into a completely unmaintainable situation. I recall it took me 2 days to get my machine setup for development against this framework when I first started working with it -- resolving differences between my GAC and a runtime environment's GAC, machine.config assembly redirects, version conflicts at compile time due to incorrect references or, more likely, version conflict due to direct referencing component A and component B, but component B referenced component A, but a different version than my application's direct reference. You get the idea.

The real problem with this specific scenario is that the assembly contents were far too granular. And, this is ultimately what caused the tangled web of inter dependencies. My thoughts are that the initial architects thought this would create a system of highly maintainable code -- only having to rebuild very small changes to components of the system. In fact, the opposite was true. Further, to some of the other answers posted here already, when you get to this number of assemblies, loading a ton of assemblies does incur a performance hit -- definitely during resolution, and I would guess, though I have no empirical evidence, that runtime might suffer in some edge case situations, particularly where reflection might come into play -- could be wrong on that point.

You'd think I'd be scorned, but I believe there are logic physical separations for assemblies -- and when I say "assemblies" here, I am assuming one assembly per DLL. What it all boils down to are the inter dependencies. If I have an assembly A that depends on assembly B, I always ask myself if I'll ever have the need to reference assembly B with out assembly A. Or, is there a benefit to that separation. Looking at how assemblies are referenced is usually a good indicator as well. If you were to divide your large library in assemblies A, B, C, D and E. If you referenced assembly A 90% of the time and because of that, you always had to reference assembly B and C because A was dependent on them, then it's likely a better idea that assemblies A, B and C be combined, unless there's a really compelling argument to allow them to remain separated. Enterprise Library is classic example of this where you've nearly always got to reference 3 assemblies in order to use a single facet of the library -- in the case of Enterprise Library, however, the ability to build on top of core functionality and code reuse are the reason for it's architecture.

Looking at architecture is another good guideline. If you have a nice cleanly stacked architecture, where your assembly dependencies are int the form of a stack, say "vertical", as opposed to a "web", which starts to form when you have dependencies in every direction, then separation of assemblies on functional boundaries makes sense. Otherwise, look to roll things into one or look to re-architect.

Either way, good luck!

这篇关于许多“小"组件有哪些缺点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆