Saturday, May 26, 2012

Dropping The "I"

I could have sworn that I'd written something a while back about dropping the "I" in front of interfaces, but I can't seem to find it.  Maybe I had merely intended to write it.  Oh well.  In any event, what I may or may not have said before is still working very well for me.

The idea, at least when I heard it, came from good old Uncle Bob.  It's simple, really.  While I'm not entirely familiar with the idiomatic conventions in most other languages, in C# (or .NET in general, I suppose) the convention has always been to prefix interfaces with an "I".  Something like this:

public interface IModelRepository { }
public class ModelRepository : IModelRepository { }

But... why?  The IDE knows it's an interface and not a class.  So you're not doing the IDE a favor.  The developers know it's an interface because, well, it's an interface.  And the code itself shouldn't care.  It's an "encoding" in the type that harkens back to things like Hungarian Notation.  And it's unnecessary.

A while back I adopted another convention for my code.  Something more like this:

public interface ModelRepository { }
public class ModelRepositoryImplementation : ModelRepository { }

Doesn't that just feel... cleaner?  There's no unnecessary encoding, each name states exactly what it does.  The interface is a repository for some model, the class is an implementation of that repository.  Two concerns, separated.

It looks cleaner throughout the rest of the codebase as well, because the rest of the codebase doesn't care about the implementation.  It cares only about the interface.  The specific module which wires up the implementation to the interface (the service locator, if you will) is all that cares about it.  And within that code it's also much cleaner.  After all, semantically what is that code doing?  Is it supplying a repository for an I-repository?  Or is it supplying an implementation for a repository?  It just makes more sense to name the constructs by what they are and what they do.

Now, sadly, this isn't common practice.  As a consultant I often have to go with what the community collectively prescribes because the code I write will be handed off to some developer with whom I will never work.  Most likely some "resource" who was hired specifically for a support role.  (I hate calling people "resources" by the way.)

So more often than not I have to go with the I-prefix simply because it's a more commonly known pattern and is expected and understood by more people.

But, for my code (and for code where I'm the team lead on a proper ongoing team dynamic, not a drive-by consultant implementation) I love this.  Clean.

Thursday, May 24, 2012

Agile Means "No End Game"

I've seen a lot of places maintaining their own flavors of "agile" (or, more specifically, their own flavors of SCRUM).  And this is good, agile is all about self-organizing teams and finding what works for you.  You should develop your own flavor.  Well... To an extent...

The most prominent barrier I see is adoption at every level of the business.  How many proponents of agile have given their pitch, presented the benefits, even attached precious numbers and values to the whole thing, only to be met with the same question:  "That sounds great.  So when can I have my finished system?  8 months?  10?  What will it cost?"

Something was lost in the exchange.  There are a couple of problems with the response:
  1. When you can have it is up to how you steer priorities.
  2. There's no such thing as a "finished system."
The first one is the more obvious of the two.  When can you have it?  We don't know.  That's the point, really.  Even if we were to estimate and plan the whole thing up front, we couldn't give you an accurate number.  It might be wildly high, in which case you'll waste time and money on something you could have had sooner.  Or it could be wildly low, in which case you'll burn out your team and end up with an inferior product.  Right now, before any discovery has been done, is the worst possible time to make such an estimate.

This is the basic paradigm of agile.  You're not getting work done faster; You're not getting work done better; You're trading one piece of control for another.  You're gaining the ability to quickly and easily change direction and adapt to new discoveries, and you're giving up the long-term planning to get this ability.

Of course, you don't want to give up anything.  You're a CFO, you want numbers.  This is going to go on a budget sheet and be locked away in a cabinet somewhere and, well, forgotten.  You demand these numbers.  But... did you ever really get these numbers in the first place?  How much do you value wildly inaccurate guesses?   Why is it so critical to write down a number that you're willing to do it at the worst possible point in the project?  Wouldn't you rather have more control of the number going forward?

It requires a change in how you want to handle those numbers.  We can't tell you with certainty that you're going to need to give us $1.6M for an 8-month project.  What we can tell you with certainty is that, if you can allocate $200K per month as a budget, we can begin work immediately.  With each passing month (hell, with each passing week) you'll have more information presented to you about the status of the project.  We could get $200K into it and realize it's going to be a lot more, or even a lot less.  You'll have feedback much sooner and can adjust and steer accordingly.

This begins to touch upon the second item above.  The lack of an end game for the system.  Now our budget is periodic, not absolute.  You can adjust it at will, even cut it entirely, and the team will respond accordingly.  Want to cut it down to $100K per month?  No problem.  You'll get half the velocity out of the team.  It's not the end of the world (though it could mean the end of a job for team members, so standard turnaround cautions apply), it just means that you're turning down a knob somewhere to get less throughput from an ongoing process.

It makes sense from the perspective of software itself.  We all know that the real costs are not in development, they're in support.  That ongoing $200K per month isn't going to go to waste after the initial production release.  In fact, if your plan is to bring in a team temporarily, have them build a system and release it to production, and then send them on their merry way... Get ready to spend a lot of money.  Software does indeed rot, sir.

If, on the other hand, you maintain an ongoing budget for the team in general, support and upgrades will just be a standard part of that budget.  Bug fixes, new features, etc.  And, as I said before, you can tweak that budget without a problem.  Even cut it entirely (if you decide, as a business, that you want to cut support for your software entirely).

Because there is no end game.  Software doesn't stop.  It's never complete.  It's an ongoing cycle (assuming your business genuinely relies on this product, of course, and it's not just a temporary scaffold that will be thrown away after you've used it).  Unless you plan on your business coming to a stop, don't plan on the software which supports your business coming to a stop.

The amount of money you spend on your enterprise software can fluctuate.  And, again, it can even dry up entirely in a dire enough situation.  But the point is that it's a periodic cost, not an absolute one.  Your big $1.8M project that's planned from the beginning is going to cost you a lot more than $1.8M, you just don't know it yet.  Which means you haven't planned for it yet.  That additional cost won't come out until after the project is "done."  Operational costs, IT costs... it'll all be there.

"You don't know that yet" is, in fact, exactly the point we're trying to relate to you in this pitch.  We don't know things yet either.  So, rather than make up numbers, we're proposing a paradigm shift in how we manage uncertainty.  Instead of pretending that we do know, let's assume that we don't know and plan our approach accordingly.  To adjust for this uncertainty, we build agility into the process.  So that as soon as we do know something, we can immediately react.  As a whole team.  As an entire enterprise.

"Agile" isn't just something the developers do.  It's something the corporate culture adopts.  And it either adopts it wholly or not at all.

Saturday, May 19, 2012

The Case for Service Accounts

It's a common question when writing an application.  Should the application access the database (and other services) as each individual user, or as a single application-specific service account?  This is an especially important question in any multi-tier service-oriented system.  There are pros and cons to either approach, of course.  But for my entire career I've always preferred the service account approach.  This is for a number of reasons.

First of all, you may not have an internal authentication/authorization context for every user.  The application may, for example, be a public-facing web application.  (I have actually heard someone suggest that user registration for a public website be handled through Active Directory.  Too bad I didn't get to see them try to implement that, it would have been a blast.)

Second, in multi-tier environments, passing that context from machine to machine is hard.  Have you ever had to maintain Kerberos in a Windows environment?  It's not only really bloody terrible, but from a more concrete business perspective it will devour operational expenses both in terms of downtime for users and constant support from IT staff who would be better off doing other things.

But there's a more pressing concern with the difference between user contexts and service accounts.  And it's one that's probably most often used as a reason for user contexts, even though it's really a reason for service accounts... Auditing.

"We want to maintain the user context throughout the system so that we can audit the user's actions throughout the system."

Are you sure that's a good idea?  Let's think about it for a minute...

When a user (we'll call her Mary) performs an action in the application, you definitely want to audit the action she performed.  But what was that action?  Did Mary edit a record in a database?  Did Mary call a web service?  What did Mary actually do?

The last time I saw this kind of user auditing in place, every record in the database had an audit log attached to it indicating a history of what changes were made (inserts, updates, and deletes) and which user made the change.  So the business can say with confidence that at 1:37:14 PM on May 17th 2012 Mary edited this record in the database.

Mary did no such thing.  Your audit trail is wrong.


Mary didn't edit a record in the database.  Mary performed an action in the application.  The application edited the record in the database.  Or perhaps even called a web service (which is another application entirely) and that application edited the record in the database.  Mary was completely removed from this action.  What Mary did in the application may have translated directly to a database record edit.  She may have even thought that she was directly editing a record in a database, like in old Access applications.  But the application actually performed that action.  Mary merely performed a request.

What if the application does more things unknown to Mary?  Maybe Mary told the application to update the record for a patient in a medical system.  The application updates the record, performs some other business logic on the new data, updates some other records, kicks off some tasks, etc.  Mary isn't aware of any of this.  And, more importantly, Mary didn't tell the application to do any of this.  All she did was tell the application to update some patient data.  So why should all of these other things be attributed to Mary?

Worse, what if the application has a bug in it?  What if this medical application accidentally updates the wrong patient's data?  Why would you want to blame Mary for that?  The audit trail would be very wrong, arguably criminally wrong.  Mary performed a request to update the data for her patient.  The application received that request, but did something completely different.  Mary certainly didn't do this.  The application did it.  Arguably even the developer did it.

If Mary opens up SQL Server Management Studio and directly edits data, then that should definitely use her personal credentials to audit those changes.  But that's not what's happening here.

What should be audited is the actual request Mary made to the application.  And any request that application makes of other systems in response to Mary's request.  Database edits, service calls, etc.  Each should be audited in its own right.  That audit trail can link these requests together for reporting purposes, so that one can easily determine which application requests were made in response to a user's request.  But the user's request should be the only thing attributed to the user, and that attribution should be as close to the user's actual actions as possible (that is, as close to the UI as possible) to reduce the risk of bugs changing the requests before the audit occurs.

Sunday, May 13, 2012

"The Business Person Doesn't Need To Know That"

At my current project there's some pretty significant involvement from the business in the details and minutia of the application design.  For better or for worse, each and every business user wants to know exactly how things are going to work, and wants to put their two cents into the design.   It's a lot of cooks in the kitchen, and as a developer it's easy to complain about that...  But I should really make the best of it.   After all, it could be worse.

I'm reminded of a previous job at a bank that no longer exists.   (I've said it before and I'll say it again...  A bank going bankrupt is irony at its best, and it also an astounding example of a business running itself into the ground.)  At one point during my brief tenure there I was tasked with fixing a bug in an application owned by the HR department.  It was a basic one-off HR utility, grabbing data from here and there and moving some bits around so they can do something.  No big deal.  But it suddenly stopped working recently.  And it stopped working in a weird way.

Normally it would iterate through every employee in the company, connect each one to some other data in some manner relevant to HR, and update some data in a transactional database owned by the application (and, thus, by the HR department).  Then it would email some reports to key individuals based on the new state of the data.

Note that I keep pointing to the fact that this is owned by the HR department.  That's a significant part of the point I'm trying to make.

The "weird way" in which it "stopped working" was that it would run as scheduled, update some data, and send some reports.  But it didn't update everything.  It took a little cajoling with the HR point of contact (which I think was also head of HR... we'll call her the Product Owner) to get more relevant information (she's used to being protective of this data... but I'm not interested in the real-world values of the strings and integers, just the fact that there are strings and integers), but the pattern which was eventually uncovered was that it only "worked" for employees whose surnames began with A-F (semi-inclusive), and never for any employees whose surnames were F+ (semi-inclusive).

The pattern indicates pretty clearly what, or at least where, the problem lies.  Something is wrong with the data for an employee whose surname begins with F, and the application is silently failing.  And this data is relatively new, as the system only recently stopped working.  (Though, in hindsight, "recently" in bank-time could have been two years while the department awaited approval and navigated the sea of red tape to get a bug fixed.)

So I set about debugging.  The arduous process of stepping through somebody else's code and examining values.  And let me assure you that this code was a mess.  I was told that it was written by somebody who didn't really know .NET very well, and was accustomed to developing in another system.  I take statements like that with a grain of salt, understand.  And I do this because the errors weren't necessarily .NET-specific errors.  If the developer didn't use LINQ or didn't use built-in functionality to perform common tasks, that's one thing.  But we're talking about serious logical problems.  Looping through data in unimaginably inefficient ways in order to find a value that you already have in another data structure, things like that.

But I digress...

I tracked down the problem, and wrote a detailed analysis of it.  This was earlier in my career, and while I don't have the analysis anymore I am confident that it could have been worded much more professionally.  So I approach this particular anecdote with a modicum of understanding of the events as they unfolded.  Nevertheless, I sent this analysis to my supervisor and to the Product Owner.

The analysis essentially laid out the logic surrounding the error, indicating specifically where and why the error occurred, the logical nature of the error (the application was assuming that every entity in Active Directory was an employee, and that every "employee" email address was unique... the falseness of the former assumption led to the falseness of the latter assumption), etc.

I was proud of this analysis.  I'd not only found the nature of the problem, but I'd found a prime candidate of code that needed to be re-factored and cleaned, which would result in an application that's easier to maintain and dramatically more efficient for the users.  So the analysis was also a request for clarification. What should the logic be?  Clearly, the logic as it stands right now is inaccurate.  But without any further knowledge of what the application should be doing (again, the code didn't give much indication of this), I needed collaboration with the Product Owner.

"She doesn't know or care about these details; It's your job to fix it."

Those weren't my supervisor's exact words, I don't think, but that's essentially the gist of it.  And the other people in my group agreed.  More vehemently than respectfully (again, earlier in my career), I disagreed.

How can the Product Owner not know or not care about the business logic driving her application?  Sure, the implementation details are unimportant to her.  That's where the developer's "magic" comes into play. But the logic?  That is most certainly owned by the Product Owner.  I can't tell her what her application is supposed to do.  I can suggest logic to achieve the desired business outcome, but that logic needs her collaboration.  She can't just expect to toss some vague concept over a wall and expect somebody to toss back a completed application.

Can she?

"That's just how we do things here."  If you've read my previous posts, you've seen that one.  It's the same place.

Again, I completely and wholly disagree.  At its core, the application was "broken" because it logically defined the unique identifier for an employee as an email address.  Does HR use this to uniquely identify an employee?  If so, then I agree that there's a technical implementation detail which broke that logic.  Nonetheless, it's useful information for the Product Owner.  Apparently enterprise-wide that particular unique identifier isn't as reliable as originally assumed, and something in the business logic may need to be adjusted.  But then... If that's not how HR uniquely identifies an employee, then the application isn't expressing the business rules of the HR department.  The Product Owner definitely needs to know about that.  And, for lack of additional information, the Product Owner needs to work with the developer to correct the logic so that it accurately and completely reflects the business rules.

Either way, the Product Owner needs to be involved.  But... She doesn't care about such details?  At another previous job I once said, "If the people who want this software don't care about it, why should I?"  It's kind of passive-aggressive, but the point remains.  It's either important or it isn't.  It's either worth your attention or it isn't.

If your software isn't worth your attention, expect bad software.  And don't be surprised when you get it.  (Loosely translated: Don't come crying to me when you get everything you want.  I'll help you fix it, but I won't take accountability for the parts that weren't under my control.)

Ok, I'm slipping back into passive-aggressive mode.  I do apologize for that.  It's something I need to correct.  But, again, I digress...

My point is that everybody needs to care about the software.  Everybody who's involved, anyway.  The developer, the tech lead, the project manager, the tester, the product owner, the data analyst, the executives who run the whole company... everybody.  Anybody who doesn't care about the project doesn't belong on the team.

Wait... the executives?

Yes, the executives.  Everybody who has a stake in the software.  This particular example of a stakeholder highlights a particular scenario, though.  Not everybody has the time to personally be involved in the software.  This doesn't mean they shouldn't care, it simply means that they delegate the responsibility to somebody else and trust that somebody.  And that somebody needs to deliver.  They need to care.

So, maybe the Product Owner in this case didn't have the time to personally be involved.  Then delegate.  And trust your delegation.  That means that if you delegate your ownership of the software entirely to the developer, then understand that whatever the developer does is owned by you.  The developer is responsible for his or her decisions, naturally.  But as the person who delegated the effort, so are you.

The previous developer made the wrong decisions.  Don't make the same mistake again.

Your software is as important as you make it.  If you just do some hand-waving and walk away, what results do you expect?

So, for better or for worse, at least my current client cares.  The business person does need to know.  And the business person wants to know.  Which is a pretty good position to have.