Dave wrote a really nice overview of how much he liked playing with Rake, the Ruby based build script. From his post I can say that it does indeed look nice in its awesomeness of clear usage and programmability. So why do I still have trouble migrating over from a “visual” build system (which we use and I cover here) like FinalBuilder and move to something like Rake?
I’ll try to think our loud and see where it leads me. Let’s compare the two approaches in several ways:
The Rake Way
The Visual Way (FinalBuilder in this case. Also check out Visual Build Pro)
What’s going on here?
The “what’s going on here” phase is what a developer faces when looking at the build script for the first time. I think the Rake way is very clear to understand what’s going on even if you don’t know ruby. But take a look at the visual way. It is easy not only to understand what is happening, but also the hierarchy of steps that are being taken.
I would find it much easier to explain to a new developer how the build works in a visual manner because of that.
Authoring Experience
A visual build developer does not need to learn a new language (Ruby) to start authoring or maintain the build. this is a huge plus. Sure, learning ruby is a great thing in itself, but it should not be a road block to create a build system. Once you know ruby though, what is the experience like? As I have not played with Rake myself, my assumptions about it are exactly that – assumptions. tell me if I’m wrong.
Ruby is easy to program in. Therefore the build should be easy to author once you know Ruby. Generally. I am not talking about custom tasks (separate point later).
Task Discoverability:
This is really important. How do you know which tasks you have available to you? I’m not sure how you know in Rake (other than sifting through source files?), but visually there are usually easy ways to see all the possible tasks, by category. see below:

As you select a task, it is easy to discover what it can do and what you need to give it as inputs. Rake and Ruby have intellisense (I’m guessing).
Visual authoring is really easy too, since it presents you with windows that let you know what inputs you need to put in for each task. here is an example:
Managing flow and logic
This is really important since any self respecting build script would do much more than simply compile or run tests. This is where you’d expect a programming based approach to have a mightier hand. It is absurdly easy to do flow logic in a programming based language. and simple if, for and switch will simply work as expected.
In my case, FinalBuilder also has excellent flow related logic that includes all of the above. Simple click the “if-else” task and arrange under it’s node anything that should be run if it is true (or false, your choice). here is how it looks(from left to right):
Some people find it silly to do such a “visual programming” thing. I think that this is good enough DSL for this medium with a balance of being easy to understand and having good flow control in an easy way.
Using Variables and parameters
In Rake you define the variables in the script files:
in a tool like FinalBuilder you set variables in a separate window and choose their scope(or even automatically have them set as env. variables):
You can also declare variables that include other variables in them (your binaries location is combined of your build location + Binaries for example).
So the visual way is at least comparable in feature set. Of course, you can modify, define and check for variables at runtime with the appropriate tasks.
Sub scripts and includes
in Ruby you can declare sub functions in the same script or in other scripts and just call them (by “include”ing them).
In FinalBuilder you can create “Action Lists” that look like tabs on the top of the build editor. You can also have tasks that invoke external build scripts. Action lists can also take in parameters (like functions) if you want, and use them in their work:
again, comparable, and reusable. although definitely more (actually, almost only) clicking (is that bad?)
Built in Tasks
This is where the visual stuff wins hands down, I believe. There are hundreds of built in, easily discoverable tasks in the FB IDE, which means I almost never have to write my own. In the four years I have used it, I can only recall a couple of times I had to create my own tasks. even then, there was always a way to do it differently if I wanted to.
Anything from file handling, Multi threaded tasks, text parting and Database manipulation to COM+, Active directory, obfuscators and installer tasks. it’s all there and easy to search for. With integrated help. Here is just the list of categories of tasks in FinalBuilder:
Rake has lots of stuff ,
but
it
is
not
even
close.
Am
I
wrong?
Custom Tasks and extensibility
You can very easily create custom tasks for Rake. You just write them. With FB you have several routes:
- Create a custom visual task that has a designer and form and everything, using its own integrated Task Studio (you can program its logic in C#),
- Run command lines and create custom batch files of console applications.
- Create the task in the build script itself using Powershell, VBScript or JavaScript (the editor has intellisense)
-
Ruby has some edge on ease of extensibility (it is almost frictionless). It takes longer with FB, but you almost never need it.
Debugging
You can easily debug Ruby scripts. FinalBuilder allows debugging as well by putting breakpoints on tasks and checking all variables and actions (plus watch windows for variables) when you break. Also, you can easily enabled and disable tasks that will run by simply checking and unchecking its checkbox:
I think they are comparable.
Compare and Merge
FinalBuilder saved to an XML File. it’s not great but it is somewhat mergeable. Ruby is very easy to merge. Assuming this is a frequent task (two people working on the build) Ruby will be much easier. However, I almost never need to do this since the build is usually handled by one person (or pair) at any time anyway.
Maintenance
It is easier to maintain something that is visual, where it is easy to find anything you are looking for. That is my feeling and I think the visual way is more maintainable than any Ruby or XML file.
Money
Ah. FinalBuilder costs money. Ruby does not. One will cost you more than the other. I don’t think FinalBuilder is the costlier one in this regard.
So, who wins in my book?
I have not yet found a really compelling reason to move to a non visual build script. I would love to hear good reasons for doing that as I am obviously missing something. Let me know what it is in the comments.
The first Israeli ALT.NET Conference was great and finished without a hitch!
Current videos from the (un) conference:

There is also:
People are already starting to write about it (here, here) and I'd like to thank everyone who showed up at the ungodly hour of 9 am on a Friday (that's like a Saturday for you Christian heathens). The talks were interesting but for me it was mainly about meeting the people and hanging out with people I feel stupid around.
Thanks to OrenEllenbogen for doing a riveting talk about the MS CCR runtime .
Thanks for all the tools people wrote down to recommend:
Thanks to our sponsors:
Typemock (for organization and food), Sela (for great hosting!), SQLink (for great drinks and chicks!), RedGate and Jetbrains (for free licenses!)



We will be having another one in 6 months or so and might have some "grok talk" meetings during the next months. Thanks again!
First, here is the code with the updates.
In the previous post I showed how you can declaratively create buttons with captions and icons in a visual studio addin. the next problem to solve in that space is how to you order them the way you want relative to each other?
A way I’ve come up with has a code based DSL that allows you to declare the location of each button type you have create like this:
public static ButtonLocationConfigurator LoadButtonConfiguration()
{
ButtonLocationConfigurator configurator = new ButtonLocationConfigurator();
configurator
.UnderCommandBar("MenuBar")
.UnderMenu("Test")
.PlaceButton<HelloWorldAddinAction>(ButtonVisuals.StartsNewGroup)
.PlaceButton<ActionThatReplacesItsIcon>();
return configurator;
}
The buttons should be placed correctly under the main menu bar under the test menu with the “HelloWorld” action above the other one.
Here is part of the code that makes this possible. first, what does the connect.cs look like?
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
if(connectMode == ext_ConnectMode.ext_cm_UISetup)
{
CommandBars bars = (CommandBars)_applicationObject.CommandBars;
Commands2 commands = (Commands2)_applicationObject.Commands;
AddinCreatorContext creatorContext =
new AddinCreatorContext(_applicationObject, _addInInstance, commands, bars);
AddinRegistry.LoadButtonsByConfiguration(creatorContext);
}
}
This works really nicely and you can grab that code the does it here.
in the previous post I said how I hated doing custom icons for addins and showed how you can make it work. In this post I’ll show what I feel is a better way of managing the actions on the buttons, and how to declaratively create buttons with icons that are loaded automatically.
First, You can download the source here. What you’ll find there are a bunch of helper classes and a base class that allows you to declare an addin button like this:
[AddinButtonCaption("yo","some description")]
[AddinButtonIconName("boldhs.bmp")]
[AddinUnderMenuName("MenuBar","Tools")]
public class HelloWorldAddinAction:AddinActionBase
{
public HelloWorldAddinAction(CommandBarButton relatedButton)
: base(relatedButton){}
public override void Execute()
{
MessageBox.Show("hello there!");
}
}
You set the caption, icon and location of the addin button using the attributes on top of the class. You need to inherit from AddinActionBase and override the Execute() method to do anything useful. You also get access to the related button to change its properties later on. The icon path is hard coded to be the location of the running assembly\icons.
here is another button that switches icons and text and is located under the “Test” menu:
[AddinButtonCaption("Another Button!","and descccc")]
[AddinButtonIconName("book_openhs.bmp")]
[AddinUnderMenuName("MenuBar","Test")]
class ActionThatReplacesItsIcon:AddinActionBase
{
private bool isOn = false;
public ActionThatReplacesItsIcon(CommandBarButton relatedButton)
: base(relatedButton)
{
}
public override void Execute()
{
MessageBox.Show("Another one!");
isOn = !isOn;
if(!isOn)
SetButtonIcon("book_anglehs.bmp");
else
SetButtonIcon("book_openhs.bmp");
RelatedButton.Caption = isOn.ToString();
}
}
It uses the “RelatedButton” property to set caption on the button, and uses a derived method “SetButtonIcon” to change icons.
So – how do you initialize all these buttons? in the “OnConnection” method, you call a special “AddinReflector” class that does all the work for you:
private DTE2 _applicationObject;
private AddIn _addInInstance;
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
if(connectMode == ext_ConnectMode.ext_cm_UISetup)
{
Commands2 commands = (Commands2)_applicationObject.Commands;
AddinReflector.LoadAllButtonsInCurrentAssembly(commands, _addInInstance,_applicationObject);
}
}
You need override another method to make the methods execute correctly:
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
AddinActionBase action = AddinRegistry.GetActionByName(commandName);
action.Execute();
handled=true;
}
}
The idea is simplicity: you want to add another button? with an icon? just create a simple class with some attributes and you’re done.
You can download the source here.
- Icons are hard coded to be found under [current assembly location]\icons
- the classes need to be declared in the current assembly (easily changed if you’d like)