Friday, July 30, 2010

Should We Re-Write It?

Yes, of course we should.  Now, what were we talking about again?  Ah, that's right, a legacy application somewhere in the bowels of our enterprise.  It's old, it's confusing, it's built from clay and straw and other such dated materials.  It's just an embarrassment to have around and is difficult to support.  So yes, of course we should re-write it.

Whoa, hold on there cowboy.  I said we should re-write it, not you or I should re-write it.  There's a lot involved in "we."  Just directly porting that old ASP code to shiny new C# code isn't going to solve anything.  The problem isn't that it's written in ASP.  The problem is that it's written poorly in ASP.  That difference is what's going to get you in the re-write.  Just changing the language isn't going to solve anything, there's no value in it.  The application needs to be re-written, not transliterated.

Consider an analogy.  Let's say some random guitarist writes a song.  And let's also say that song is terrible.  The guitarist might not be so bad, and maybe there was some real inspiration behind the song and he really wanted to express it.  But he failed.  The song is just awful.  The music and the lyrics don't come together to tell a story so much as they get in each other's way and prevent each other from telling their parts of the story.  It's hard to follow, it doesn't get the message across.  It's just a bad song.

Would that song sound any better on a piano?  Probably not.  Sure, a skilled pianist could add a little talent to the playing of the song.  Each note would individually sound better, more alive and easier on the ears.  But is that really your measure of what makes music "good"?  That it's slightly less offensive to your ears?  The song still doesn't convey its story.  It's still difficult to follow and understand.  It still, well, sucks.  All you've done is expend a sizable amount of effort for the purpose of, what, exactly?  You haven't fixed the code, you've transliterated it.  You've created the C# version of engrish.  Ya, that's going to be much easier to support.

The problem is in the design of the application.  We don't know what it does, the business user doesn't know how it does it.  But maybe if we work as a team, we can mutually educate one another a little bit and pool our expertise to actually come up with a solution to a business problem.

Having the developers take it upon themselves to just re-write applications is a very, very bad idea.  Why?  Because you're asking the person who knows the least about the requirements (doesn't know the story the song is trying to tell) to develop an application that meets those requirements, and the business user doesn't even know this is taking place.  Nobody knows that the entire application needs to be regression-tested.  Does the business user have time for something like that?  They didn't ask for it.  Does anybody else know how to test it or validate that anything in it works?

Yes, I agree that poorly-written legacy software which is difficult to support should be re-written.  Absolutely.  But not secretly.  We need a product owner.  We need collaboration.  We need to come together to define the correct solution to the business need at hand.  Otherwise we're just turning one difficult-to-support application into another difficult-to-support application.

To put it another way... If somebody successfully polished a turd, would you now be willing to touch it?

Thursday, July 29, 2010

Code Dojo

Our first Code Dojo meeting is scheduled!  The idea is simple enough, and has been done before, of course.  Our version is just in its infancy and we're seeing if we can gain some traction here.  But we're hoping to turn this into a regular meeting of developers where we come together and team-code a project into reality.  We're doing this so that we can learn new things together by just sitting down and doing them.

The first meeting, which is Saturday August 7th at my house, will be mostly for the purpose of brainstorming.  We have some basic ideas of how we'd like to start, and we've at least settled on an initial goal of developing something in Ruby for the sake of learning Ruby.  That "something" is still open to much debate and will likely evolve over time.  We don't want it to be too much at first, because we want to learn the basics.  But at the same time we don't want it to just be (as Sean put it) "Rails 101" where we just follow some tutorial and be done with it, not learning much of anything.  So we need to find a good balance.

If you're interested in the dojo, let us know!

Friday, July 16, 2010

Left versus Right

I have recently read and heard discussion of the two sides of the brain. The left side is more factual, concrete, and good are more of the engineering tasks. The right side is more bigger picture, capable of discovering odd patterns, and is better at creative tasks. To produce new valuable and applicable ideas you generally have to switch between the two back and forth. Digging up connections between bits of knowledge from the left and finding new connections to consider with the right. Verifying with the left and digging up more and the cycle continues.

Software development certainly combines both sides of the brain, but sometimes I read or see how people are trying to make software development into software engineering.

Comparing software development to an engineering discipline is always interesting in my mind. I know there was some movements (academic and professional) on trying to develop a software engineering discipline, but I don't think that can happen. Engineering disciplines usually have many years of grounded research and field application to prove how to do things, but we are in a world that is completely built off of arbitrary ideas that are built on other arbitrary ideas that may not always be true. There is a degree of creativity and judgement needed I think in software development that isn't as needed in the engineering disciplines I have encountered. I think this is partly because of how soft what we are shaping is, the speed of technology, the youth of our field, and the wildly differing ideas we face. I will admit I do not have experience in performing or studying any engineering discipline past a basic level.

An example of what I'm getting at that is applicable to what's happening in our field currently is that all our knowledge of object-oriented software design and practice is not directly transferable to working in a functional oriented way. Also our knowledge of relational databases won't transfer over very well to document databases. I suppose being able to apply the knowledge of a particular technology is a more engineering task but knowing when and where to use a particular technology and how to combine it with others is probably a more creative task.

This is just partly my own theory I was just thinking about. You guys have any feedback or opinion on the subject?

Why (not How) Agile Works

Sean shared this with us over email this morning and I'd like to post it here for posterity.  I'm part-way through the presentation right now and it's pretty good.  I highly recommend that we share this with as many managers as possible.

http://universite-du-si.com/fr/conferences/6/sessions/909

Friday, July 9, 2010

Try And Catch Me

There was a fun question posted to StackOverflow today basically asking if the "finally" block in a try/catch will always execute.  The responses varied from a definite "yes" to a definite "no" with lots of discussions and mutual corrections made by the crowd.  So I thought it would be fun to enumerate here the things which can cause a "finally" block to not be executed in a .NET application.  This may not be an exhaustive list, so please add/correct as you see fit...

  1. StackOverFlowException - The process has run out of necessary resources, it simply can't execute any more code.  Even if the next line of code is to pass control to the "finally" block, it can't get there.
  2. OutOfMemoryException - See above.
  3. ExecutingEngineException - It's rare, I've never seen this one.  Basically, the .NET runtime b0rked, the application can't continue.
  4. Environment.FailFast() - Kills the application with extreme prejudice, not allowing it to finish what it was doing.
  5. Process/Thread is killed by an external process/thread - The application isn't asked nicely to terminate, it's shot in the head by the OS.  Note that a ThreadAbortException will attempt to execute a "finally" block before aborting.  But there are more sinister ways to kill an enemy process.
  6. Infinite loop within the try block - The application will run indefinitely until #5 above happens.
  7. Power failure.
In this I've learned a few things, which are good things to know.  First, I didn't know about Environment.FailFast().  I don't know if I'll ever use it, but it's good to know that it's there.  Also, more importantly, I'd never heard of Constrained Execution Regions before.  In writing enterprise software with high reliability requirements, this is definitely something I should look into.

It's just good to keep in mind that a "finally" block is not the end of the discussion when talking about reliable code.

Wednesday, July 7, 2010

Repositories

I wonder if I may be taking "repositories" in the wrong direction in my code, so (in a similar light to Sean's last post) I'm looking for some feedback from the group.

In the anemic domain model that I'm using, crudely sketched in an earlier post, I have a handful of "domain cores" (the big balloon thing in the sketch) and a bunch of pluggable "repositories" that get injected into them.  But I'm using the term "repository" more broadly than, say, a table in a database.  I'm using it as more of a business area that involves some kind of IO.  So I have repositories such as:

  1. FileSystemRepository
  2. EMailRepository
  3. CoreDataRepository (the company's core critical data is part of a 3rd party application suite)
  4. CommonDataRepository (a database of common data that internal applications share)
  5. HRDataRepository (the database used by the company's 3rd party HR software)
  6. ActiveDirectoryRepository
  7. [InsertVendorHere]Repository
  8. etc.
So, since the "repository" can interact with different kinds of data in different ways, it doesn't just implement CRUD procedures.  Its procedures have a little more business meaning.  For example, the EMailRepository might have a method called SendNotificationsFor[InsertBusinessProcessHere](args) that will, based on the arguments it receives, send out some email notifications.  Or the ActiveDirectoryRepository might have GetUsersInGroup(args) that takes a group name or group ID of some kind of returns a list of user objects.

In this design, anything specific to the repository is kept in the repository.  The methods only accept/return standard types or domain objects.  So the CommonDataRepository would never return a DataSet or a list of an internal entity type, it internally converts anything from the data source into a domain type and returns that.  The idea there is to keep any knowledge of the actual I/O strictly inside the repository.

So I guess the first question is, am I off-base here?  Is this wrong?  Maybe I just need to not use the terminology "repository" in describing these things?

Further down this road, I have another question about how these are organized.  Basically: Should repositories be able to internally reference each other?

For example, let's say we're getting the users for a group from the ActiveDirectoryRepository.  It will return a List where "User" is a custom domain user object.  Let's also say that the User object has some fields on it that are populated by the HRDataRepository.  So any time you populate a User object, it's going to need to contact both of these repositories.

Currently I have it set up such that, internally, the ActiveDirectoryRepository has an injected dependency on the HRDataRepository and, any time it builds a User object (or list of User objects, etc.) it calls the HRDataRepository.  The reasoning for this is, again, to keep knowledge of this in the repositories.  Any developer who's writing code to hit that repository just expects back a list of Users, all good and proper.  We certainly shouldn't expect every business logic function in the domain to manually hit both repositories and combine the data, should we?

Am I looking at long-term support problems here?  Does anybody have any thoughts or insight on this?  The IoC of the whole thing works out fine because the repository assemblies (each one is its own project) reference the domain core assemblies into which they'll be injected, so they can see the interfaces for each other inside those assemblies and the IoC container hooks them up just fine.

Thoughts?