Thursday, January 31, 2008

Objects vs SoC Objects

Object Oriented Programming rocks the house. The reason why it is good can be summed up with a single word: Abstraction.

I had an awesome professor in college who said that a person is only so smart. They can only keep so many things in their minds at one time and can only fully understand some of those already limited things. The only way, then, that a person can do anything complicated is to abstract out the details. This frees up more space in their limited heads for other things.

This is true. And because it's so enormously true I'm going to provide some examples of abstractions people use all the time.
  1. Language
  2. Money
  3. Time, Dates
  4. Math
  5. Physics
Language is certainly the most powerful example. I say "Dog" and you know what I mean. I could also say say "Golden Retriever." Or I could try not to be so abstract and say "Four legged animal with ears, eyes, tail, nose with extremely sensitive smell, hair all over, and isn't a cat." Of course, now I'm wrong, because there are Dogs that have no hair... So, obviously, language is a very powerful abstraction.

In computer programming, we have programming languages. "Modern" programming languages are typically considered modern because they allow more powerful abstractions. Object Orientation is one such abstraction. Though I'm not sure it really qualifies as "modern" anymore...

It's important that programming languages have good abstraction techniques. Software development is complicated. So for a person to do software development they must be able to abstract things. Its not enough to just abstract things on paper either. Things have to be abstracted in code. What are these things? Algorithms and data. That's about all there is in programming. You have data that has some meaning and you have algorithms that manipulate that data in meaningful ways.

Objects allow us to abstract both data and algorithms. Typically the algorithms are still quite detailed, but we can abstract the details into an object so we don't have to think about them. (Aside: Functional programming allows you to make your algorithms more abstract with fewer details.)

Objects let us abstract things by grouping a set of data and algorithms together into a single named container. And then it goes one step further and lets us create many instances of those containers. So now I can have a Dog object. And I can create many of them. And they can have names and colors and weights and heights and any other data they need. They can also bark and whine and soil the carpet and any other actions (algorithms) they need.

Objects also let us represent commonalities and relationships between things through fun words like inheritance and polymorphism. That just makes the abstraction that much more powerful.

So that's why Object Oriented programming rocks the house: Abstraction. But everyone (who is reading this) knows that. So why did I waste all my time writing it and your time reading it? Because I couldn't stop myself.

What I actually want to talk about is what these objects should actually abstract. As far as I can tell there are two schools of thought. I'm pretty sure the one has already mercilessly beaten the other and kicked it to the curve. But in my schooling I wasn't taught about either, so I'm gonna teach myself about them both here.

The two schools:
  1. Objects should represent "the thing" and everything about it
  2. Objects should do exactly one "thing"
Or if you'd prefer,
  1. Objects represent real world objects
  2. Objects manage "concerns" and concerns are separated between objects
In the first you have one big object that knows everything about dogs and manages everything about dogs. Wanna draw a dog on the computer screen? Dog.Draw(); Want to make puppies? Dog.MateWith( Dog );

In the second you have lots of much smaller objects which together, collectively, know all about dogs. DogDisplayer.Draw( Dog ); DogMating.Mate( Dog, Dog ); Note however that this doesn't preclude you from hiding all the various classes behind the Dog class so that a user of the Dog object could still say "Dog.MateWith( Dog )".

As far as I can tell, current industry thinking is that Separation of Concern Objects are the way to go. However, when object oriented programming is taught it inevitably starts with the Real World Objects because that approach is just easier to understand.

MVC is an example of three Separation of Concern Objects. Just about every Design Pattern depends on Separation of Concern Objects (Observer, Strategy, State, Factory). And the point of just about every Design Principle I've learned is that you should write Separation of Concern Objects, the principles are just defining what Separation of Concern actually means (Single-Responsibility, Open/Closed, Liskov Substitution, Dependency-Inversion, Interface Segregation)!

There are a couple things you have to get over when you start creating these kinds of objects though. First, having lots of objects is not a bad thing. Second, having simple objects that only do one thing is a Good Thing. This often feels like overkill before you do it. After you do it you realize it has the potential to make your life seriously easier.

Okay, but why create many objects? Why not just put all the code in the same object? How is this going to make my life so seriously easier? The biggest reason is that if you put all that code in the same object it will get tangled. That is, two algorithms that really have nothing to do with each other (except that they apply to the same object) will start to affect each other. They'll use the same variables, but in different ways, they'll make assumptions that the others will break. This will become a problem when you need to change one of them and you suddenly and accidentally break the other.

The second reason is that you may want to allow for reuse. If everything is all packaged into one object, you can't reuse only a portion of it without the other parts. The final reason is that you may want to swap out the details of how something behaves for different details.

What would this mean for our Dog? Well, we can still have a Dog. But when we tell him to bark, he'll delegate the actual details of how to bark to a DogBark object. And when you tell him to soil the carpet, same thing.

Now if you decide that he should always bark when he soils the carpet, you can do that. And when you later realize that its bad enough that he's soiling the carpet, but now he's waking you up in the middle of the night barking, you can change it again so he doesn't bark when he soils the carpet. And you wont have to worry that soiling the carpet and barking got all tangled.

Moral of the story: SoC Objects add more abstraction to our abstraction. So when I told you that Unit Testing would improve your code design, this is why.

Wednesday, January 30, 2008

Unit Testing: MVC

So I've talked about what MVC is and looked at MVC in Rich Client Applications.

In those posts I mentioned that MVC was pretty helpful when it comes to unit testing. This is because, as I pointed out in Unit Testing and TDD, you can't test GUIs. Of course, you can if you really set your mind to it... But at this point I'm not convinced its worth the effort.

So how does MVC help us Unit Test? Well, once you have a controller that manipulates a view, you can mock out the view and unit test the controller. So MVC gave us something in our GUI layer to test!

Here's an example. Suppose you're creating an interface in which there are three combo boxes, each one is dependent on the one before it. So, when you select a value in the first, the second one gets populated with certain data. When you select a value in the second, the third one gets populated with certain data. Change the first one, the second one loses its value, gets filled with different data, and the third one loses its value and its data is cleared. Pretty simple little UI and not all that uncommon.

So, the view is simple, it's three combo boxes. Lets ignore data binding to keep this example even simpler. So what does our view's interface look like?
  • ClearComboBox2Value
  • ClearComboBox3Value
  • SetComboBox2DataSource( data )
  • SetComboBox3DataSource( data )
Now our controller can cause the view to change state by calling the methods on the view. How does the controller know when values have been changed on the view? This could be done in two ways.
  1. Add events to the view that fire when the values of ComboBox1 and ComboBox2 change
  2. Simply put methods on the controller to indicate the values have changed and have the view call the controller
Personally I prefer the second approach. This approach makes it easier to test and easier to read the view's code. Also, it doesn't violate the dependency chain of MVC because the controller still doesn't depend directly on the view. The view depends on the controller, but that's OK. If you need to provide different controllers to the same view you can do this with Dependency Injection. So, if you're willing, lets go with the second approach.

Now we have a view and a controller. Can we unit test the view? You can, but I'm not. Can we unit test the controller? YES!

Why does this matter? Well, the controller now contains the actual behavioral logic of the form. By testing the controller we guarantee that that logic is correct. Now we just have to test that the view updates its state appropriately. You could do this manually by clicking around, or you could use a visual scripting framework to click around for you, or you could write code to click for you... I'm still just doing it manually.

Again, no silver bullet, but we're 80-90% there (depending on how complicated the view is).

The post on MVC in Windows Applications ended without an answer. However I think this post clarifies that the benefits of unit testing a controller likely out weigh the complexity that comes from MVC.

Have you tried it? What do you think? Why not leave a comment? Josh always does! Is he really that much better than you?

Thursday, January 24, 2008

MVC in Windows Applications

In the last post I looked at what, exactly, MVC really is. Now I want to look at how it applies to Windows applications.

Windows Forms with data binding is basically Active MVC! The data binding keeps the view and the model up to date automatically. When the user performs an action (like clicking a button) an event is fired. Some code executes in response to the event, updating the model and causing the view to be updated. Just like in Active MVC. The only difference is we did it all in two classes, the form class (view & controller here) and the data class. We could separate the controller into its own class if we wanted to, and then we'd have the M, the V, and the C.


Are we comfortable with this? The only problem is that in Active MVC the Model takes on more responsibility because its responsible for keeping the view up to date. But if we're data binding to the model, it has to be 1-1 with the controls we're displaying. There is some potential for this to get complicated if we need our Model to do more advantaged state management. This could cut two ways and could be a great thing, or could become really hairy very quickly.

We could convert this to look more similar to Passive MVC by creating two models. One model will be independent of the view and managed completely by the controller. The other model will be the class we use to data bind into the View. This second model will be updated by the controller to cause values of the view to change and be read/monitored by the controller to respond to user events. With this setup we've moved more of the responsibility to the controller but we've also increased the amount of data passing that has to go on.

And there in lies the rub. On the web, the data passing is required, there is no way around it. But in a windows application, we don't have to pass data around like this. We can write code that gets the data directly from the controls and writes them to the database if we want to. There is no need to have a model class for housing data.

So what are we gaining by using MVC in a Windows Application? We've separated the data from the GUI and we've also separated the "controller" logic from the GUI. This will be nice if we ever want to make changes to the GUI like swapping one control for another. Its also nice because we can now write unit tests for the controller and mock out the GUI (and the model if needed).

So the big question is, are the benefits of an MVC design worth the overhead that comes with an MVC design?

To start with, its certainly not good to have a single form class that contains EVERYTHING. In Windows Forms this is how nearly everyone writes, at least when they're starting out. It seems like the simplest option: 1 form, 1 file, 1 class. Everything is in one place!

But as the form gets bigger (more controls, more rules, more behavior) the number of event methods just keeps rising and before too long you're looking at a 2,000 line class (not including designer code...). You can't remember where anything is and you can't find anything either. It feels like being lost in a jungle.

So we need to come up with a way of breaking this into pieces, no question. We just have to decide what pieces we want. MVC provides us with three pieces. They are nice logical pieces in theory. In practice, you really have to commit to "shoveling data around."

If you were hoping I'd end this by telling you what the best practice is, I'm sorry to disappoint, because I don't know. I'm still experimenting and researching. I'd love to hear your take, or your best practice, or even approaches you've tried and despised.

Update 1/25/08: Added chicken scratch images
Update 9/22/08: Follow up post about MVP and MVC which may be more applicable to Windows Applications and talks about View State.

Wednesday, January 23, 2008

MVC is What Exactly?

MVC (Model, View, Controller) is a design pattern or application architecture, depending on how you want to look at it, used to separate the storage of data from the presentation of data from the processing that takes place when the user interacts with the software.

It's also a huge buzzword in software development that everyone has heard about and thinks they understand but that very few people have ever actually researched or read about.

The concept of MVC was first introduced in the Smalltalk language. The Model stores data, the View presents a user interface, and the Controller handles user interaction.

It was recognized that MVC typically took one of two general forms, Passive or Active. Each form differs based on how the controller and the model behave.

Active Form:
  1. Controller handles user iteration events and updates model
  2. State changes in the model cause the view to update (observer pattern keeps model independent of view)

Note: This means the model can be changed by things other than the controller and the view will still updatePassive Form:
  1. Controller handles user interaction events and updates the model and causes the view to update
  2. Model is completely independent of view and controller
Clearly the Model must carry a lot of responsibility in the Active Form by maintaining state or whatever else is needed to keep the UI up to date. In the Passive Form the Model isn't required to do anything more than house the data. The Controller can manage the state changes.

MVC also appears in a slightly different form called the Document-View pattern used by the MFC (Microsoft Foundation Classes) framework which combines the controller and the model into one object, the Document.

MVC as seen in Ruby on Rails is basically the passive model. The controller is invoked by a user interaction. The Controller builds the model (or tells it to build itself) and/or modifies it as needed, the controller then picks what view to render and passes it any data it may need.

ASP.NET's new MVC framework works almost exactly the same way as Ruby on Rails in terms of MVC (surprise surprise!).

Passive MVC makes tons of sense on the web because the Request/Response nature of HTTP requires a very structured data passing model. Ultimately, that's all MVC is, a standard for how to pass data around:

Data is housed in the Model, accessed and modified by the controller, passed to the view to be displayed, passed back to the controller from the view w/ changes made by the user, etc...

So, MVC is a great thing on the web. It simplifies the code, makes it obvious where to go for what, standardizes the flow of data and rendering of web pages, and exactly matches the behavior of HTTP.

That being said, there are still some variations:
Does the Model match the database schema and just house data (as in .NET Typed Datasets or the new LINQ to SQL objects)? Or does the Model present data in an intelligent (problem domain specific) way and contain high level logic for modifying the Model? I'm not sure it actually matters, honestly. Its just a question of where you want to put your logic, all in the controller or spread between the controller and the model?

So, now we've surveyed MVC, talked about some frameworks that use it, and decided that it works really well for the web. In the next post I'll look at if MVC makes sense in a Windows Application.

Update 01/25/08: Added chicken scratch images

Monday, January 21, 2008

Web UIs vs Rich Client UIs

Nearly every application has a User Interface of some sort. It could be a configuration file, a command line, a Windows Form, or a web site. A software application's User Interface is the part of the software that effects the user the most because its the only part that the user has direct interaction with. Unfortunately the UI is also the hardest part of the software to quantify and measure, so its hard to determine if one UI is better than another. And further complicating it, a user might like a UI that they don't work as efficiently with and hate a UI that actually helps them get their work done faster. Its very subjective.

Before I go any further I ought to point out that having a good UI doesn't mean you have good software. The primary function of software is to fullfill a user's goals.

In any event User Interfaces are clearly important. So where do you find the best user interfaces? I think most people these days would say that Rich Client UIs are the best. They're more consistent, easier to develop, have shortcut keys and menu bars and toolbars, and have fast response times. Meanwhile, web apps are all different and inconsistent, are very difficult to develop, arn't as easy to interact with, and have high latency.

At least, that's what everyone seems to be thinking. Even in articles where very smart people like Joel Spolsky and Jeff Atwood are discussing how web apps are going to replace desktop apps you can still see those underlying assumptions.

Of course, AJAX is changing things. Now we have Gmail and Google Calendar and 30 boxes and Jott and Remember the Milk and Fog Bugz and Scrybe and Google Maps and Yahoo Maps...

Maybe its just me, but I like the UIs of these web apps better than what Outlook has to offer, or iCal, or Thunderbird (and Sunbird) or TFS or Microsoft's Streets and Trips. Why? It comes down to three reasons:
  1. They are more dynamic
  2. They are easier to read and understand
  3. They are prettier

By more dynamic I mean, when you hover over something, information is displayed in a nearby panel. Or when you click a row, it expands to show you more detailed information and give you links to perform actions. Also, the display of data is usually customized so that, for example, if you're seeing a list of todos and one is longer than another they both take up whatever space they need making them easier to read. In a rich client they're typically forced into the same amount of space in some kind of Grid control.

They're easier to read and understand because everything isn't displayed in static grids and panels. Instead, it's displayed more how you'd display the same information in a report. That is, it's laid out like a Flow Document. This makes it easy for your eye to find the information you're looking for and remember where to find that information in the future. Also, things tend to be broken into display and editing in two different interfaces. This way you're not staring at a grid of labels and text boxes, some with data in them and some without.

And finally, they're prettier. They have color and logos and icons. Most rich client apps are either a sea of grey, or washed out white, with black text over top.

So from a strictly functional standpoint, these Web UIs are better than any Rich Client UIs I've used to accomplish the same tasks. Now when you add in cross browser compatibility problems and the steep development cost and the potential for high latency things become less attractive. And this inevitable leads me to ask, "Why don't my Rich Client Applications behave as well as these Web Applications?"

The answer is its actually harder to do this kind of stuff with the existing frameworks in Rich Clients. For example, there is nothing in Windows Forms which will let you create an html style layout. You can simulate it by creating a custom control for every item and state you may need to display and throw those into a Flow Layout Panel, but the overhead involved in developing this and the performance costs when it's completed makes it too prohibitive. Ultimately you'd have to just perform your own custom GDI drawing or use an HTML rendering engine and write in HTML. Neither of these is really a very good solution.

WPF may offer a solution to this. I haven't actually done any development in it yet, though I've done plenty of reading. For now, I'm hopeful and looking forward to finding some free time to experiment with it.

Ideally I'd love to see Rich Client applications which took a more flow document layout style approach like you see on the web as well as more dynamic interfaces capable of showing the most pertinent information in the "report" view and allowing the details to be displayed through a web style progressive disclosure model.

And I'd love to see tab controls replaced with web style Navigation bars that toggle the "report page" or navigate to "anchors" in the page. These are simple but powerful UI patterns that you rarely see in a Rich Client environment.

How do you edit data? Either allow users to click and open a pop up to perform edit tasks (like Properties Windows) or dynamically display an edit control when the user clicks on the read only data. These two patterns both allow you to perform very simple spot editing or display more complicated edit UI when needed.

The fun part of all this is that none of it is new. You use it every day when you browse the web. Its time designers started incorporating the good ideas from the web in Rich Clients. And its time Rich Clients were developed with a Framework that makes dynamic UIs possible!

Wednesday, January 16, 2008

Unit Testing: Gateways

In an earlier post I gave an overview of Unit Testing and TDD. Now I'm going to start drilling down into some actual examples of how to structure your code to get the most out of Unit Testing.

In the last post I made the case that Unit Testing improved your object oriented design. I stand by that. But there is a stumbling block. You can still write badly designed code and add badly designed unit tests.

So how do you know what's bad? Just answer these two questions:
  1. Are your tests testing exactly one thing?
  2. "Does the object you're testing serve exactly one purpose?

If the answer to both questions is yes, you're doing great. If not, you may need to refactor.

Of course, those questions are easy to ask, but much harder to answer.

My first example will have to do with code that retrieves data from a database or some other data store. When first starting out people tend to write a classes that include data retrieval along side various "business logic" routines. For example, you may create a class that takes a data table as input, validates it for certain restrictions, and inserts it into the database.

This class does two things, it validates and it inserts. If you unit tested it your tests would be testing two things, that the validation was performed correctly and that the insert into the database was performed correctly. So, how do we refactor this?

Use the "Gateway" pattern. A Gateway is a class which serves as the path to and from your data store. The, err, gateway to your data. I always create one Gateway per "functional unit." So in this case because I'll have a Validator class and a ValidatorGateway. So far our example only requires the ValidatorGateway to have an insert method.

Once we perform this refactoring we'll unit test our Validator and we'll use nmock to mock out our dependency on the database by providing a mock Gateway (through dependency injection). Now when we Unit Test our Validator class we wont be testing that it inserted into the database correctly, only that it intended to insert into the database correctly.

However, isn't that still two different things? Validation and the intention to insert? It is. So we should probably take the Gateway out of the Validator all together. Instead, our Validator will just validate the data and tell us if it passed or failed. Then some other code will utilize the Validator and the Gateway.

Clearly those two simple questions can be very powerful in guiding your design if you take the time to ask them. Furthermore, the Gateway pattern is a very simple and very flexible concept that can easily be applied to nearly any situation. As a freebie, the gateway pattern also gives you the ability to swap out what kind of data store you're using very easily. Need to switch from talking directly to the database to talking to a web service? Just update the gateway and you're done.

Thursday, January 10, 2008

VS2005: Referencing an exe

If you create a VS2005 solution which contains an exe project and any other project type which has a project reference to the exe project, chaos will ensue.

You may see errors like the following:
Could not find file 'someResource.ico' referenced by assembly 'C:\path\to\your\assembly.exe.manifest'.

You might even see the error:
Could not find file 'Microsoft.Windows.CommonLanguageRuntime"

It turns out this is a bug in Visual Studio 2005:
KB907757
msdn forum thread
other msdn forum thread

We ran into this problem when creating a project to contain Unit Tests that references the actual application project. The work around we're using is to turn off the "Enable ClickOnce Security Settings" check box in the Project -> Properties -> Security menu. Unfortunately, when you publish an application through ClickOnce this option is automatically checked. That means you'll have to turn it back off after you finish your publish so your Unit Test solution doesn't fail to build.

The other work around is to replace the project references with references to compiled dlls. However, that clearly isn't very helpful if you're trying to do TDD.

From what I can learn, it seems that this bug is fixed in VS2008 but I haven't had an opportunity to test that for myself yet.

Wednesday, January 9, 2008

Leadership

In High School and College teachers and professors (of the liberal arts...) pay a lot of lip service to "Leadership." Of course they never really tell you what it is, they just tell you to do it.

Usually this was most apparent in group projects. The group's first order of business was always to select a leader. This was done by someone asking, "Who wants to be group leader?" Everyone would give each other blank stares until someone finally responded with, "I'll do it, I guess."

Sometimes the group leader would simply end up being the group secretary, responsible for writing down the answers and turning in the final paper. Other times the poor bastard would actually try to "lead." Depending on who the leader was, this would take a few different forms. Some leaders would try to make all the decisions and tell people what work they were going to do, even before anyone had started brainstorming about the project. Other leaders would wait for someone else to come up with a good idea and would then say, "Okay, here's what we're going to do!" and repeat the idea.

So basically school was worthless when it came to understanding or teaching leadership, and group projects were only good as an exercise in frustration (which is clearly a good exercise for the real world).

Ultimately, I think leadership is simply organizing the behavior of a group of people. So, basically, it's telling people what to do. Good leaders tell people to do the right things and don't piss people off when they tell them. Good leaders also resolve disputes by helping others make good decisions. Good leaders are also able to take the best advantage of the skills of the members in the team.

Over the years in observing how people try to lead, and how other people seem to lead without trying, I've decided leadership has more to do with personality than anything else. These are the three ways I've identified that seem pretty common:
  1. Lead by decree
  2. Lead by consensus
  3. Lead by respect

The people who lead by decree come into a meeting with their minds made up and tell everyone else what the team is going to do. Sometimes these people try to pretend they want other people's input, but instead of actually listening to what people are saying they just wait for them to finish talking so they can go back to convincing everyone to do what they want.

The lead by concensus type is more democratic. They bring their ideas to the table along with everyone else's and allow everyone to argue it out. Which ever idea the team decides on wins. The lead by consensus type of person typically doesn't throw their weight around to get what they want, even if they have any weight to throw. That doesn't mean they give up on their idea completely, but it means they usually defer to the group before trying to issue a decree. This can be a problem when a decision really needs to be made or when a firmer hand is warranted, because you don't want to waste forever arguing around in circles. Typically I think I fall into this category.

The lead by respect person is a rare and impressive find. These are people who everyone simple likes and respects so much that other people actually want them to lead. I've only known a few of these kinds of people and I've never been fully able to understand how they did it. Sometimes these people never even come across as telling people what to do.

These are the three "categories" I thought up, and as you can tell they focus more on how a single person actually behaves. I did some brief google research and found Lewin's Leadership Styles. Interestingly, these correspond somewhat well with my own take, but they capture more of the gray area:
  1. Authoritarian Leadership - leading by decree
  2. Participative Leadership - leading by consensus but retaining the final say
  3. Delegative Leadership - leading completely by consensus and/or allowing everyone to make their own decisions

Some interesting thoughts. No one leadership style can be considered the best. It depends on the circumstances. For example, if the leader is the most skilled of the group, Authoritarian leadership makes the most sense. However, if the peers are primarily equal, Participative makes the most sense.

The leadership style also dramatically affects the group members. If the group members are very independent people, they may prefer a Delegative leadership style. But, while they may prefer it, it may not be the most effective.

Finally I've been in very few situations where there really was one leader. Leadership tends to float around, landing on different people at different types. The title doesn't float around, but the actual act of leading does. I think its this fact that makes effective leadership important. You have to recognize that leading doesn't mean controlling every detail. And you have to work well with other people when the leadership bubble has landed on them. Otherwise you're just going to piss everyone off.

Monday, January 7, 2008

Versions Followup

In the previous post, Two Versions of the Same Shared Assembly I outlined a problem as well as many solutions, suggesting the solution I thought was the best choice. Since then I have run into one very serious problem, and one slight concern.

Lets start with the serious problem. I implemented the solution of putting the version number in the assembly name. This worked great at run time, but the Visual Studio designer started bombing out. The weird part is it worked great in one project, but not at all in another. What's the difference between the two projects? I have no idea. They are both referencing the same project which has the SharedAsm built as a dll w/ a version number in the name as follows:

App1 -> Comp1 -> Comp1Utils -> SharedAsm.1.0.0.0
App1 -> SharedAsm.1.0.0.1
---
App2 -> Comp1 -> Comp1Utils -> SharedAsm.1.0.0.0
App2 -> SharedAsm.1.0.0.1


App1 doesn't work, App2 does work. I thought it might have something to do with the alphabetical ordering of the project names affecting what assembly VS used, so we renamed App1 to be the same as App2 relative to SharedAsm. That didn't change anything, it still worked.

I can't explain what is going on here yet, but it seems like the VS Designer is arbitrarily picking one of the two versions of SharedAsm in the AppDomain when it creates an instance of a type from that assembly. In the one project, it picks the wrong version, in the other project it picks the right version. Ultimately this results in the designer bombing out because of some code which tries to cast an object to a known type, but in this case the versions on the type don't match... boom.

Here's an example:
Form1.cs:
private SharedAsmType var = new SharedAsmType();
...
var.TypeOfInterest = typeof( Form1 );


Inside SharedAsmType the TypeOfInterest is constructed using the Activator class. This is then casted to a known type in the SharedAsm assembly. It is this cast that fails.

The reason for this is that SharedAsmType is coming from SharedAsm.1.0.0.0 but the TypeOfInterest inherits from a type in SharedAsm.1.0.0.1. Thus the activator returns a SharedAsm type different from the type that we're executing in at that point, and the cast fails:
SharedAsmType2 t2 = (SharedAsmType2)Activator.CreateInstance(t);


What should happen is SharedAsmType should come from SharedAsm.1.0.0.1. It doesn't make any sense to me at all why it's coming from 1.0.0.0... It really looks like the VS designer is just picking a SharedAsm assembly, ignoring which one is actually referenced by App1.

If any one can shed any light on this one, I'd absolutely love to hear about it.

The other problem is one I haven't directly tested but which I imagine would be an issue. If your existing code base had any code in it which used reflection to reference the SharedAsm assembly by name, you wouldn't know which version you were going to end up with. I don't know if .NET would just pick a version, or if it would bomb out... This one is just a problem of having two versions of a shared assembly loaded in the AppDomain at the same time and using reflection. The only one of our solutions which wouldn't suffer from this would be the ILMerge /iternalize solution. And again, the memory usage side effects of that just aren't acceptable.

So, unfortunately, this seems to bring me back to square one again... I'll post any information that may come up as I continue to fight with this problem and I'd really love to get some insight from the vast world of .NET developers out there. Surely there are more .NET programming shops running into the need to create "packages" that contain shared assemblies!

Thursday, January 3, 2008

Two Versions of the Same Shared Assembly

This post is a follow up to an earlier cry for help: Shared Assemblies, Components, and Applications

I actually have a few workable solutions to the problem I presented there now. But you don't have to read that old post, I'll present the problem again here in a lot more detail:

Suppose you have some .NET assemblies which depend on each other as follows:
  • App1 is an executable application
  • Comp1 is a dll library, used by App1
  • Comp2 is a different dll library, used by App1
  • SharedAsm is a dll library used by App1, Comp1, and Comp2
Notice that the diagram indicates that there are three different versions of SharedAsm being referenced here. The problem I have been trying to solve is, how would you set up such a system with .NET?

Lets step back first and look at why you might run into this. It's quite simple. Component1 and Component2 are pretty beefy modules. So beefy in fact that they each have their own development teams. The components aren't just used by App1 either. There are dozens of applications that use these components. This is a perfectly common occurrence. The only reason it is a problem is because of the dependency on SharedAsm.

Here's why: Comp1 is working with version 1 of SharedAsm. They want to release their component to the App1 development team. But App1 is using version 3 of SharedAsm. Version 3 is not compatible with version 1. If we're working in Visual Studio here this will be a serious problem.

Suppose App1 is setup with a solution that has all project references. If this is the case, Comp1 wont compile because it was expecting version1 of SharedAsm but its going to find the current source control version instead.

Okay, suppose App1 is setup with a solution that references dlls instead. This still wont work. When the dlls are copied into the output directory one version will overwrite the other version... Boom.

It seems that the only option is for the Comp1 team to update their code to use the same version of SharedAsm as App1 is using. But what if App2 is using a different version? Well, lets just make it company policy that all active projects must use the latest versions of all assemblies. But what about App3 which is no longer in active development and doesn't have a development team anymore?

Let's sum up our troubles:
  • Comp1 can only be used in any application as a project reference if that application will reference ALL assemblies as projects and be willing to immediately update to new versions when they are checked in (sloooooooow build times w/ all those projects, very fragile environment as the slightest bad checkin breaks everyone, hard to deal with legacy projects)
  • Comp1 can't be "released" as dlls because of the potential for shared assembly version conflicts
  • We can't work on non active projects without updating them to the newest versions of all components or performing fragile and complicated branch magic in our source control system.
Are there any completely automatic solutions to this problem supported by Visual Studio? Nope.

Are there any solutions for this at all? Lucky, yes.
  1. Add the version number to the end of the dll names by changing the Assembly Name property of the visual studio project before building it.
  2. Use ILMerge to combine the SharedAsm.dll and Comp1.dll into a single Comp1Merged.dll using the /internalize option.
  3. Install SharedAsm to the GAC and make sure all references to it in the Visual Studio projects are set to SpecificVersion = true and CopyLocal = false.
I think the first solution, appending the version number to the name, is the best all around solution.
  • + It can be done from within Visual Studio requiring no outside tools or custom build scripts
  • + It generates pdbs with no effort allowing people using the assembly to step through the code at run time
  • + Its memory efficient, different versions of SharedAsm will only be loaded if different versions are actually being used
  • + The SharedAsm team only has to add the version number. Nothing unusual has to be done by any other teams.
  • - It requires someone to manually update both the version number and the assembly name
  • - It requires that SharedAsm go through "structured releases" in which the version number is incremented and the dlls are made available to anyone who wants or needs to upgrade
  • - To upgrade, teams using SharedAsm have to both remove the old dlls from their project and update the references (this can be automated with a script if necessary) (and fix errors)
The second solution, ILMerge, works great, but it has a few more serious downsides. For more details on this solution refer to this post on Jon's ReadCommit blog.
  • - Requires an outside build script to run ILMerge (or a post build event in VS? or a project file modification?)
  • + PDB files are merged as well
  • -- Potentially very memory inefficient as n versions of SharedAsm will be loaded regardless of if they are actually different versions. This is a deal breaker for the way I need to use this pattern as I have will have way more than 2 components using the same shared assembly.
  • +/- The process is managed by the Comp1/2 development teams, the SharedAsm team doesn't have to do anything special.
  • - It requires that SharedAsm go through "structured releases" in which the new dlls are made available
  • + To upgrade teams using SharedAsm just copy the new version over the old version (and fix errors)
The third solution, GAC, also works great but requires the most work and maintenance.
  • - Dlls must be placed in the GAC on every developer's computer
  • - Comp1 team and Comp2 team must release script to add needed dlls to GAC as well as new version of their comp1/2.dll
  • - No PDBs for dlls in the GAC, thus can't step through code in SharedAsm when used by components
  • - The process requires effort from everyone
  • + As memory efficient as the version number solution
  • - Dlls must be placed in the GAC, regardless of if they really make sense there
I have tested all of these methods and they do all work. I haven't actually started using them in our development environment so I'm only speculating about the pros and cons that will arise from that.

For the record here are some non-solutions:
  • .netmodules generated with csc.exe
  • use of the extern keyword and aliasing references (requires too much foresight and work to be practical)
  • renaming dlls after they've been built (you must change the Assembly name before you build or .NET will not be able to find the dll to load it)
  • ILMerge w/o the internalize option. This will work if App1 doesn't directly reference SharedAsm. But as soon as you add the SharedAsm reference you will receive a compiler error: The type "sharedasm.type" exists in both "comp1.dll" and "comp2.dll." This is because all three types are visible and .NET doesn't know which one you wanted to use. The internalize switch solves this problem by making the types internal in comp1 and comp2.
Big thanks to Jon and his ReadCommit blog which taught me about the /internalize switch of ILMerge.

FOLLOWUP: Versions Followup