It’s been a long time – New Year, small vacation, etc…
Getting back to the blog. By the recommendation of my colleagues I took the Framework
Design Guidelines book in the library. This is an interesting book. Unlike some other books where “evangelists” throw at you empty slogans about things they hardly understand, the guys that wrote this book seem to know very well what they are talking about. Even if you don’t agree with everything they say, the book provides an insight into the philosophy behind the .NET framework.
Scope of The Book
The subtitle of the book is “Conventions, Idioms, and Patterns for Reusable .NET libraries“. This is a little bit misleading. For the authors “reusable .NET libraries” means first and foremost the .NET framework. If you were to design another .NET framework, this would be a perfect book for you. In reality, the .NET framework is already there, and in many aspects it is quite different from the frameworks we, mere mortals, design:
- The .NET framework is very, very big
- It is designed for the audience of tens if not hundreds of thousands of developers
- It has a release cycle measured in years
- It is reviewed by the best specialists in the industry
- It has hundreds if not thousands of beta testers
- It is Microsoft. This carries a lot of weight. If Microsoft says that there is no data structure but array, and insists on calling that “list”, this has a good chance of becoming a new standard. After all, if G-d wanted us to use trees, He would put a tree class in the framework. 🙂
p 5: Backward compatibility is not discussed in detail in this book. This is a shame. Backward compatibility is one of the most difficult subjects in framework design.
Framework Design Fundamentals
p 13: Frameworks must be designed starting from a set of usage scenarios and code samples implementing these scenarios. I totally agree. I’ve seen too many “ad hoc” APIs, that were very difficult, sometimes even impossible to use. If the authors thought about use cases first, these APIs would look much better.
p 17: Usability Studies. Before making your API public, the authors suggest to give it a test drive: take a number of average developers not familiar with the API, give them the documentation and ask them to program a simple task. This is wonderful idea, albeit I don’t see how to effectively apply it on a scale much smaller than .NET framework. If I have a “local” framework that serves 15-20, or even 50 overworked developers, the logistics become problematic. You need to finish you work, write all the documentation, then find enough volunteers to do the study, develop a technique to interpret the results, and possibly do another iteration of design, coding and documentation. Good in theory, too much trouble for a small framework.
As a side note, they admit Microsoft did not do usability studies for the
System.IO namespace, and it turned out somewhat problematic. The stream classes seem to be a particularly tough nut to crack. For whatever reason, stream classes are a weak point not only in .NET, but also in C++, and in Java (of course, this is only my personal opinion; hey, this is my blog after all :-)).
p 24: Naming. The simplest, but also often missed opportunity for making frameworks self-documenting is to reserve simple … names for types that developers … instantiate in the most common scenarios. Framework designers often “burn” the best names for less commonly used types, with which most users do not have to be concerned.
So true, so true.
Further on that on p 54: Another important consideration is that the most easily recognizable names should be used for most commonly used types, even if the name fits some other type better in the purely technical sense, For example, a type used … to submit print jobs to print queue should be named
Printer, rather than
p 26: DO involve user education experts early in the design process. User education what?! I am not sure our department even has those. User education experts is not something I can “involve”. Even if I manage to find one, he probably will be too busy to deal with my stuff. In other words, this recommendation is good only for a big framework.
p 28: Avoid many abstractions in mainline scenario APIs. While discussing this, the authors scoff at the Object-Oriented Programming, accusing it of making too many abstractions. I don’t think they are doing OOP justice. Having too many abstractions is not a product of the OOP per se, but a product of the violation of the KISS principle. One can produce an overengineered system with or without OOP. As Kent Beck puts it, we want to build the simplest thing that can possibly work (i.e. satisfy all the requirements), but not simpler. In the crusade against complexity, the last part is often forgotten, and “too simple” implementations turn out to be too rigid and difficult to maintain.
p 39: Capitalization and spelling for common compound words. The authors go to great lengths in discussing capitalization rules. While this is kinda boring, I guess it is a necessary evil. Having all identifiers to follow a common convention is a Good Thing. The problem is, the rules use the term “word”, and for some compound constructs it is not entirely obvious what is a “word”. In fact, it is not obvious to the point that they had to make a table for difficult situations. And yet, this table is still confusing. I could never understand why “hashtable” is one word, whereas “white space” are two words. Here, the spell checker agrees with me: it says there is no such thing as “hashtable” 🙂
p 44: Do not use abbreviations. This looks kinda funny alongside a table that lists “
SByte” and “
ushort“. Why are they calling me short?! 🙂
p 50: Do not use organizational hierarchies as the basis for names … because group names within corporations tend to be short-lived. It’s a very smart thing to say. Furthermore, even names of the corporations themselves change, e.g. when the corporations are bought or merged. From the other hand, it is sometimes not clear what to use instead of the organizational name.
p 62: Consider giving a property the same name as its type. This means name collision, and it raises an internal protest in me. From the other hand, sometimes the type name is the best name for the property.
p 63: Do use two parameters “sender” and “e” in event handlers. The sender parameter is typically of type object, even if it is possible to employ a more specific type. The pattern is used consistently across the framework. Unfortunately, the authors don’t care to give any reasons for this statement. Why would I want to use object when I know the type? Why would I want to pass an empty structure when there are no any arguments? Why if I want to pass a single argument I have to package it in a structure? This is one of the things the continues to puzzle me. BTW, what is “args” in “EventArgs” anyway? Didn’t they say not to use abbreviations and contractions?
p 64: Do not use a prefix for field names. For example do not use “g_” or “s_” to distinguish static versus non-static fields. Why not, may I ask? Prefix “_” works perfectly fine for fields, and I don’t see anything wrong with it. It particularly helps in constructors, when I need to assign parameter to a field. It also helps with property names. If I have a field
something and corresponding property
Something they would differ only by case. Weren’t we told it’s a bad thing?
p 66: This concludes 33 pages of naming guidelines, many of them just in the form of decrees (“do this”) without explanations. That’s a lot of guidelines. From the other hand, naming is important, especially for public stuff, since this is what the users will see.
p 69: On the flip side, sometimes types do end up being dumping grounds for various loosely related functions. The .NET Framework offers several types like this, such as
Application. This is a very honest and very unexpected passage coming from a Microsoft book. My respect to the authors. This actually made me to look who is the publisher. Naturally, it was not Microsoft Press :-). The book is published by Addison-Wesley.
p 70: Contrary to popular belief, the main purpose of namespaces is not to help in resolving naming conflicts. No kidding?! Is it really a popular belief? I hope not.
p 71: One of the best features of Visual Studio is Intellisense… The benefit of this feature is inversely proportional to the number of options. This is may be true, but I somewhat fear the advent of “design for Intellisense”paradigm. I am not entirely convinced it will produce a higher quality, easy to maintain software. Charles Petzold echoes some of these doubts in his article: “does Visual Studio rot the mind“. I do not 100% agree with everything he says, but there is definitely something to it.
p 72: Prior to C# 2.0, distinguishing the to types (same namespace, same type name, different assemblies) was impossible. However, with C# 2.0 it is now possible using the new extern aliases and namespace qualifier features. Using what?! To my astonishment I have no idea what he is talking about. Probably, because I never had such a conflict between two types. I will have to look that up.
p 75: Value types that can be changed can be confusing to many users. Therefore, value types should be immutable. Hm… I like this logic. Reference types that can be changed also could be confusing to many users, especially in a multi-threaded applications. Therefore, reference types should be immutable. 🙂 In fact, when I think about it, the C# language can be confusing to many users…