Just got this in email:
Our April meeting will not be held on our regular 3rd Tuesday of the
month. It will most likely be on the 4th Tuesday - April 22nd. We are
awaiting confirmation that our regular meeting location will be
available to us on the 22nd. We'll send out the details as soon as they
are finalized.
Thought you'd want to see it if you didn't get it.
I think the ALT.NET brand is recognizable but awareness is lacking a bit.
If you've been wondering what exactly is going on, take a look at this short piece in the latest MSDN Magazine by Jeremy D. Miller. And then head to the wiki for more.
I was in Austin in October and I'll be in Seattle in April...
[update] Hanselminutes podcast on ALT.NET with David Laribee
In-house developers (software developers that work for an IT department and not a software development firm) openly condemn their plight of being tasked to design software quickly rather than correctly.
In-house developers rely on environmental certainty. We have a comfortable technical environment. We have our data sources, our common web services, a monolith HR system, and these things never change.
Right? Never? ...
Mergers, acquisitions, vendor changes, new technologies, staff changes, user requests, management fiat, budgetary constraints...
To overly rely on your environment is an anti-pattern for corporate developers.
My company was acquired in November by a huge mammoth company that isn't asking questions about why our data sources are useful. Our technical environment is about to radically change.
Fortunately it's not hard to reduce dependencies on certain external services in our applications. Here is a real-world five-minute example with a scenario should be familiar to most in-house devs.
Interfaces define the implementation
There's a web application. In it we like to do things with the currently logged in user. Show data specific to that user, display the user's real name, etc. We call a web service to get the full name from the login name. I'd wager that almost every moderate-sized company has a "directory" web service like this.
public class GetFullNameService
{
public string GetFullName(string username)
{
string fullname;
// call your web service and get the full name
return fullname;
}
}
Great, wonderful, okay. But to prepare for an eventual change in environment, we should write an interface so that we can switch out the implementation using dependency injection.
public interface IGetFullNameService
{
string GetFullName(string username);
}
This is useful because my new implementation (the one that will work after the acquisition is complete) is totally different, in fact instead of a web service it uses ADO.NET against OHR.
public class OHRFullNameService : IGetFullNameService
{
public string GetFullName(string username)
{
// use ADO.NET to call OHR
return "full name";
}
}
Since I am programming against an interface and have written a new implementation I can just do a find and replace and change all the GetFullNameService calls to call OHRFullNameService, rebuild, redeploy and ... um, no.
Using dependency injection to swap out implementations
So now we have an interface and two implementations. In the application, we might see something like
public class BasePage : Page
{
private IGetFullNameService _nameService;
public BasePage()
{
_nameService = new GetFullNameService();
}
}
Instead of newing up a concrete type we can use dependency injection to create the instance for us:
public class BasePage : Page
{
private IGetFullNameService _nameService;
public BasePage()
{
_nameService = (IGetFullNameService)
ObjectFactory.GetInstance(typeof (IGetFullNameService));
}
}
Now our BasePage class doesn't care which implementation of IGetFullNameService we use!
Configuring the dependency injection container (StructureMap, in this example) is super easy. You can set this up to use attributes instead of a configuration file. But here is a simple, sample StructureMap.config:
<?xml version="1.0" encoding="utf-8" ?>
<StructureMap>
<PluginFamily
Type="MyProject.Web.Services.IGetFullNameService"
Assembly="MyProject.Web"
DefaultKey="Default">
<Plugin Assembly="MyProject.Web"
Type="MyProject.Web.Services.GetFullNameService"
ConcreteKey="Default"/>
<Plugin Assembly="MyProject.Web"
Type="MyProject.Web.Services.OHRFullNameService"
ConcreteKey="OHR"/>
</PluginFamily>
</StructureMap>
Changing the implementation fro GetFullNameService to OHRFullNameService is as easy as changing the DefaultKey attribute of the PluginFamily element to "OHR".
So we've successfully eliminated our dependency on one aspect of our technical environment and we are secure knowing that if our environment changes, we can handle it easily.
So this is just the start down a deep rabbit hole. There are a few more considerations if you are developing an application using dependency injection that I have omitted from this post. Fortunately there are resources out there.. a good starting place is Jeremy Miller's blog and my links to DI resources.
I saw a post today about ORMs and how they are hard to use and maintain. Since we saw ActiveRecord/NHibernate at Ben's talk and we're going to have more talks on ORM tools there may be questions. I wanted to share my experience and assuage some fears about ORMs that may be holding you up from getting started..
I'm using NHibernate, which does have a learning curve, but it's not as steep as you might think.
Here are one of the criticisms mentioned:
They are not legacy system friendly meaning they are a nightmare to implement
My current project is pulling data from an Oracle 9i database with a schema and data that has been around for 10+ years. I created a few new tables for my stuff and getting set up and relating to the old stuff was painless.
The most unmaintainable thing about the system is all the business rules encapsulated in stored procedures. Fortunately once I got the gist of those rules, which are also enforced in constraints, they were a snap to implement in code.
Real nightmares
What is a nightmare is the previous app that used this data. I found this method of the Account class used to persist new instances in that old, legacy app:
Public Function Save() As Int32
Dim MyDataAccess As New Legacy.BLL.DataAccess
Dim MyCommand As New OleDbCommand
Dim sb As New StringBuilder
sb.Append("LEGACY_ACCT_PKG.SAVE_ACCOUNT")
MyCommand.CommandText = sb.ToString
MyCommand.Parameters.Add(New OleDbParameter("pACCOUNTID", OleDbType.Numeric, 22, ParameterDirection.Input)).Value = _ID
' ... 20+ more parameters!!! horror!
MyDataAccess.isSetGlobalContext = True
MyDataAccess.RunSP("", MyCommand)
End Function
This is one of hundreds of similar CRUD methods in this app. Not maintainable.
I don't have a save method in my class, I am using repositories.. the actual "data access" code, common to all the objects I persist is:
public virtual T Save(T entity)
{
NHibernateSession.Save(entity);
return entity;
}
To me that was very easy. NHibernate handles things for me, I don't have to worry about 20 or 30 of the things that a user of that one old-fashioned method has to worry about. Including all that horrible ADO.NET mess.
Query languages considered harmful?
Here's another criticism:
They require an Intermediary Query Language which means extra work for the programmer
Eh... ok, extra work to learn a query language. Getting the gist of NHibernate's query language takes about 5 minutes. If you want to explore its intricacies, take an hour to parse the relevant docs. But writing it is pretty easy! Here's a simple but typical example of a query to pull back all Projects that a certain Employee is a TeamMember of (think of it as populating a grid on a "My Projects" page):
from Project p join fetch p.Team t where t.Employee = ?
which generates SQL something like:
select * from project
inner join team on project.id = team.projectid
where team.emplid = :p
Still, there's no requirement that you learn HQL. There are other ways to query: using the Criteria API, straight SQL and in code. It's okay to decide to avoid pain.
Pain relief
If religion is opium for the masses then object relational mapping would be like Aspirin in the programming world . Not powerful enough to get any programmer high and makes programming easier for about four hours, then real sedation is required to mask the pain. They have even been likened to an unwinnable war in South-East Asia.
This has not been my experience. What causes me pain is having to deal with the data access myself, or to have queries in my code-behind or worse, in the markup. It's painful to worry about columns and constraints instead of conceptual relationships and meaning.
Here are some NHibernate resources I found to be really helpful:
Critical to read the documentation
Billy McCafferty's NHibernate Best Practices (I read it four times and it keeps getting better)
Ben Scheirman's NHibernate screencast (very good tips in here)
Setting up NHibernate mapping intellisense
Example application: Cuyahoga CMS source
Example application: CodeCampServer
Jon Galloway touched on it in his blog post today:
The best way to learn is to "aspire to be the dumbest person in the room."
Being the smartest person in the room is comfortable - you can feel
smug and important as you deign to dole out information. It's also the
surest way to avoid learning anything. Surrounding yourself with people
who are better informed than you are is a great way to keep learning,
but it can take away your confidence in what you've got to say.
Wrong solutions:
- Keep quiet for fear of saying something stupid
- Keep quiet because all those other brilliant people will probably say it soon, and better
Solution:
- Don't write for your own ego, write to share information
- Accept
that publishing anything on the internet is one of the best ways to
invite constructive criticism for what you think you know
Ah, to invite criticism! To publicly lay intellectually prone with your fleshy bellyful of ideas exposed to the anonymous internet is an incredibly scary thing.
It takes a good deal of confidence to participate online.
On the old altnetconf list, Alex McMahon explains: He ranks participation online by confidence required
- Casual chat with close colleagues
- Meeting/workshop with close colleagues
- Meeting/workshop with unknowns
- Writing on internal blog
- Writing on internal blog and actually telling people about it and referring them to it
- Writing on internal wiki
- Releasing a 'proper' guidance document internally
- (4-7 on the internet)
So join a mailing list list, hang out on Twitter, write the blog and participate in the community. Another way to pitch in is to contribute to open source software. I've been working on codecampserver, and even though sometimes I feel I am "the dumbest person in the room" the learning experiences, contacts I've made and pure coding thrills have been invaluable.
My friend is a software developer, but he doesn't work for a software company. He works for a home builder, or a pipe manufacturer, or a retailer. His job is to deliver software, but delivering software isn't the organization's core competency.
This friend of mine is an in house developer haunted by this reality:
You never get to do things the right way. You always have to do things the expedient way ... Once the core functionality is there, the main problem is solved, there
is absolutely no return-on-investment, no business reason to make the
software any better. So all of these in house programs look like a
dog’s breakfast: because it’s just not worth a penny to make them look
nice. Forget any pride in workmanship or craftsmanship you learned in CS323.
You’re going to churn out embarrassing junk, and then, you’re going to
rush off to patch up last year’s embarrassing junk which is starting to
break down because it wasn’t done right in the first place.
On the other hand, a comfortable technical environment means he can focus more on building great software for his users and less on the complexities and headache of struggling through technical challenges.
Are you an in house developer? What anti-patterns do in house developers uniquely face?
I noticed about two dozen eyes glaze over last night when Ben started talking about dependency injection.
This stuff rocked my world when I started understanding it. Things I used to worry about are non-starters now, and I've been freed to worry about what I should have been worrying about all along. By that I mean I am able to write good code because decoupling my objects doesn't have a complexity penalty. It's quite liberating.
I had a chat with someone who has been helping me go like this:
11:39 AM me:
if i have SearchService use another repository (say,
IProductsRepository).... it's cool to just add a parameter to the
constructor? seems to be
11:40 AM XXX: yes, structuremap will build it for you
11:41 AM me:
just to make sure i am getting this right: there is no value in
overloading the constructor, and there is no worry about having too
many parameters since DI is used.
11:45 AM XXX: yeah, you got it
11:46 AM me: freaky
Here are some starting points to get up to speed.
You might want to go over the Windsor getting started walkthrough. Here, Inversion of control isn't used in exactly the same way it was demonstrated last night, but you can get acclimated to the techncial capabilities of a container.
There's a ton of info at BitterCoder's Windsor Wiki and more in a great article from Simone Busoli. You can also surf the list of popular posts tagged ioc on del.icio.us (which always has great information about a given topic)...
Besides Windsor, there are other containers for .NET: StructureMap, Spring.Net, and ObjectBuilder.