The Toilet Bowl Manager

This is number 4 in my series of ridiculous happenings in my software development career.

I had just left my first paying job at Ubber-IT Company to start a new job at a small consulting firm specializing in the new paradigm of "Client-Server" development.  I will call this company Upstart Consulting.

Upstart sent me to several weeks of training on their methodology and development tools of choice and then sent me out on my first project.  The project was for a large railroad and our task was develop a scheduling and settlements system for their railcar transactions.

After being at the client site for a few weeks, I dropped by the men’s room one day after lunch for a quick visit.  As I entered the room, I heard an unusual noise that I could not identify.  I looked around and saw a hand drop down from under the first stall wall.  I thought to myself, "My god, this guy is having a heart attack or something!".

I rushed to the stall door and looked over the top.  The guy was sleeping on the toilet!  Snoring quite loudly, I might add.

I went back to my team and told them what I had just seen.  One of my co-workers, an employee of the client, said "Oh yeah, that is <name removed>, he is a manager over the <group name removed> area.  He sleeps on the toilet every day after lunch." 

A brief survey of his employees and peers revealed they were all aware of this interesting habit.

At that point in my career, I had not yet been exposed to the enormous amount of waste that goes on in large companies and I have not seen a situation of this magnitude of acceptance since then. 

Apparently, this goes on much more than my experience tells me.  Here is a video that is very funny.

By the way, Toilet Bowl Manager’s technique was very similar to Coma in toilet 1.

Tags:

Ease Versioning Multiple Assemblies by Splitting Up AssemblyInfo

Most .Net project deployments are made up of multiple assemblies and it is common to version all assemblies in a given release with the same version numbers.  Since changing each AssemblyInfo.cs file can be time consuming and error prone, most projects take one of two approaches to solving the problem:

  1. Generate AssemblyInfo.cs files using an nant build scripts and setting properties.
  2. Use a single AssemblyInfo file and have all projects reference that file.

Both approaches have pluses and minuses.  Generating AssemblyInfo.cs can be hard to setup and get correct but is more flexible.  Using a single AssemblyInfo.cs and have each project reference it is easier but all projects will have the same information in the assembly properties.

A hybrid approach that many developers overlook is splitting AssemblyInfo.cs into an assembly specific version and a product wide version.  Each Visual Studio project would contain the standard AssemblyInfo.cs file that is generated by the project templates.  The difference would be that product wide attributes are removed.  See the sample AssemblyInfo.cs file below for an assembly named ClassLibrary1.dll:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyDescription("Assembly for ClassLibrary1")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e96237d4-2420-4dc7-aed2-43a121bd0221")]

Notice that several of the standard attributes have been removed.  Those attributes are moved to a file in a central directory so that it can be changed once for several projects.  The following is the contents of a sample file containing these attributes, named ProductAssemblyInfo.cs:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyCompany("My Company")]
[assembly: AssemblyProduct("My Product")]
[assembly: AssemblyCopyright("Copyright ©  2007")]
[assembly: AssemblyTrademark("")]


// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Revision and Build Numbers 
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.1.0")]

After creating the product level AssemblyInfo, multiple VS.net projects can reference it and pull in those attributes.  Below is a snapshot of my Solution Explorer within VS.net 2005.  Each project has their own AssemblyInfo.cs but each also has a reference to ProductAssemblyInfo.cs.  Once the solution is rebuilt, each assembly will have the combination of the attributes in ProductAssemblyInfo.cs and the specific AssemblyInfo.cs.


This approach allows each assembly to have a separate AssemblyTitle, AssemblyDescription, GUID, and ComVisible Setting, while maintaining the ability to change the version numbers and company information in one place and have all assembly builds pick up the updated attributes.

If you are using a continuous integration server like CruiseControl.net, a build dependency can be set on the directory containing ProductAssemblyInfo.cs for each individual build in your product deployment.  That way, the entire product will rebuild automatically with new version numbers after ProductAssemblyInfo.cs has been modified.

kick it on DotNetKicks.com

Tags: , , , , ,

How Not to Respond to User Requests for Functionality

I love ReSharper.  I am using Visual Studio 2008 and Jetbrains does not have a released version of ReSharper that completely works with the new language features in C# 3.0.  This morning I was looking at the ReSharper newsgroup to see if there is any discussion about the upcoming 4.0 release and I did find an informative discussion.  A user of ReSharper was met with an interesting reply when he asked when the product would support the C# 3.0 language features.  I have removed names and links that would identify people because the purpose of this post is not to embarrass people.

Hello <potential user>,

It seems to me there are two parts in the topic.

First, current state of ReSharper in regards of VS2008 I tried to address
in my post here: <link to post at employee’s personal blog>

Second, why do you need to use C# 3.0 right now? It is not mature enough,
it is not tested in industry, pitfalls and glitches are not known yet, there
are plenty of scepticism out there on the web and nobody really knows how
to work with it. Well, there are some marketing and other "it’s so cool"
stuff on the web, but do you believe that LINQ or extension methods will
do their job better than existing solutions like ActiveRecord (http://www.castleproject.org/activerecord/index.html)
and other alternative, non-microsoft tools? We really want to know this,
honestly. There is so much buzz about how cool "var" keyword or automatic
properties are, but with ReSharper you almost don’t need them 🙂 
So, could you please tell us, why do you need to use VS2008 with C# 3.0 right
now?

Sincerely,
<employee>

JetBrains, Inc
http://www.jetbrains.com
"Develop with pleasure!"

After a few users chimed in with WTF types of responses, <employee> realized that this was probably not the correct way to respond and attempted to rectify the situation with the following reply.

Hello <another potential user>,

My apologise, I didn’t mean to abuse anyone. I just expressed my own opinion,
it is community newsgroup after all 🙂 May be I was too much expressive…

Anyway, I’m really interested in the reasons people are so anxious about
VS2008 and C# 3.0. And more than that, I’m interested why people need it
*now*! It was out there for a while, in a CTP, then Beta. Release in not
something that significantly changes products like VS2008 or .NET 3.5.

For me, I have to use VS2008 and C# 3.0, so that ReSharper 4 will be good
in terms of usability, feature set and language support. If I were developing
business application, I’d wait several months while constantly monitoring
the web to understand the problems I may have when I upgrade. That’s how
I would treat VS2008 release if I were on different project. On the other
hand, if I were on the hobby-project or something research-like, I’d be using
Orcas since any time it was usable to write code and do not crash too often.
For me, "RTM" mark doesn’t change much.

Sincerely,
<employee>

JetBrains, Inc
http://www.jetbrains.com
"Develop with pleasure!"

First, I would like to say that ReSharper is an outstanding product and I have a great deal of admiration for the Jetbrains developers.  As a Visual Studio addin developer, I realize how difficult the functionality is to develop that they have in their product.

That said, these were both terrible posts.  I realize this employee was voicing his own personal feelings but it was on a newsgroup for the company’s product and the signature of the post makes it seem like an official company stance on the matter.

There are two major roles in software development:  users and developers.  I know there are actually many more than that, like QA staff, technical writers, project managers, etc. but I am lumping all of those roles into developers for this discussion.  If you are in the developer category, people in the user category tell you the functionality they want.  Your job, as a developer,  is to evaluate those requests and to deliver that functionality if it is cost effective to do so.  Obviously, you can’t spend a huge amount of money working on a feature that will never make back your investment in that feature. 

However, in this case, users want the product to work with the latest C# language features and I do not think that is unreasonable for them to expect.  There was a long beta period for VS.net 2008 and I know that the VS.net SDK documentation was not kept up to date with the beta releases, which makes it difficult for addin and package developers to release products simultaneously with the Visual Studio release.

Yes, Visual Studio betas are not always stable.  Yes, supporting C# 3.0 was very difficult even for the Microsoft compiler developers.  That is why people are paying for ReSharper.  The product does amazing things that are difficult to develop.  If it were easy, nobody would need to buy the product.  Instead, they would develop it themselves.  In fact, there is a value proposition that every potential customer of every development or support tool product weighs when they look at options to fill a need. 

"Will it cost me more to develop the equivalent functionality than it will to buy it?"

 In the case of ReSharper and Visual Studio addins specifically, the question is more like

"Will this product pay for itself by increasing my productivity to cover the cost of the initial expense?" 

If you need to use C# 3.0 features, the answer currently for ReSharper is more questionable than it has been in the past.

Telling your users that the features they want are not important right now is a sure way to get them looking at your competitors.

Tags: , ,

The Marathon Man

This is the third of my series of ridiculous people and happenings that I have come across in my career.  If you have been following along, you know that my career (at least paid career) started at a large company I refer to as Ubber-IT Company.  My first role at Ubber was in a support group working with jcl mostly but generally performing the tasks that nobody else wanted to deal with.

I had moved into a new role with a group that developed document imaging systems using that crazy new technology paradigm called "Client-Server".  I enjoyed working in this group because everything new in tech was what we were working with.  What also made the role interesting was the group of developers I worked with.  They were real programmers.  I have never had the chance to thank this group of developers for the inspiration they gave me, but I am convinced that I would never have accomplished what I have without working early on with a group like that.

However, my group back then is not the focus of the discussion today.  My team members and I sat in a huge cube farm and a few rows over was a group that worked on a project for Huge Government Agency.  This group was well known in Ubber for working obscenely long hours.  Calling what they did a death march doesn’t seem to capture it well because a march implies that it will end at some point.

There was one individual in particular who seemed to go beyond what the others on the Huge Government Agency project did.  I will call him Marathon Man.

I have always been an early riser, getting in to the office around 6 am.  Back then, with no wife and family, I also stayed quite late.  On occasion, I would even drop by the office on weekends and sometimes very late.  Even at these odd hours, I do not recall every being at the office when Marathon Man was not working diligently in his cubicle.

I came to the office early one Monday morning to find that Marathon Man was not in his cube.  Next to his cube was a window that had plywood covering it.  I walked over and wires were exposed from his desk, where his tube and keyboard used to sit.  I looked out the window (we were on the second floor) and below were parts of what used to be Marathon Man’s terminal.  Ubber maintenance had attempted to clean up the mess but there were far too many small parts to get it all in one pass.

Nobody said anything about this.  A few days later, a new tube appeared in Marathon Man’s cubicle and a new window replaced the plywood.  Still no sign of him.

A few weeks later, I saw one of Marathon Man’s teammates in the coffee room and quietly asked what had happened.  He said, "The guy just snapped.  He had a bug that absolutely needed to be fixed by Monday morning and he wasn’t going to make it.  He finally tore his tube out and threw it out the window.  Nobody has heard from the guy since."

I walked out of the coffee room stunned at what I had heard.  I knew then that Ubber wasn’t the company for me and started planning my departure.

I never saw Marathon Man again.  I think of him every now and then and I envision him at a tropical resort, sipping a drink with umbrellas in it, watching the sunset.

Tags: , ,

TortoiseSVN and Creating a Patch Containing New Files in New Directories

This morning I was attempting to create a patch, using TortoiseSVN, that contained new files within newly added directories.  When I selected the files to include in the patch, I was met with the following message:

You’ve selected added folders.  The patch won’t contain added files within such added folders.  Do you want to proceed anyway?

Sure enough, some of the files were not included in the patch.  Thinking this must be my fault, I blew away the new directories and reverted everything to the previous version.  I then created the new directories and added back the new files making sure that the Add to Subversion was all done properly.

The second time I received the same error.  The TortoiseSVN docs did not seem to offer any suggestions so I download the Subversion binaries from here at Tigris.org.  Afterwards, I was able to create the patch by running:

svn diff > pathfilename.patch

The patch file produced was just as I hoped it would be, including all directories and files.  I’m not sure if I was doing something wrong in TortoiseSVN or if this is just a bug, but if you encounter this error just download the Subversion binaries and run the diff from the commandline.

Tags: , , , ,

Opera is bringing an EU antitrust complaint against Microsoft

I read this story on Redmond Developer News this morning.  This quote basically summarizes the complaint:

We are filing this complaint on behalf of all consumers who are tired of having a monopolist make choices for them

I am wondering why these frustrated consumers don’t just use the monopolist software product one last time to google for alternative web browser windows and download one of the options.

This complaint has as much chance of actually working as the whole SCO vs. IBM thing.  My favorite quote is:

In addition to promoting the free choice of individual consumers, we are a champion of open Web standards and cross-platform innovation.  We cannot rest until we’ve brought fair and equitable options to consumers worldwide.

Yes you can, Opera.  You can rest right after you have bankrupted yourself attempting to sue a behemoth company that has more lawyers on its staff than you have total employees.  If you need publicity for your product, it will be much cheaper and effective to place a full page ad in every major newspaper in the EU.

Even though I am sure it is fine product, I have never used Opera.  However, I do share something in common with  them:  It is difficult to get knowledge of your product offerings to the consumers that could be interested in buying those products.  It is much more difficult than most people think.  This is specifically true for software products for the general public.  People want to use what they are familiar with and what is easy for them to obtain.  Contrary to their quote, I believe that the number of consumers that are tired of the monopolist is probably about topped out and those people have made their choice.  Unfortunately for Opera, the choice was some other product.

I recently read that market share for the Opera browser is under 1%, while Firefox is somewhere around 10-12%.  I think Safari was around the same percentage as Firefox.  I am not sure how accurate these numbers are and I can’t even remember where they came from.  However, the numbers seem to reflect my own personal surveys of folks I know and they mean that Opera needs to raise their market share if they do not want to go away for good.  I just don’t think this particular approach is going to work for them, even though the EU seems more sympathetic to these types of complaints than their US counterparts.

Of course, these numbers could also change if consumers begin to try other operating systems due to frustration with windows vista or just due to those funny mac vs. pc commercials.  The numbers say this would favor Firefox and Safari instead of Opera.  This is what Opera needs to work on instead of making sure they use up the legal budget before year end.

I have tried Firefox and I use Safari on my mac.  Both are good browsers but I still use IE when I am on windows.  With IE 7, the product has tabbed browsing and pop-up blocking and those are the killer features for me.  The reality is most of my web browsing comes from my rss reader and not my stand alone web browser.

Tags: , , ,

The Smoke Stack

This is the second in my series on ridiculous things that have happened to me in my career.  As you may recall, I started off my career at a large IT company that I will call Ubber-IT Company  My position was in a support group for other development teams.  However, my team was not the only support team.  There was another team composed of only one guy as far as I could tell.  I will refrain from giving his real name.  Instead I will refer to him as The Smoke Stack.

The Smoke Stack was a system’s engineer in the real sense of the word.  His job was to actual write code that interacted with the mainframe OS.

Most people preferred not to interact with The Smoke Stack.  Back in those days, people were actually allowed to smoke inside some office buildings.  Even though smoking was still technically allowed, very few people smoked inside.  The Smoke Stack was one of these people and the Ubber gave him an enclosed office to reduce the chance of the offending odor engulfing the entire area.  In addition to the heavy smoking, he was also very offensive in his speech.  To make matters worse, he spoke broken English so you were never quite sure exactly what he said.

Needless to say, people avoided The Smoke Stack if at all possible and he seemed to enjoy that.

One day, The Smoke Stack needed a job created by my team and refused to give any written specifications to my manager.  The manager ordered to me to extract the specifications from The Smoke Stack and I was instructed to not perform any work until a suitable spec had been written.

I reluctantly went to Smoke Stack’s office and knocked on the door.  From inside I heard "@#%$# $#@@!  Come in!".  As I walked in the office, I was overcome by the smell.  The office was engulfed in a fog from the cigarette smoke and my eyes began to water.  There were stacks of dump output (core dumps from mainframe jobs) everywhere in the office and empty food containers stacked in the corner.  I’m certain that no member of the Ubber janitorial staff had entered this office in at least a decade.

There were five tubes (3270 emulator for you younger readers) on his desk generating quite a bit of heat for this small office.  Additionally, The Smoke Stack had a space heater generating at full capacity under his desk.  This made for an experience in heat usually reserved for the sauna when combined with the Ubber-IT Company requirement of wearing a suit with your jacket on at all times.

The first thing I said was "My manager is requiring a written spec before work on your job starts so I am here to get everything written down". 

The Smoke Stack countered with "That #@%$# @##@!.  I don’t write $@!$$ specs.  If you can’t understand what I $%#@$ say, and do it right, you shouldn’t be %$#&@ working here!".

At this point, I only been in his office for 45 seconds.  My eyes were bloodshot and I was sweating profusely.  I had to think of something fast or might end up in the corner with those food containers.  I decided to go with flattery.  "I understand where you are coming from.  It must be difficult working with these people for as long as you have.  I understand what you want but my manager absolutely will not allow me to work on this without something written down.  Can you help me out?".  Sort of a help me to help you moment.

The Smoke Stack looked at me, puzzled.  He mumbled "@#$%!" as he grabbed a stained napkin from his desk and quickly scribbled a few sentences on it.  The napkin appeared to have been previously used to wipe up a coffee spill.  At least that is what I made myself believe.

He handed me the spec/napkin and I was out of there, glad to get out of the office before passing out.  As far as I was concerned, that was the best spec I had ever seen.

ASP.net MVC, MVCContrib, and Using Spring.net as a Controller Factory

The ASP.net MVC CTP as been out for a few days and I have read quite a number of good posts about using the framework and extending the available functionality.  Keep an eye on the MVCContrib project over on CodePlex.  I can already see that many good things are going to come from this project, based on the functionality already being worked on.  There is already integration with the popular Dependency Injection (DI) containers including Windsor, StructureMap, and Spring.net (my contribution to the project).  For fans of Resharper, like myself, there will be some live templates developed to help with the normal programming tasks for ASP.net MVC projects.

For this post, I will be discussing the usage of the SpringControllerFactory and how it integrates with ASP.net MVC.

ASP.net MVC has the concept of a Controller Factory (IControllerFactory) that is used to create controller instances.  Developers can create their own IControllerFactory implementations to take advantage of class factory implementations already in use or DI/IoC containers like Spring.net.  SpringControllerFactory is the IControllerFactory implementation that is included with MVCContrib.  Getting started with using this controller factory is easy.  Below is a repeat of the brief documentation that I created on the MVCContrib Wiki for SpringControllerFactory, with some additional commentary.

First, you will need to add a reference to MVCContrib.Spring.dll to your project.  After adding the reference, you need to add some code to the Global.asax.cs file in your MVC application project to Configure the controller factory and tell the MVC framework about it.

protected void Application_Start(object sender, EventArgs e)
{
    //This example just sets the default context for 
    //use with the Spring.net Controller
    //Factory.  An IObjectFactory instance is also 
    //supported, if greater control over
    //Spring.net is desired.
 
    IApplicationContext ctx = ContextRegistry.GetContext();
    SpringControllerFactory.Configure(ctx);
 
    ControllerBuilder.Current.SetDefaultControllerFactory(
        typeof(SpringControllerFactory));
 
    //more configuration code for the MVC framework
} 

The code above retrieves the default Spring.net context and passes it to the static Configure() method on SpringControllerFactory.  Configure() will accept either an IObjectFactory instance or an IApplicationContext instance. Spring.net documentation recommends the IApplicationContext approach for most cases. IObjectFactory implementations allow for greater flexibility when you need it. This step is necessary to allow the developer to share the Spring.net context with the controller factory and any other components there might be in the application.  In other words, this allows a singleton to really be a singleton for the entire appdomain.  Since currently there is no way to pass an instance of a controller factory to ControllerBuilder (notice that SetDefaultControllerFactory() accepts a Type), somewhat ugly approaches need to be taken to share state between controller factories and other components. 

Some will probably not like the approach I took with the static Configure() method.  I went with the static method approach because I thought it was the most strait forward way of communicating to developers what needs to happen before the controller factory is used.  The developer of the Windsor controller factory implementation for MVCContrib took the approach of requiring the developer to extend the HttpApplication to implement the Windsor IContainerAccessor interface.  I really like this implementation but Spring.net does not really have the equivalent concept so I went with the simple static method approach.

The instances of IController that you create for your application now need to be configured in Spring.net.  Note that the object name for the IController instances need to be the Type.Name of each particular instance.  This isn’t really a great approach either, but like SetDefaultControllerFactory(), IControllerFactory.GetController() only accepts a Type parameter.   Phil Haack said they are looking into possibly changing this.  Phil, can you guys also look into allowing developers to pass an instance of IControllerFactory to the ControllerBuilder as well?  Pretty please?

Below is a shell of an IController implementation that I used for the unit testing of SpringControllerFactory and the configuration that would go along with it.

public class SimpleController : IController
{
    public void Execute(ControllerContext controllerContext)
    {
        //controller code goes here
    }
} 
<objects xmlns="http://www.springframework.net"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
 
  <object id="SimpleController" singleton="true" type="Examples.SimpleController"/>
 
</objects>

I am working on a full working sample application that uses Spring.net for the controller factory.  That sample will be included in the MVCContrib source tree as well and should be there soon.

kick it on DotNetKicks.com

Tags: , , , , , ,

ASP.Net 3.5 Extensions (MVC Framework) Preview is Out

I first read the news from Brad Abrams, but there are several links in my rss reader this morning.

Microsoft has released the preview of ASP.NET 3.5 Extensions, which includes the much anticipated (at least by me) MVC framework.  Also included are Astoria, which is apparently officially named ADO.NET Data Services, better data controls, and more Silverlight goodness as well as other things.

The download is available here.

Tags: , , ,

Are Extension Methods Useful for Normal Programming Tasks?

With the release of Visual Studio 2008, Microsoft also released C# 3.0.  The new language version includes some nice programmer productivity features like Anonymous Properties, Lamda Expressions, and Extension Methods.  I will be concentrating on Extension Methods for this post.

Extension methods allow a programmer to define a set of static methods in a static class that can be called on any object that matches the parameter type of the method.  Note that the methods must be in a static class or they may not be used as Extension methods.  For instance, I have defined the following static class named SampleExtension:



The only difference between ExtMethod1() and any other static method is the use of the keyword this.  The use of this string is basically saying that the Extension Method ExtMethod1() can operate on any object of type string and that the string itself should be passed to the method as a parameter. 

To use my new Extension Method, all I need to do is import the StringExtensions namespace and start calling the new method on string data types.


As you can see, Extension Methods make a class appear to have new methods that are not in the original class definition.  Visual Studio will even give you Intellisense for the Extension Methods in the namespaces you are referencing. 

Some of the dynamic languages, like Ruby for instance, have included this type of functionality for quite some time.  In fact, the Ruby on Rails framework makes extensive use of this type of functionality.  LINQ, new to .Net 3.5, utilizes Extension Methods to all developers to incorporate their collection types directly in the syntax of the queries.

Well printing to the console is nice, but not very useful in real life.  The method below demonstrates create an object instance based on string representation of the object type:


Below, I have added an example of calling this method.


The final aspect of Extension Method syntax I wanted to discuss is that, just like other static methods, Extension Methods may accept other parameters in addition to the object that is targeted for extension.  Below I have added a new overload to ExtMethod1() that accepts an additional string parameter:


Calling the method overload is just like calling any normal method:


Finally, developers might be tempted to put these extension methods operating on System.* types under the System namespace, thinking that it is more convenient for users of their methods.  I believe you should refrain from this and instead keep your Extension Methods in specialized namespaces.  This will keep users of your libraries from inadvertently using your methods when they do not intend to.  After all, every C# class imports the System namespace automatically.

In my opinion, Extension Methods are probably most useful for framework and reusable library development.  Now that Visual Studio 2008 is officially released, C# 3.0 will start gaining more usage, and we will see how people use this new capability.

I hope you find this brief introduction to Extension Methods useful.  You can find the sample code here.

Tags: , , ,

Next Page »