Wednesday, July 30, 2008

The LinFu Reimplementation Plan, and Dogfooding

Before I hit the ground coding, let's go over some of the features that were in LinFu v1.0 that will also be in 2.0:
  1. Dynamic Proxies
  2. Late Binding / Multiple Dispatch
  3. Duck Typing
  4. Mixins
  5. Universal Event Handling
  6. Closures with Lambda Arguments
  7. Design By Contract
  8. AOP (static and dynamic weaving)
  9. Inversion of Control / Dependency Injection
  10. Adaptive Object Models
  11. A MyXaml Engine Clone
Aside from the fact that v1.0 has a fairly hefty feature list, one thing that I've noticed with the source is that despite those features, LinFu itself doesn't really use its own IoC or DbC facilities to improve the quality of its own code, and that's a wasted opportunity.

With that in mind, I've decided to implement the following features first:
  • Inversion of Control / Dependency Injection
  • Dynamic Proxies
  • Design by Contract
  • Static AOP Weaving
Building an IoC/DI container will help enforce a separation of concerns, and using Design by Contract in tandem with TDD will eliminate over 90% of the bugs in the code. The reason why I'm also implementing the static AOP weaving and dynamic proxy generator first is that there has to be a way to transparently inject those contracts into a service instance using a dynamic proxy without having to clutter the original source code. In addition, using the static AOP weaving in a debug build will allow me to dynamically inject diagnostic code without affecting the actual release build.

As for LinFu's Design by Contract v3.0, my goal is to make it injection-agnostic. That means that the library itself should be completely unaware of how it's actually being injected into a service instance. It will allow you to inject contracts using a 3rd-party dynamic proxy generator (such as Castle), and most importantly, it should make no distinction between LinFu's static AOP injection and its own proxy generator.

Probably the most striking difference that you'll see between v1 and v2 is that LinFu will no longer be split into multiple projects (aside from PostWeaver.exe, and the MSBuild task for LinFu.AOP). There might be some who might say that clumping all of LinFu into one DLL violates the principle of Separation of Concerns, but in practice, it will save you an untold amount of headaches when managing your project dependencies.

I realize that rebuilding LinFu is a very tall order, and I'm putting my heart and soul into this one to make sure that it's the best code that I'll ever write. This is going to take some time to redo, and I'll keep posting more and more updates on my blog as time progresses.

7 comments:

  1. A word of advice:
    You should split LinFu into seeral projects, and merge them together using ILMerge on delivery.
    This will easy the maintainabilty of your code base, while achieving your "one dll" vision (which is good).

    ReplyDelete
  2. I'm a new fan of LinFu for its dynamic proxy features, and I will probably only use this part. So merging it all to a single assembly is, to me, a bad idea.
    For example, take a look at Spring.NET, where there is a core, and an AOP assembly, and some more. This is not too much (since there are probably 4 or 5 assemblies covering the whole features set), and can be used as required.
    Long comment. Sorry :)
    Also, take a look at architectured applications (>= medium size), where you find at least two assemblies per layer (interface and implementation), and again, this is not too much.
    There are several ways to split LinFu:
    - per feature split, so each functionaly (or group of) will have its own assembly
    - per support split, for example, if you support a specific framework part, then you have an assembly dedicated to it.
    And both options are not exclusive (for example, Spring.NET has an AOP assembly, this is a feature assembly, and also a WCF assembly, this is a support assembly).
    Long comment, sorry :)

    ReplyDelete
  3. @picrap/anonymous:

    Done. From now on, each LinFu feature will be split into at least a single interface assembly and a separate implementation DLL.

    If you take a look at the development branch, you'll see that the first project (LinFu.IoC) has been organized in that fashion. Enjoy!

    p.s. If you have any feedback on the existing development branch, please don't hesitate to drop me a comment or two. Thanks!

    ReplyDelete
  4. No offense to the previous posters, but after many years of advocating breaking things down into different assemblies I have personally learned that hard way that splitting assemblies is worth essentially zero, except in the specific cases where you need to expose interfaces and/or base classes with absolutely stable versioning and/or need to isolate dependencies on third-party components into pluggable assemblies. Splitting your work up for any other reason is a red herring and will cause only one thing: slower builds.

    ReplyDelete
  5. ... ignoring for the moment the need to distribute pieces across different physical systems, which I didn't bother to mention in my list because it doesn't seem applicable to LinFu.

    ReplyDelete
  6. I agree with Jeremy.
    Basically my deal is that you only get to create a new assembly if you can sit down and justify its existence in plain terms. If you can't do that it's no dice.

    I've worked on projects with over 650 .dlls before and that's a horror no-one should ever need to face if it is an option.

    ReplyDelete
  7. @Jeremy Gray/Jax:

    I understand why one would separate the "interface.dll" from "implementation.dll", but what I'm not entirely sure about is whether or not everything should be clumped into one a single DLL, much like a big ball of mud.

    On the other hand, the "Ala carte" approach seems a bit more clean since it lets you focus on the code that's relevant to the current library at hand.

    As for build times, I certainly don't see LinFu ballooning to any extreme size (such as the 650+ DLLs) Jax mentioned.

    In practice, it only took me about ten seconds to rebuild all 24 of LinFu v1.0's projects in release mode using my modest 1.8Ghz dual-core laptop, and if I can do this in ten seconds, I can only imagine how fast it would be on some of the better quad-core setups that some developers have today.

    So my stance on this issue is that while it can pose a significant problem on paper, in practice, it doesn't pose so much of a problem for LinFu that people are actually complaining about the build times, much less handling any possible dependency issues associated with multiple DLLs.

    FWIW, I easily can shift back and forth between the two paradigms, but I'll stick with what I have right now until I can see enough real edge cases that would merit a shift back to the "one.dll" approach.

    I can only go so far on hearsay before I make the library stable, and stick with it--and that's not to say that both your points are invalid--on the contrary, they're very well grounded.

    What I have to do, however, is to keep the API as stable as possible, and right now, that takes precedence over issues (or extreme edge cases) that have yet to materialize.

    If build times for LinFu become a problem, however, I won't hesitate to take action, and if the dependencies get too entangled, then I'll consider merging everything down to a single DLL.

    ReplyDelete

Ratings by outbrain