不断发展的 .NET 项目的管理和结构
我们正在构建一个用于测试自动化的 .NET 软件平台,供我们公司内部使用。
该应用程序由 GUI (WinForms) 组件和动态加载到其中执行的各种“操作”组成。
大约有 100 个行动项目正在进行中,并且这个数字还在增加。 其中一些项目与其他项目相互依赖,等等。
加载的所有操作都必须引用我们的“SDK”dll 来进行各种活动(主应用程序的结果、日志记录等)。
通过这种相对简单的设计,我们面临着一些我们希望以最佳方式解决的管理决策:
- 操作(“插件”)是否应该引用我们的 SDK 项目输出,或者它的一些已知的稳定版本? 例如,在开发大型应用程序时(仅以 MS Office 为例),并非所有团队都会自然地使用所有组件的源代码。
对于这样的事情最好的解决方案是什么?为什么?
- 如何正确验证所有需要的依赖项(例如第三方库)确实是从正确的位置获取的?
在管理多个相互关联的项目的场景中,常见的做法是什么?这样做有什么建议吗?
We're building a .NET software platform for test automation for in house use in our company.
The application is composed of a GUI (WinForms) component, and various "Actions" that are dynamically being loaded into it to be executed.
There are approximately ~ 100 Action projects going already, with this number increasing.
Some of these projects are interdependent on other projects and so on.
All actions loaded must reference our "SDK" dll for various activities (results to the main app, logging, etc).
With this relatively simple design, we are facing some management decisions that we'd like to solve in the best way:
- Should actions ("plugins") reference our SDKs project output, or some known stable version of it?
For example, when developing a large application (MS Office just for the example), not all teams work with source code for all components naturally.
What is the best solution for something like this ? and why?
- How to properly verify that all needed dependencies (3rd party libraries for example) are indeed taken from the correct location ?
What are common practices in scenarios where managing multitude of projects that are linked in between? are there any tips for doing so ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个没有明确答案的问题,但是...
您可以采取两条路径。强耦合系统或松耦合系统。
对于强耦合系统,我可以建议两个二进制文件目录:一个第三方目录和一个包含贵公司构建的可供其他开发人员参考的 DLL 的目录。第 3 方 DLL(公司外部)应位于源代码管理中,以便所有开发人员从同一位置引用相同版本的第 3 方 DLL,从而避免开发人员计算机不一致以及在每台计算机上安装第 3 方软件的问题。内部 DLL 不应在源代码管理中引用,而应通过自动构建批处理文件或类似文件在每个开发人员计算机上构建。在构建后步骤中,您可以将它们全部复制到同一目录,只要开发人员获得最新的源代码控制和构建,每个人都可以从公司内部获得相同的 DLL。
例如,获取最新版本、构建(使用批处理文件构建所需的所有项目),然后作为构建后步骤将输出复制到 common。现在,您的所有其他项目都可以从同一位置引用通用公司 DLL 和第三方 DLL,并且每个人都是一致的。
问题在于引用是强耦合的,因此如果沟通不正确,更改有时可能会出现问题。
松散耦合的系统使用诸如 MEF(托管可扩展性框架)之类的框架和定义组件接口的组件引用“合同 DLL”。该项目引用接口或合约 DLL,并不真正关心实现,然后 MEF 会为您管理插件。
在这种情况下,您引用接口 DLL,但不引用实现的实际 DLL。
例如,假设我有一个名为 ILog 的接口,其中包含一个名为 LogMessage 的方法。
因此,在强耦合情况下:Action.DLL 直接引用 Logger.DLL。
在松散耦合的情况下,Action.DLL 引用 ILog.DLL(只是接口)。 Logger.DLL 实现 ILog.DLL。但Action.DLL没有直接引用Logger.DLL。
现在我可以拥有任意数量的实现 ILog 接口的 DLL,但 Action.DLL 不会直接引用它们。这非常酷,而且是 MEF 和松散耦合中更令人兴奋的功能之一,即没有依赖关系的能力。
你选择如何走,无论哪种方式都是可以接受的,我认为松散耦合的想法最适合你的场景,因为团队只需要了解合同与实际实现。
我不会有一个庞大的合约 DLL,我会尝试将接口分解为逻辑分组。例如,日志记录似乎是一种实用程序类型的接口,因此我将创建一个带有 ILog 接口的实用程序合约 DLL。如何分割取决于您想要做什么。或者每个接口都可以是一个契约 DLL,但这也许有点极端。
This is a problem that doesn't have a clear answer, but...
There are two paths you can take. A strongly coupled system or a loosely coupled system.
For a strongly coupled system I can suggest two directories for binaries: a 3rd party directory and a directory that houses DLLs that you company builds that other developers can reference. The 3rd party DLLs (outside your company) should be located in source control so that all developers reference the same versions of the 3rd party DLLs from the same location this avoids developer machine inconsistencies and having the problems of installing 3rd party software on every machine. The in house DLLs should not be referenced in source control and should be built on each developers machine via an automated build batch file or similiar. In a build post step you can copy them all to the same directory and as long as developers get the latest source control and build, everyone has the same DLLs from within your company.
For example, get latest, build (using a batch file to build all the projects needed), and then as a post build step copy the output to common. Now all of your other projects can reference the common compnay DLLs and the third party DLLs from the same location and everyone is consistent.
The problem is that the references are strong coupled, so changes can sometimes be problematic if not communicated properly.
A loosely coupled system uses a framework such as MEF (Managed Extensibility Framework) and your components reference "Contract DLL" which define the interfaces for your components. The project reference the interface or contract DLLs and don't really care about the implementation and then MEF manages the plugin for you.
In this case, you reference the interface DLL but not the actual DLL that implements.
For example, say I have an interface called ILog with a method called LogMessage.
So, in a strongly coupled case: Action.DLL references Logger.DLL directly.
In a loosely coupled case Action.DLL references ILog.DLL (just the interface). Logger.DLL implements ILog.DLL. But Action.DLL has no refernce to Logger.DLL directly.
Now I can have any number of DLLs that implment the ILog interface, but the Action.DLL does not reference them directly. That's pretty cool and one of the more exciting features of MEF and loose coupling in general, the ability to not to have dependencies.
How you choose to go, either way is acceptable, I think the loosely coupled idea fits your scenario the best as teams would just have to know the contracts versus the actual implementations.
I wouldn't have one massive contract DLL, I would try and break the interfaces into logical groupings. For example, logging seems like a Utility type of interfance, so I would create a Utility contract DLL with a ILog interface. How it is split up depends on what you are trying to do. Or each interface could be a contract DLL, but maybe that is a little extreme.
这是一个有些复杂的主题,尤其是在 .NET 领域。我不知道“最佳”解决方案,但我会解释我们如何管理它;也许你会觉得它对你自己有用。
这允许您构建具有大量链接项目的大型系统,但会带来很多复杂性问题。我认为任何此类解决方案都会如此。
第一:物理结构(我们使用SVN)。
\lib 文件夹包含要引用的二进制文件。
这些二进制文件可能是第三方库或您需要链接到的其他项目(例如,您的 SDK)。 \lib 下的所有二进制文件均来自企业 ivy 存储库(请参阅 http://ant.apache.org/ivy/< /a>)。这些天,.NET 领域有很多关于 NuGet 的动态,因此您也可以查看一下。
您的版本化 \build 文件夹包含构建脚本,例如从 ivy 获取二进制文件、将项目发布到 ivy 或编译每个项目。当您想要为每个项目指定持续集成服务器时,它们也会派上用场。
第二:定义依赖项来自哪里
答案:它们来自你的ivy存储库(它可以像网络共享文件系统一样简单)。
您已经创建了存储库,因此您可以控制其内容。
请务必小心安装在 GAC 中的第 3 方二进制文件。 Visual Studio 处理这个问题很痛苦。
具体来说:
Ivy 为您提供了极大的依赖关系灵活性,并且还解决了传递依赖关系;例如,您可以依赖于 SDK rev="1.+" status="latest.release",这意味着“最新稳定的 1.x 版本的 SDK,或者依赖于 SDK rev="2.+" status="latest。集成”,这意味着 2.x SDK 的最新可用二进制文件(可能是从持续集成构建生成的)。
因此,您将始终依赖于已编译的二进制文件,而不是项目输出。并且您可以控制要获取哪个版本的二进制文件3rd 方依赖项可能会被引入为 . 这也意味着您的项目中的代码量将保持在您需要的可行 Visual Studio 解决方案的范围内
,这也意味着像 ReSharper 这样的重构工具的用处将会大大减少。关于您的构建脚本和分支策略的一定程度的复杂性在很大程度上取决于您的组件的逻辑,这
是一个简短的概述,如果您认为这是您想要的,我可以扩展答案。 .NET 生态系统和 Visual Studio特别是,并没有真正被认为是这样工作的。
This is a somewhat complex topic, especially in .NET land. I don't know about "best" solution, but I'll explain how we manage it; perhaps you will it useful for yourself.
This allows you to build large systems with lots of linked projects, but incurs in a lot of complexity issues. As, I think, any solution of this kind would.
First: physical structure (we use SVN).
The \lib folder contains binaries to reference.
Those binaries could be 3rd party libraries or other projects that you need to link to (e.g., your SDK). All binaries under \lib come from an enterprise ivy repository (see http://ant.apache.org/ivy/). There is a lot of movement these days in .NET land concerning NuGet, so you could check that out too.
Your versioned \build folder contains build scripts, for example to get binaries from ivy, publish your project to ivy, or compile each project. They will also come in handy when you want to point a Continuous Integration server at each of your projects.
Second: To define where dependencies come from
Answer: They come from your ivy repository (it could be as simple as a network shared file system).
You have created your repository, so you have control as to its contents.
Be very careful with 3rd party binaries that get installed in the GAC. Visual Studio is a pain in the a^^ to deal with this.
Specifically:
Ivy gives you a great flexibility with dependencies, and it also resolves transitive dependencies; e.g., you can depend on SDK rev="1.+" status="latest.release" which would mean "the latest stable 1.x release of SDK, or on SDK rev="2.+" status="latest.integration" which would mean the latest available binary of 2.x SDK (probably as produced from a continuous integration build).
So you will always depend on compiled binaries, never on project output. And you can control which version of the binaries to get. 3rd party dependencies will probably be brought in as transitive upon your SDK.
This also means that the amount of code in your projects will stay as small as you need to have workable Visual Studio solutions. It also means that refactoring tools like ReSharper will be a lot less useful. There will also be a certain amount of complexity concerning your build scripts and your branching strategy. That depends a lot on the logic of your components.
This is a brief overview, if you think this is the sort of thing you want I can expand the answer. Good luck; the .NET ecosystem, and Visual Studio in particular, isn't really thought to work like this.