Monday, March 24, 2008

Visual Studio is not a build tool

Visual Studio (henceforth Visual Fucking Studio) is not a build tool. I have spent the last few days hating Visual Fucking Studio more than ever before. I have hated on it in the past for things like the "Add new item" dialog box that has about 100 different options in no particular order that are all just names for a text file. I have hated the "add reference" dialog box that takes forever to load because it always has to parse every .Net assembly in the GAC and every COM object ever created before it can load (I know they fixed this in .Net 2008 but it still takes a long time to load the first time and I wish it would default to the "project references" tab because that's what I always fucking use). Both of these things that I hate specifically, however, are nothing compared to the build issues that I've had in the last few days.

How we build normally

So on my TeamCity server, I build the project using a Nant script. This is really not hard and it works well. You can also run the build script locally, and thanks to a few ideas that I've borrowed from some people it all works quite nicely and has very few issues. In fact, the biggest problem that happens is when someone adds or removes a file in the Visual Studio project and forgets to modify Subversion to include/remove the file and breaks the build but this is easy enough to detect and fix.

However, people on the dev team absolutely have to have the capability to build the project using ctrl-shift-b and run it with f5 so that they can debug in the Visual Studio environment. This means that when I hit f5 it has to work. This is the way of pain.

Why oh why did I remove that project????

So our application needs to work with both Sql and Oracle with identical functionality. This is one of the most important requirements. As a result, we had to write a data access layer that was abstracted enough so that our factories didn't need to know what platform they were connecting to (there is a reason that we did this ourselves instead of using NHibernate or something similar but more about that in a future post). This project and it's associated dependencies is commonly referred to as the "Data Access Layer" for this project.

Now it turns out that we actually have three or four separate projects (and a few future projects) that will need the Data Access Layer in order for them to live. Initially, we wrote the Data Access Layer in our main solution file for the application, but as soon as we realized that we'd need it in other places, I decided to factor the Data Access Layer out of that solution and give it its own independent solution and build process (it took me about five minutes to modify team city and our NAnt script to set up this new project). So, I now have a separate Data Access Layer solution that I can reference in all projects that are dependent on it. Now I try to build the main application solution and that's when the fun started.

You can't reference that

So you can't reference a project in another solution using Visual Studio. Ok, not a problem, let's just use a file reference. Well, where do we point the reference to? Oh, well there's the obj/debug directory that has the DataAccess.dll and it's associated referenced dll's, let's point it to that. But wait, what about obj/Release? What if we change the build mode? Well, it's unlikely that the developer builds will not be in debug mode, unless there's a bug that is only reproducible in release mode or one of 1000000000 other scenarios that would necessitate it. That means that you'd have to change the reference. What if we move that project around more? You'd have to change the reference. What if we blah, blah, blah you get the idea.

So, I get a great idea: I'm going to create an Artifacts directory in a common location for the build. Then I can just reference whatever DLL is in there so it will work in whatever mode I built the Data Access Layer in. I'll create a postbuild step that deploys them into the artifacts directory and then keep them out of version control. That way, all you have to do is make sure you build Data Access Layer and everything else will build. Cool.

Batch files have been around for years and they're not hard

So I write a simple Copy command in the post build step in Visual Fucking Studio. I run it. "Error: The command exited with code 1." WHAT THE FUCK DOES THAT MEAN? I check the output that Visual Fucking Studio tells me its running and it turns out that some of its macros don't actually mean what you think they mean and append an extra slash on them, so ${projdir)\bin actually resolves to c:\some project\directory\\bin instead. I fix this, it runs. I run it again a few minutes later "Error: The command exited with code 9663." WTF, bitch? What do you want now? I finally start adding echo and dir commands and determine that the command is being run on the wrong directory so no files were originally copied. Now I run it a second time and I get "Error: The command exited with code 9347" or something. This is about when I wished I hadn't quit smoking. I forget what fixed this, but suddenly I'm getting "0 files copied" which is not what I want, particularly when there should be 3 files copied because the source directory has three files in it and copy *.* means copy all files, in this case THREE OF THEM.

Are you sure (y/n)?

It takes me a minute to figure out that the copy command wants to ask you if the files should be overwritten first and if you don't answer it assumes that you don't. Adding /Y to it only surpresses that message but it still assumes that you don't want to overwrite. Fuck you, DOS. I wish I had cygwin installed about now, but that isn't helping me fix the build. So I add a delete command to my artifacts directory prior to the copy and after another "exited with code 1" I determine that there's another one of those directory path issues and finally get it to work. Happiness.

We sure are lucky the build worked at all

So now I start looking at getting the remaining application solution to build. When I first start, it utterly fails for some reason. It turns out that no dependencies were set between projects and there was no build order, so the whole time we were working on this project it was coincidence that it was building correctly. I set some dependencies and changed the build order and put in a reference to my Artifacts directory and the build worked. So I hit f5 to run the application and what happens? App no work. Sadness. After a few more minutes, it turns out that since this is a web app and the UI is in its own project, all the DLL's need to be copied in the UI/bin directory and of course they're not. Our project is structured so that each project should only reference a project that is directly below it. This keeps UI from referencing Data Access Layer which is a good thing. However, without a reference, it won't copy the dll's over because Visual Fucking Studio is not smart enough to follow references in dependent projects. Not a problem, I'll add a postbuild event to copy all the dll's from artifacts and the other output directories into the UI/bin folder. Go back and re-read the previous paragraph because that's pretty much the same thing I went through to add this post build step. I even copied and pasted the commands from the Data Access Layer but it still didn't work. I don't even remember why. I think in total that I spent almost four hours trying to copy like six files into a few directories as part of a build that we're never even going to use except to set breakpoints in the app and run it. I really hate Visual Fucking Studio right now.

Things to fix:

Here's what I'd like to see changed in Visual Fucking Studio:

  1. If I reference a project and that project has references to anything not in the GAC, chase down those references and copy every binary I need into the /bin folder where the app is going to run.
  2. It appears that Visual Fucking Studio just puts all the commands that I add to prebuild and postbuild events into a .bat file and runs them. I would like to see that .bat file. Better yet, I would like that .bat file not to exist and for it to just run the commands.
  3. I want to see WHICH command failed in my steps, not just some useless error code.
  4. I would like to be able to add a reference to another project in a different solution.

I don't foresee myself not using Nant any time in the future.


James said...

Watch your fucking language, Tucker.

Flip said...

I feel your pain. Visual Studio is a fucking piece of shit.

Anonymous said...

I'm with you. I'm here because "The command....exited with code 1." WTF does that mean???

More-used-to-Eclipse said...

Yup, Windows' command-line stuff is a pile-o-shite compared to just about everything else.
Mind you, I wouldn't rate Visual Studio itself much higher - it's only half there (one needs to purchase lots of commercial add-ons to fill the gaps), and as you've said "it's not a build tool".
It doesn't even appear to know when its builds are finished, as it runs the "post build event" command before it's finished building its own stuff, causing programs that read the files its generated to get told "FILENOTFOUND" by windows (which doesn't allow multiple programs to use the same file). Adding a 5 second pause before doing anything seems to (usually) fix that though.

Unfinished, unreliable, non-deterministic. If it were free, it still wouldn't be good value for money.

Joris Verbeek said...

I think you are a little to frustrated. Guys like you should use Waterfall methodology. You are a shame for the Agile community.

Roger said...

Go and first take some beginner classes that include the Visual Excellent Studio IDE.

Then all your frustrations will become a thing of the past.

Good luck!

Anonymous said...

Yeah I'm with ya - fuck Visual Studio. 2010 is no better. I honestly don't know what Microsoft developers do all year - I mean - it's 2010. We're emant to have flying cars by now, and Visual Studio still ends up in a non-deterministic state once a day. Fuck Microsoft.

Anonymous said...

It seems the problem is not Visual Studio, but your ability to use it (although I'll agree VS2010 is an utter dog).

Build scripts are for people tasked to do product builds and for automated build tools like CruiseControl.Net

For the regular developer VS.Net is the perfect tool. If VS.Net is considered a problem in that context then there's a problem with the way you have set up your source tree. No developer should have to build everything locally just to get going.