Sergio and the sigil

Coding style per project

Posted by Sergio on 2008-06-01

A few months ago, when I installed Visual Studio 2008 on my system, I opened one of my projects, did the usual project conversion, edited some files, created a few others, saved, tested, and checked in source control. Another developer working on the same project, also with VS2008, later edited some of the same files I had edited.

Then I went to do a diff to verify the changes and I saw what I always hate to see. He hadn't changed a lot of code, but he was using different style settings in VS and all the extra spaces around ifs, function arguments, etc were making it harder to find the important changes. To be fair, I was the one that forgot to adjust my default settings to be more compatible with our current coding style.

The situation above is not all that critical, but is certainly a big annoyance. Some diff programs will allow you to ignore white space differences but it is still sickening to see your source code with mixed code formatting style in the same file, sometimes in the same method.

That kept me thinking: why aren't code format style settings part of the project? Imagine if you work for two different clients, with different standards, or that you are a contributor to Open Source projects that also have different opinions about code format. It's too easy to forget to adjust your settings every time you switch projects, even if you export and save the appropriate VS settings to import as needed. Any IDE with so many options as VS should offer an option to save any settings that deal with the actual code be part of the project. A developer should be able to explicitly ignore or change the project settings but not by default.

With that problem in mind, I thought it would be useful to just adopt the practice of exporting the VS settings that are relevant to the project coding style and checking that in source control too. Here's what I did.

Fire up the the Import and Export settings wizard and choose only the settings that relate to code formatting and for the languages the project uses, for example C#, HTML, and XML. In this case we will just do the C# settings.

 

Right here we hit a limitation in VS. There's no way to select only the code formatting settings for C#, so we will export all of them anyway. Once we do that, save the file to the project directory (like MyProject.vssettings) and add it to the project or solution. Open it in VS (it's just XML) an stare at the plethora of settings that are saved.

<UserSettings>
	  <ApplicationIdentity version="9.0"/>
	  <ToolsOptions>
	    <ToolsOptionsCategory name="TextEditor"
	    RegisteredName="TextEditor">
	      <ToolsOptionsSubCategory name="CSharp"
	    RegisteredName="CSharp" PackageName="Text Management Package">
	        <PropertyValue name="TabSize">4</PropertyValue>
	        <PropertyValue name="AutoListMembers">true</PropertyValue>
	        <!-- ...(snip)... -->
	        <PropertyValue name="AutoListParams">true</PropertyValue>
	      </ToolsOptionsSubCategory>
	      <ToolsOptionsSubCategory name="CSharp-Specific"
	    RegisteredName="CSharp-Specific"
	    PackageName="Visual C# Language Service Package">
	        <PropertyValue name="NewLines_QueryExpression_EachClause">1</PropertyValue>
	        <PropertyValue name="Space_Normalize">0</PropertyValue>
	        <PropertyValue name="WarnWhenMembersCauseCompilerGeneratedReferences">1</PropertyValue>
	        <PropertyValue name="CollapseInactiveBlocksOnOpen">1</PropertyValue>
	        <PropertyValue name="Watson_MaxExceptionsToReport">1</PropertyValue>
	        <PropertyValue name="EditAndContinueReportEnterBreakStateFailure">1</PropertyValue>
	        <!-- ...(snip)... -->
	        <PropertyValue name="RemoveUnusedUsings">1</PropertyValue>
	        <PropertyValue name="Rename_Overloads">0</PropertyValue>
	        <PropertyValue name="EncapsulateField_SearchInComments">0</PropertyValue>
	        <PropertyValue name="ProgressDialogDelaySeconds">2</PropertyValue>
	      </ToolsOptionsSubCategory>
	    </ToolsOptionsCategory>
	  </ToolsOptions>
	</UserSettings>

Upon closer inspection, we can more or less recognize each settings by their names. Let's remove the ones that don't seem to be related to code formatting. This is more or less a value judgment on the importance of some of the settings. My choice was to keep TabSize, IndentStyle, and InsertTabs in the first subcategory and, for the second subcategory, I'm keeping any of the setting whose name starts with NewLines_, Indent_, or Space_ and also the item named SortUsings.(I should probably just write a macro to do that at some point)

After all this sanitizing, my settings file is reduced to the following:

<UserSettings>
	  <ApplicationIdentity version="9.0"/>
	  <ToolsOptions>
	    <ToolsOptionsCategory name="TextEditor"
	    RegisteredName="TextEditor">
	      <ToolsOptionsSubCategory name="CSharp"
	    RegisteredName="CSharp" PackageName="Text Management Package">
	        <PropertyValue name="TabSize">4</PropertyValue>
	        <PropertyValue name="IndentStyle">2</PropertyValue>
	        <PropertyValue name="InsertTabs">true</PropertyValue>
	      </ToolsOptionsSubCategory>
	      <ToolsOptionsSubCategory name="CSharp-Specific"
	    RegisteredName="CSharp-Specific"
	    PackageName="Visual C# Language Service Package">
	        <PropertyValue name="NewLines_QueryExpression_EachClause">1</PropertyValue>
	        <PropertyValue name="Space_Normalize">0</PropertyValue>
	        <PropertyValue name="Space_AroundBinaryOperator">1</PropertyValue>
	        <PropertyValue name="NewLines_Braces_Method">1</PropertyValue>
	        <PropertyValue name="Indent_CaseLabels">1</PropertyValue>
	        <PropertyValue name="NewLines_Braces_ControlFlow">1</PropertyValue>
	        <PropertyValue name="NewLines_Braces_AnonymousMethod">1</PropertyValue>
	        <PropertyValue name="Space_WithinOtherParentheses">0</PropertyValue>
	        <PropertyValue name="Space_AfterBasesColon">1</PropertyValue>
	        <PropertyValue name="Indent_Braces">0</PropertyValue>
	        <PropertyValue name="Space_WithinMethodCallParentheses">0</PropertyValue>
	        <PropertyValue name="Space_AfterCast">0</PropertyValue>
	        <PropertyValue name="NewLines_Braces_CollectionInitializer">0</PropertyValue>
	        <PropertyValue name="NewLines_AnonymousTypeInitializer_EachMember">1</PropertyValue>
	        <PropertyValue name="NewLines_Keywords_Catch">1</PropertyValue>
	        <PropertyValue name="NewLines_Braces_ObjectInitializer">1</PropertyValue>
	        <PropertyValue name="NewLines_Braces_ArrayInitializer">0</PropertyValue>
	        <PropertyValue name="Space_WithinExpressionParentheses">0</PropertyValue>
	        <PropertyValue name="Space_InControlFlowConstruct">0</PropertyValue>
	        <PropertyValue name="Space_BetweenEmptyMethodDeclarationParentheses">0</PropertyValue>
	        <PropertyValue name="Indent_UnindentLabels">1</PropertyValue>
	        <PropertyValue name="SortUsings">1</PropertyValue>
	        <PropertyValue name="NewLines_ObjectInitializer_EachMember">1</PropertyValue>
	        <PropertyValue name="Space_WithinMethodDeclarationParentheses">0</PropertyValue>
	        <PropertyValue name="Space_BetweenEmptyMethodCallParentheses">0</PropertyValue>
	        <PropertyValue name="Space_BeforeSemicolonsInForStatement">0</PropertyValue>
	        <PropertyValue name="Space_BeforeComma">0</PropertyValue>
	        <PropertyValue name="Space_AfterMethodCallName">0</PropertyValue>
	        <PropertyValue name="Space_AfterComma">1</PropertyValue>
	        <PropertyValue name="Space_BeforeBasesColon">1</PropertyValue>
	        <PropertyValue name="Space_AfterMethodDeclarationName">0</PropertyValue>
	        <PropertyValue name="Space_AfterDot">0</PropertyValue>
	        <PropertyValue name="NewLines_Braces_Type">1</PropertyValue>
	        <PropertyValue name="Space_AfterLambdaArrow">1</PropertyValue>
	        <PropertyValue name="NewLines_Braces_LambdaExpressionBody">1</PropertyValue>
	        <PropertyValue name="Space_WithinSquares">0</PropertyValue>
	        <PropertyValue name="Space_BeforeLambdaArrow">1</PropertyValue>
	        <PropertyValue name="NewLines_Braces_AnonymousTypeInitializer">1</PropertyValue>
	        <PropertyValue name="Space_WithinCastParentheses">0</PropertyValue>
	        <PropertyValue name="Space_AfterSemicolonsInForStatement">1</PropertyValue>
	        <PropertyValue name="Indent_CaseContents">1</PropertyValue>
	        <PropertyValue name="Indent_FlushLabelsLeft">0</PropertyValue>
	        <PropertyValue name="Space_BetweenEmptySquares">0</PropertyValue>
	        <PropertyValue name="Space_BeforeOpenSquare">0</PropertyValue>
	        <PropertyValue name="Space_BeforeDot">0</PropertyValue>
	        <PropertyValue name="Indent_BlockContents">1</PropertyValue>
	      </ToolsOptionsSubCategory>
	    </ToolsOptionsCategory>
	  </ToolsOptions>
	</UserSettings>

It sucks that I still have to remember to load the settings for each project before making changes in that project, but at least I don't have to remember which individual settings to use for each project.

How do you handle this situation? Do you just live with the inconsistencies or is there an alternative way to deal with this issue? Are you using StyleCop (a.k.a. MS Source Analysis) or something like it to enforce some or all of the rules?

The Fluent Interfaces or DSLs Conundrum

Posted by Sergio on 2008-05-21

Maybe I'm just behind the curve on this one, but I don't understand the fascination with building internal DSLs (or the so-called fluent APIs) in C#. The argument is usually that they are expressive and readable but, since these are subjective assessments, I happen to disagree on both counts. They would need to bring some other values to the table to convince me to use them without being annoyed.

I think C# is not well suited for this task and maybe we should just stop trying to imitate what we see in other languages.

The idea that we can create classes named Is or Returns or With just rubs me the wrong way. At the present moment I hope this trend is just a fad. I'm willing to be proven wrong and suddenly "get it." Time will tell.

Take the following snippet using Rhino Mocks.

With.Mocks(mocks).Expecting(() =>
{
    Expect
	.Call(dependency.GetSomething("p1"))
	.IgnoreArguments()      
	.Repeat      
	.Once() 
	.Return("result");
    dependency.DoSomething();
})

Imagine yourself trying to setup this expectations. You know that when calling dependency.GetSomething("parameter") it should return "result". How would you discover that the With class is your starting point? Then look at the lambda code. I'd imagine your first reaction would be to look for a method in Expect that would take both the method call and the result. I'd say your first reaction is appropriate, after all this is still supposed to be C# code.

Maybe the desire behind these fluent interfaces is to make the API have a little more keyword wannabes at the expense of tolerating all the punctuation and ceremony that comes along.

In other languages this type of APIs are more popular because the language lends itself more adequately to this design. I'm not an Objective-C programmer but take a look at this line.

[expect call:[dependency getSomething:@"p1"], repeat:1, returns:@"result"];

Or in Ruby, probably leveraging the method_missing goodness behind the scenes:

dependency.expectCall.getSomething("p1", 
	:ignore_arguments => true, 
	:repeat => :once,
	:returns => "result"
	)

For a Objective-C or Ruby developer the above translations probably read more natural than the C# version for a C# developer.

I'm using Rhino Mocks as an example because it is fairly popular. I'm not trying to pick on it. Just to give another example of a fluent interface, recent versions of NUnit come with the Constraint Model for assertions:

Assert.That( ex3, Is.Not.SameAs( ex1 ) );

Again, classes, properties, and methods being used as quasi-operators, trying to blur the lines between language features and the custom API. But C# fights back and makes clear that it is not open for these kinds of extensions and throws a bunch of punctuation at you. To me this just doesn't feel fluent. It doesn't read like English nor like C#. It's more like some schizophrenic middle-of-the-road compromise.

It's possible that this desire to write fluent interfaces and DSLs becomes just a gateway to a more appropriate language like IronRuby or even Boo (to stay in the .Net universe.) Or, who knows, maybe C# changes to be more friendly to these designs. I will not be surprised if, in a few years, we look back at all these implementations and feel a little embarrassed for trying so hard to recreate an experience that is just not viable. Equally, I will not be surprised if I'm proved wrong, jump on the bandwagon, and regret having ever written this piece.

And the winner is... VB.NET ?!

Posted by Sergio on 2008-05-18

Every time I see an updated version of the TIOBE index it strikes me differently. Sometimes I'm surprised to see some programming languages in the TOP 20 that I didn't even know existed (happens all the time,) sometimes it's the realization of the languages on the rise like Ruby and Lua in recent years.

Take a look at this month's list.

1 Java 20.176%
 
2 C 15.292%
 
3 (Visual) Basic 10.782%
 
4 PHP 10.637%
 
5 C++ 10.484%
 
6 Perl 5.869%
 
7 Python 4.613%
 
8 C# 3.963%
 
9 Ruby 2.851%
 
10 Delphi 2.641%
 
11 JavaScript 2.411%
 
12 D 1.314%
 
13 SAS 0.738%
 
14 PL/SQL 0.625%
 
15 Pascal 0.498%
 
16 Lisp/Scheme 0.449%
 
17 Ada 0.431%
 
18 COBOL 0.411%
 
19 Lua 0.393%
 
20 FoxPro/xBase 0.385%
 

This month, although not new, what hit me was the state of the .Net languages. I'm definitely a C# guy. You'd have to tempt me with serious money to get me doing VB.Net again (IronRuby, on the other hand, would be a different story ;)

Although I'm not exactly surprised to see the .Net languages being dwarfed by other heavy hitters like Java and C, which enjoy a little more platform-independence, it's always an humbling effect seeing VB that far ahead of C#.

The interesting thing with this index is how it is built. It serves as a good thermometer to what kind of support you can expect to find on the Internet for that language. That's why it surprises me in relation to Visual Basic in particular.

I understand the index lumps together VB.NET, VB6, plain Basic, etc, but the non-Net versions of VB have been considered legacy for so long now that I tend to think VB.NET is indeed what is pushing Visual Basic to the top.

Maybe it's just because "Visual Basic" or "VB" as much easier search terms than "C#", "CSharp", "C-sharp", etc.

I've been reading about .Net online for almost 8 years now and C# has always seemed more prevalent than VB.NET in article, samples, documentation, and Open Source projects.

What about you? Anything interesting in this list? Is VB really the bomb?

Chicago ALT.NET - May 08 meeting summary

Posted by Sergio on 2008-05-15

Last night we had the monthly meeting of the Chicago ALT.NET group. After a few social/networking and group planning events, this was our first content-bearing event.

We had the pleasure of having Dan Sniderman come and talk about his experience with TFS and how we can build a Continuous Integration process with it. Dan talked about the different components and options in TFS and it was a very useful presentation, especially for me, because I'm going through the process of making CI a fundamental part of my client's workflow.

The discussion was not limited to TFS as it was constantly put in perspective against the other non-MS CI offerings. Knowing what TFS can do in comparison to the existing alternatives like SVN, TeamCity, CruiseControl.net, trac, JIRA, etc will enable me to assist the client choosing the most appropriate option for their team and infrastructure.

I'm very happy with the level of the discussions and knowledge sharing that we got in that meeting. It was not your average user group lecture. I think that is the direction we want our group to follow, not limiting our scope to MS branded products and eventually looking outside of the .Net boundaries as well.

Topics for our future meetings are up for voting, but it looks like we will soon be talking about NHibernate, IoC containers, distributed architectures, TDD, ORMs, rich JavaScript client libraries, etc.

If you want to learn more about the group and attend future meetings, check out our mailing list and our calendar (iCal).

Designing With Lambdas - Part IV

Posted by Sergio on 2008-05-08

My previous posts in this series revolved around using lambdas to encapsulate logic. In this post I'll show a different side of the lambdas, the expressions.

Lambda Expressions

We have already seen that lambdas can be used to create anonymous methods to be passed wherever a delegate is expected. That's not the end of the story, though.

Lambdas can also be used where an Expression<DelegateType> is expected. The difference is that the compiler will not resolve the lambda to an anonymous method. Instead the lambda will be converted to an expression tree, which is a way to describe the code in the lambda.

If you used LINQ to SQL for example, you have already been using lambdas that are converted to expressions. Expressions are what enable LINQ to SQL to convert a LINQ query like this:

from cust in Customers
  where cust.City == "London" 
  && cust.ContactTitle == "Sales Representative"
  select cust
into a SQL query like this:
SELECT 
	[t0].[CustomerID], [t0].[CompanyName], 
	[t0].[ContactName], [t0].[ContactTitle], 
	[t0].[Address], [t0].[City], [t0].[Region], 
	[t0].[PostalCode], [t0].[Country], 
	[t0].[Phone], [t0].[Fax]
FROM [Customers] AS [t0]
WHERE 
	([t0].[City] = "London") 
	AND ([t0].[ContactTitle] = "Sales Representative")

In particular, pay attention to how the where clause was converted from C# syntax to SQL syntax.

Yet another JSON converter

Let's illustrate how expressions can be used by creating some code to convert objects to JSON.

What I will try to produce here is a converter that let's me specify which properties of my object will be included in the JSON version of the object.

One way to accomplish this could be by simply passing a list of property names to a conversion function that would work some reflection magic and extract the properties into the JSON format.

string userJson = ConvertToJson(userObj, "Name", "Email", "Age");

The biggest problem here, in my opinion, is not the reflection activity behind the scene, it's those strings. If you change the name of any of the properties the compiler and the refactoring tools won't be able to help you updating those strings. You may end up with runtime errors.

With lambdas and expressions we can do better. Here's the syntax that I will build.

class Company               
{                   
	public string Name { get; set; }      
	public int CompanyID { get; set; }      
	public string Address { get; set; }     
	public bool PlatinumCustomer { get; set; }    
	public string InternalControlNumber { get; set; } 
}          

// object that we will convert
var acme = new Company {        
	Name = "ACME, Inc." ,       
	InternalControlNumber = "3X77-AC",  
	Address = "123 Main St, Anytown, ST", 
	PlatinumCustomer = true,      
	CompanyID = 789         
};                

//convert it but only copy a few properties
string json = ConvertToJson<Company>(acme,  
	c => c.Name,        
	c => c.CompanyID,     
	c => c.PlatinumCustomer);

The resulting JSON string, stored in the json variable will be:

{"Name":"ACME, Inc.", "CompanyID":789, "PlatinumCustomer":true}

Each of the lambdas passed in contain just one access to an existing property. As soon as you start typing this you'll already see the advantage of working with strongly-typed constructs like this. IntelliSense will automatically list the Company properties and methods once you type c.. Also, if you rename one of the properties, the IDE will offer to rename all references to that property, and the lambda will also be included in the renaming. Lastly, your code won't even compile if you make a typo.

The code for ConvertToJson will receive an array of expressions of type Expression<Func<T, object>>. This type looks complicated but if we think about it from the inside out, Func<T, object> is something you typically see in regular lambdas. It's a delegate type. As soon as we decorate that delegate type with an Expression< T > around it, the compiler will continue to accept the lambda syntax for anonymous methods but now the method never gets invoked, it will become an expression tree, which is then passed to the function. Here's the function.

public static string ConvertToJson<T>(                 
	T data,                            
	params Expression<Func<T, object>>[] properties)         
{                                
	int exportedFields = 0;                      
	StringBuilder json = new StringBuilder();                
	json.Append("{");                        
	foreach(var prop in properties)                    
	{                                                  
		string propName = null;                    
		object propVal = null;                   
                                 
		if(prop.Body.NodeType == ExpressionType.MemberAccess)          
		{                          
			PropertyInfo pi = 
				(PropertyInfo)((MemberExpression)prop.Body).Member;  
			propVal = pi.GetValue(data, null);             
			propName = pi.Name;                  
		}                          
		else if(prop.Body.NodeType == ExpressionType.Convert)          
		{                          
			UnaryExpression expr = (UnaryExpression)prop.Body;       
			PropertyInfo pi = 
				(PropertyInfo)((MemberExpression)expr.Operand).Member;
			propVal = pi.GetValue(data, null);             
			propName = pi.Name;                  
		}                          
		                           
		if(propName != null)                     
		{                          
			string stringVal = null;                 
			if(propVal == null) stringVal = "null";            
			else if(propVal is string) stringVal = "\"" + propVal + "\"";    
			else if(propVal is bool ||               
				propVal is byte ||               
				propVal is int ||                
				propVal is long ||               
				propVal is short)                
					stringVal = propVal.ToString().ToLower();  
                                 
			if(exportedFields > 0) json.Append(", ");         
			json.AppendFormat(@"""{0}"":{1}", propName, stringVal);      
			exportedFields++;                  
		}                          
	}                              
                                 
	json.Append("}");                        
	return json.ToString();                      
}