Consider the following code, which fetches and parses some data (from a random gist on the web) into properties on an object:
public void Parse(string fileName)
{
var userAccounts = new Collection();
var html = new HtmlDocument();
html.Load(fileName);
var document = html.DocumentNode;
var users = document.QuerySelectorAll("user");
foreach (var userNode in users)
{
var userAccount = new UserAccount();
var node = userNode.ChildNodes["name"];
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
userAccount.Name = node.InnerText;
}
node = userNode.ChildNodes["company"];
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
userAccount.Company = node.InnerText;
}
node = userNode.ChildNodes["blog"];
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
userAccount.Blog = node.InnerText;
}
node = userNode.ChildNodes["email"];
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
userAccount.Email = node.InnerText;
}
node = userNode.ChildNodes["id"];
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
userAccount.Id = int.Parse(node.InnerText);
}
node = userNode.ChildNodes["followers-count"];
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
userAccount.Followers = int.Parse(node.InnerText);
}
userAccounts.Add(userAccount);
}
}
There's lots of duplicated code, and the first target for refactoring are the longest lines, which can be extracted into a method to check whether a child node is valid:
private static bool IsNodeValid(HtmlNode node)
{
return node != null && !string.IsNullOrEmpty(node.InnerText);
}
Better, but there's still scope to reduce duplication.
...
node = userNode.ChildNodes["email"];
if (IsNodeValid(node))
{
userAccount.Email = node.InnerText;
}
node = userNode.ChildNodes["id"];
if (IsNodeValid(node))
{
userAccount.Id = int.Parse(node.InnerText);
}
...
Ideally, the blocks of five lines would be refactored into a new method. Because we're accessing different properties of the userAccount, we can't pass them in directly, nor can we pass them in as references, as they're not variables. Also, some of the properies are ints, so we'd need two methods.
We can, however, pass in an action to the new method, which performs the assignment (the only unique code in the five lines):
private void CopyNodeData(HtmlNode userNode, string name, Action func)
{
var node = userNode.ChildNodes[name];
if (node != null && !string.IsNullOrEmpty(node.InnerText))
{
func(node.InnerText);
}
}
This now means each assignment can now take a single line:
CopyNodeData(userNode, "name", s => userAccount.Name = s); CopyNodeData(userNode, "company", s => userAccount.Company = s); CopyNodeData(userNode, "blog", s => userAccount.Blog = s); CopyNodeData(userNode, "email", s => userAccount.Email = s); CopyNodeData(userNode, "id", s => userAccount.Id = int.Parse(s)); CopyNodeData(userNode, "followers-count", s => userAccount.Followers = int.Parse(s));
The third parameter is a lambda that will be called only if the node is valid. We've removed lots of duplication, making the code more readable.
CSS is great and everything, but it isn't that programmery. Less, and the .NET port, .Less add some useful things, like variables, operations, functions and mixins.
The basic workflow in Visual Studio is to edit the .less file, run it through the parser in the post-compile step, and include the generated CSS output in your HTML head as normal. More on this later.
There's a bit of an art deciding when to use these features and when to use CSS properly, so I've been using them cautiously at first. Variables are great for colours, as you can give them readable names; I for one can't tell what colour #BAD455 is without seeing the output. Ah, it's a sludgy colour. I can call my variable 'sludge' and use it throughout my stylesheet.
Mixins are super handy for the HTML5 / CSS3 items with multiple browser prefixes:
This can then be used anywhere you want a box shadow:
Javascript and CSS minification is all the rage, and is quite simple to do in .NET, thanks to the YUI compressor for .NET. It can be found with NuGet, as YUICompressor.NET. The setup details are on codeplex.
The idea is that the .js and .css files are compressed as a post-build step, with the files to be compressed listed in YuiCompression.targets, which is an MSBuild script included in your main .csproj file, thus:
And in YuiCompression.targets:
Any files listed in the item group will be squished together and minified into a single .js and a .css file, which can then be included in your HTML.
It can be a nuisance trying to debug compressed Javascript / CSS in development, so in my master page, I conditionally include the originals for debugging, and the compressed file for release versions:
Also a nuisance is editing .Less files. With plain CSS, I would edit the file, save it, and press F5 in the browser. With .Less, the CSS file must be regenerated. Rebuilding the whole Visual Studio solution is so much slower, but fortunately unecessary. Phil Haack's T4 script rebuilds just the .Less file. The cunning bit is how, when run, the file marks itself as unsaved. T4 scripts are run when saved, so every time the file is saved, .Less generates the CSS files again.
Using that feature, you can open T4CSS.tt in Visual Studio along with the .less file you're editing, and leave it open. Now, when saving the .less file, instead of pressing Ctrl-S, press Ctrl-Shft-S, which is saves all open files. This will save the T4 script (thus regenerating the CSS), and the changes will appear when you refresh the browser. Once setup, the only change to the edit / save / view cycle is pressing Shift when saving.
I'm working on a domain model at the moment, and I'm struggling to name a thing. A piece of text data can be one of three types; a label, a code or a group. The (C#) class to represent this is simple
public class TextData
{
public string Data {get; set;}
public TypeOfData DataType {get; set;}
}
Only thing is, I dislike the name of the second property. I named it badly for emphasis, but there are two problems:
Firstly, it isn't a data type, because data type means int or double or string or other such thing. Secondly, just calling something a type makes it sound like a .NET Type, so it is automatically ambiguous when coding, even if it is in the domain model.
So if we can't call anything a ‘type’, how about a ‘sort’. As in, “what sort of data is it?” Fairly obviously, sort usually means to arrange things in sequential order. What about ‘class’? Ahem.
Thesaurus time. Classification? Too long; too pompous. Breed? To animalish. Category? Hmm. Not sure why not, other than it sounds too big for this purpose. Genre? Also too big. Genus? Species? Again, animals. Kind?
Kind. I like that. It doesn't mean anything else in code. DataKind. That could work. Well, perhaps it wouldn't on a dating website, as it would also be an attribute of a potential date. Well, for me it would. Wouldn't want to date anyone unkind.
What else is there? Ilk. That's a nice word. Ilk. Yes, I like ilk. It isn't ambiguous in any way. It definitely means what I think it does. I don't often hear it used, and when I do, it generally pertains to people (men of that ilk). It sounds a bit odd, but I think that's good. It will stand out as meaning the type of thing, the sort of thing, the class of thing, the kind of thing, but without the ambiguity.
So, I propose Ilk as the new industry standard for the name of an informal classification of things. It may not sit well with you now, but if we start using it regularly and it becomes ubiquitous, then it will sound no less out of place than dongle, widget, mash-up, tweet, blogosphere and other words of that ilk.
Oh alright, so not blogosphere.
[Lively discussion encouraged]
I got the following error message when trying to start a site on port 80 in IIS
Internet Information Services (IIS) Manager The process cannot access the file because it is being used by another process. (Exception from HRESULT: 0x80070020)
Following the instructions here, I:
netstat -aon | find ":80" from a command promptStrange Visual Studio 2010 error message today, with absolutely nothing on Google.
VsTextViewAdapter initialization failure: Trying to create a text view without an available text buffer, current state:Sited
The project is ASP.NET MVC 2.0, and any views that were open when the project was closed are being reopened, but nothing is being rendered, even in code view. Trying to open a C# file produced this error:
Internal error occurred. Additional information: ''.
Thanks for that. Pressing F5 to run the solution in debug mode just crashes VS without any error.
After trying a few other files and projects, I rebooted, and it was all fine.