System.TimeZone2 Naming ... and related design guidelines
There is an interesting discussion on the BCL blog about a new BCL type called TimeZone2. Just take a look at the comments below the System.TimeZone2 Starter Guide post. The new type supersedes an existing type called TimeZone (which is obsolete now).
Lots of people are not thrilled with the “2” suffix. I am responsible for the guidelines (excerpt below), and so I thought I would try to provide some context:
· Some comments suggest that the BCL team just take a breaking change, i.e. remove the old type and add a new one with the same name. This is not an option for such a widely used framework. We basically have a policy against doing any intentional breaking changes. In other words, this is not negotiable :-)
· Some comments suggested using a new namespace, e.g. System.Globablization.TimeZone. This would cause all sorts of problems. The main one is that most source files import System namespace and this approach would mean that most source files have to fully qualify the new TimeZone (otherwise you would get type name ambiguity). I don’t like fully qualifying core types when I program and usability studies we conducted have shown that I am not alone. There are other issues related to the difficulty in searching for documentation on such duplicated types, referring to such types in books and in speech, etc.
· Using numeric suffixes is the last resort thing. If you have a “good name” that does not include a numeric suffix, you should use it. The problem is that sometimes all reasonable names are already taken, and that’s when the guideline is applicable. It’s what we call the best out of many bad alternatives.
Having said that, I would love the BCL team to find a new “good name” for the type. If you have a great name, post it to my or the BCL blog.
And for reference, here is the excerpt from the design guidelines:
Naming New Versions of Existing APIs.
Sometimes a new feature cannot be added to an existing type even though the type’s name implies that it is the best place for the new feature. In such case a new type needs to be added, often leaving the framework designer with a difficult task of finding a good new name for the new type. Similarly, often an existing member cannot be extended or overloaded to provide additional functionality and a member with a new name needs to be added. The following guidelines describe how to choose names for new types and members that supersede or replace existing types or members.
þ Do use a name similar to the old API when creating new versions of an existing API.
This helps to highlight the relationship between the APIs.
class AppDomain {
[Obsolete("AppDomain.SetCachePath has been deprecated. Please use AppDomainSetup.CachePath instead.")]
public void SetCachePath(String path) { /* … */ }
}
class AppDomainSetup {
public string CachePath { get { /* … */ }; set { /* … */ }; }
}
þ Do prefer adding a suffix rather than a prefix, in order to indicate a new version of an existing API.
This will assist discovery when browsing documentation, or using Intellisense. The old version of the API will be organized close to the new APIs as most browsers and the Intellisense show identifiers in alphabetical order.
þ Consider using a brand new, but meaningful identifier, instead of adding a suffix or a prefix.
þ Do use a numeric suffix to indicate a new version of an existing API, if the existing name of the API is the only name that makes sense (i.e. it is an industry standard), and adding any meaningful suffix (or changing the name) is not an appropriate option.
// old API
[Obsolete(“This type is obsolete. Please use the new version of the same class, X509Certificate2.”)]
public class X509Certificate { /* … */ }
// new API
public class X509Certificate2 { /* … */ }
Comments
Anonymous
October 06, 2006
Yeah.. Krzysztof have finally blogged about the controversal naming guidelines around TimeZone2! CheckAnonymous
October 06, 2006
How about TimeZoneRegion?Anonymous
October 06, 2006
Right now, there is no easy way to convert a time from one arbitrary timezone to another arbitrary timezoneAnonymous
October 07, 2006
The comment has been removedAnonymous
October 07, 2006
Totally cheap. .NET has jumped the shark. I hate the new name.Anonymous
October 07, 2006
Since Kathy's article mentions a relationship to the new Vista API and looking at her example #4, TimeZoneInformation sounds like a feasible alternative to me.However, Information is probably one of your black-listed suffixes, isn't it?Anonymous
October 09, 2006
I'm one of the people who wrote a comment on making it a breaking change.I don't argue that making a breaking change will hurt some people, but I think this is an investment in the framework in the long run. If we look ahead 10 years, will .NET be littered with TimeZone9 and X509Certificate6? Will we still want to use it?You say that you cannot introduce breaking changes due to policy, yet .NET 2.0 introduced many breaking changes? So has the policy changed - are you saying that there won't be a single breaking change in .NET 3.0?I think you should have the courage to realize that this /should/ be a breaking change, and that you will be better off taking the hit now, than letting developers suffer for it in the many years to come.Anonymous
October 09, 2006
If Microsoft are going to choose backwards compatibility over a clear sensible evolving API we are going to be in the same scenario as Win32 is now within a few years.I'd go with giving the new class the TimeZone name and moving the old one to a .Obsolete namespace (for 1 version only) and adding the Obsolete attribute to it.The VS 200x project upgrade wizard should detect references to the original TimeZone class and switch them to System.Globalization.Obsolete.If Microsoft aren't prepared to break the underlying API between major revisions .NET is going be become a mess real quick.Where they want to support an old version of a class for some time then an old-API wrapper round the replacement class might also be an option.[)amienAnonymous
October 09, 2006
We recognize the problem of frameworks deteriorating over time and we look for ways to stop or reverse this process – but without resorting to breaking changes. For example, in 2.0 we added type forwarders which we plan to use to fix some of the layering/dependency issues. We are also thinking about technologies that would allow us to fix naming and design issues without resorting to breaking changes. Breaking changes are just too disruptive for many projects/customers and they almost never add enough value to be worth the pain. There are cases where we feel like the benefits outweigh the costs (for example changes required to fix security issues) and we do approve limited breaking changes in such cases. But, I would assert naming changes for hygiene reasons can never provide enough value to offset their cost. This is especially true in Orcas. Orcas is an in-place (not Side-by-Side) update to the .NET Framework. See the following blog describing more detail: http://blogs.msdn.com/somasegar/archive/2006/05/18/601354.aspx. Changing TimeZone APIs in Orcas would amount to breaking applications in a service pack. This is a big no-no.Anonymous
October 10, 2006
Hi Krzysztof,I've a name suggestion, what about calling the new type "TimeRegion"CheersAnonymous
October 10, 2006
I noticed a good debate going on the BCL blog (and now Krzysztof Cwalina’s blog) about the naming ofAnonymous
October 10, 2006
The comment has been removedAnonymous
October 10, 2006
Ever since Kathy Kam announced on her weblog that a new type named TimeZone2 will be introduced intoAnonymous
October 10, 2006
Diego and Henry, I forwarded the suggestions to the BCL team. I actually talked to Kathy and she pointed me to the following blog which describes tradeoffs related to many of the names people suggested. See http://blogs.msdn.com/kathykam/archive/2006/10/06/Naming-Guideline-Discussion.aspx Adam, we are not changing version number in Orcas. This is basically the distinction between in-place and SxS. Also, even if we were doing a SxS release, it is a big deal for many people when they recompile and find a ton of errors. Migration tools cannot migrate everything. Also, there are various publisher policies which by default run applications on the new SxS release. Anyway, this whole compatibility discussion is probably a good topic for a blog post. I will ask around maybe somebody has already written on this, if not, I will try to write something.Anonymous
October 10, 2006
When I read the design guideline, it says use numeric suffix "if the existing name of the API is the only name that makes sense". But "TimeZone" isn't the only name that makes sense - there are many names that make sense... You could name it TimeZoneInfo as suggested in Kathys blog comments. You could name it after the reason you chose to create the new class - for instance if the main purpose was conversions it could be named ConvertibleTimeZone. So by your own admission you cannot apply this rule, and as such it must not be named TimeZone2... yesss! SCORE! ;-)Anonymous
October 10, 2006
Dudes, TimeZone2 is an attrocious name for a class. We've been through this before with COM and it's been a nightmare. Names need to be descriptive. Including a version number describes nothing about what the class does. If the new class cannot replace the old TimeZone then it should have a significant name that explains why it's different. Ex: DynamicTimeZone, WorldTimeZone etc. There's nothing wrong with breaking the 3.0 codebase at this time. It's still very far from release.Anonymous
October 11, 2006
I'm going to add my 2 cents in as well and say "Bad BCL team! Bad!" You can use all kinds of logic to say why TimeZone2 should be used. But when it comes right down to it, its still stupid. How does the quote go? "Logic is nothing more than a way to err with confidence."Anonymous
October 11, 2006
Micael and urig, I will pass your proposal to Kathy. She owns TimeZone naming.Anonymous
October 11, 2006
Dear Lord! Please, please, please don't do this to the BCL. Think of a different name, please! Your customers obviously cannot stand the appending 2 to the class name. Please don't do this, please use a different name. I beg you.Anonymous
October 17, 2006
> I don’t like fully qualifying core types when I program and usability studies we conducted have shown that I am not alone. using System; using TimeZone = System.Globablization.TimeZone; Done !Anonymous
October 17, 2006
I have to agree with the comments on adding a "2" suffix is a bad decision. Especially the comments by Micael Baerens are interesting. There's a number of other suggestions for names. The in-place installation is, however, an issue and this just adds to the arguments that .NET 3.0 should not be named .NET - rather .NET 2.1 (or 2.5) for what it is (.NET 2.0 with WinFX). Releasing the new version of the BCL as a side by side installation would allow you to make the breaking change now and use the "obsolete" features to inform developers about the new class. Already mentioned in other comments, the .NET 2.0 framework made several changes (some breaking). The changes to the Xslt namespace is a good example. The addition of compiled transformations forced a lot of people to update their code. Were the developers angry with this decision? no. Were the developers positive towards the investment Microsoft made in the BLCs? definately yes. It is extremely positive that Microsoft shows more transparency, allowing us - the developers - to comment on the decisions. We're hoping it makes a difference (hint hint) :-)Anonymous
October 18, 2006
I agree that a way to rename a class without breaking versioning would be nice. I've thought about this before, and the only con to it would be possible confusion in the documentation. If somebody looks up System.TimeZone in the help file and finds a listing for a completely different class that could be a problem, but not an unsolvable problem. So in case you're considering a feature like this, count me in as a supporter. I don't see how we can get this in time to solve the TimeZone/TimeZone2 problem (it'll have to be a major version update to support the new versioning capabilities). But still, it'd be nice to think that someday after TimeZone has been obsoleted for a while we can rename TimeZone2 to TimeZone and TimeZone to _OBSOLETE_TimeZone without making any binary breaking changes. I'm not entirely sure how Reflection would work with type-renaming (I'm not sure what it does with type-forwarding), but if you have a way to see what version of a library an assembly was compiled against then I'm sure there's a solution that would work.Anonymous
November 08, 2006
Having built my own TimeZone class for a very large international law firm (because the System.TimeZone class is ridiculously short-sighted), I have done a lot of research about time zones and daylight saving time around the world and am very interested to see how this plays out. I've been reading a lot of comments in several blogs about the TimeZone2 proposal. This is my take on the whole thing.
- TimeZone2 should not be based on the Vista "dynamic/historic timezone API", it should contain all the logic/data to compute this independent of the OS. This is so much easier for the developer, less things to think about and consider.
- TimeZone is a broken, almost useless class. The ideal recourse is to replace it - it is already broken. That said, if you are adamant about not replacing it, the new name should describe a class which clearly indicates that it is a replacement and therefore I am ok with the TimeZone2 name.
- Define interfaces so we have more flexibility... such as IDateTime and ITimeZone.
- Also, I don't like this: TimeZone2.FindSystemTimeZoneById(“Hawaiian Standard Time”); I would like all the time zones be listed, like the Color class lists many colors. Easier discoverability, strongly typed (no misspelling bugs), less frustration and time wasted looking things up on msdn or wherever.
- May I suggest an instantiation of a TimeZone2 object have the methods: ToLocalTime(DateTime utcDateTime) ToUniversalTime(DateTime localDateTime) but still maintain the "ConvertTime" static method. I named my static method "ToOtherTimeZone", but I like "ConvertTime" as well. Last but not least. I am very happy you guys are working on this TimeZone thing. The framework certainly needs it! Cheers, Jules
Anonymous
November 09, 2006
Jules, Thanks for the very detailed feedback. I have passed it to the team working on TimeZone2.Anonymous
November 30, 2006
Hey Krzysztof. Did you thought about different solution? Maybe your should separate TimeZone class as a container and a manager of TimeZones (all that static methods and calculating stuff). I didn't dig enought deep into the problem, but, perhaps, you could implement all time management features in a static (?) class named (for example) "Clock" (that would be really a good name) or "Time" and have a stupid TimeZone container (maybe even keep the old TimeZone class, or create a base class to improve compartability) . In that case, that would not be that important how this container would be called. The usage pattern will be something like this: Clock.GetTimeZone("name").IsDayLightSavingTime() . And the method could delegate the functionality back in the clock class via internal methods. I agree, from the point of OOP this is not the best thing to do, but from the point of usability, maybe it's the thing to consider ? p.s: just finished reading your book (design guidelines) a couple of weeks ago, and want to say my "thanks". Great one.Anonymous
February 12, 2007
為什麼推薦 ? Krzysztof Cwalina 是 .NET Framework API Design Team 的 Program Manager, 他也寫了 一本 Framework DesignAnonymous
March 09, 2007
I think a lot of commenters here are simply ignoring an important part of what krzystof is saying: There is no new version number in .net 3.0 or 3.5 for assemblies that already existed in 2.0. Therefore, breaking changes are absolutely not an option, this is not a mere matter of preference. Consider what a breaking change would mean. Among other things it would bring library developers in an impossible situation. Once I update my libraries to the new version of the .NET assemblies, they are not going to work in older versions. Worse, strong naming won't prevent this error because the version numbers did not change. The effects of such a decision would be simply unacceptable to any library developer (and cause problems for application developers too). We would end up having to query the installed framework version during installation (adding the requirement of an installation routine, which is unnatural for libraries), and this is still not robust, because the framework could get updated afterwards. This would be ridiculous. The other option would be to increase the version number. Thanks, but no thanks. Migrating build scripts and delivering seperate library versions for 1.1/2.0 was painful enough (not everybody is building their solutions solely via VS). We definately don't want this only because of some obscure class most people have not even noticed before. Once we accept this, there are still a few things that I'm uncomfortable with. Krzystof, you seem to think that your solution would still be the best one even if the version numbers would increase to a new major number.
- You mention the possible use of publisher policies. This is technically correct, but this raises the following question: Why do we have to struggle with the unforgivingness of strong naming and still do not get to depend on it? I mean, doesn't that give us the worst of both worlds - the missing robustness of dynamic programming AND the complicated build scenarios of statically typed languages? Arguably, in this case it could be better to drop the static checking altogether and depend solely on unit tests for robustness.
- If we ignore the publisher policy problem for a second, I'd strongly agree with the posters arguing for a breaking change in case of a major update.
- I would feel better about this decision if you would consider renamimg TimeZone2 back to TimeZone with the next major update of the respective assemblies. After all, once I have completely migrated to TimeZone2 and removed every reference to the old TimeZone, renaming TimeZone2 seems pretty painless (hit the obsolete message, search&replace in files). And aliases are always a possibility. (Although I have to say that this would be much easier if i had a project/solution-wide way of defining aliases, having to put a "using" in every code file is a pain. Especially if I have to decorate them with #if's. There are still moments when I miss those old #includes's ;-)) Stefan
- Anonymous
May 02, 2007
The comment has been removed - Anonymous
May 03, 2007
The comment has been removed - Anonymous
March 27, 2008
Probably far too late for this. But couldn't most of this been handled with a "TimeZoneConverter", "TimeZoneManager" or using Extension methods?