I see a lot of articles on the internet these days about ways to trim down your RSS subscriptions, how to manage your time to read through all your items, etc. My opinion on this is the complete opposite.
I say: subscribe to many RSS feeds. Leave most of them unread. Or set them as read after merely glancing at the article titles.
Most RSS feeds have crappy articles (insert a snappy joke about this one here) or, at least, articles not relevant to you. Most of the RSS feeds you're subscribed to will only have a small fraction of posts that are of any use to you. It's the case even with great sites like LifeHacker or DownloadSquad. It may be because you subscribed to the whole feed, instead of a tag-specific feed, or it maybe just because that's the way things are.
When you read a newspaper, you leave articles unread all the time. You skim through a page and only read the articles that look interesting. There are some pages you know you're not interested in at all, like the astrology and crosswords page, the obituary page, the sports page, the economy page, whatever. These items are effectively kept unread. It doesn't matter. You can just skim through your feed items and read the ones that look interesting, given their title or author. Leave the other ones unread.
What if you miss something interesting or important? Well, get over it. You're missing lots of interesting or important things all the time anyway. In this day and age, you've got to trust your judgement in filtering out information, and you've got to believe that if something is interesting or important enough, it will resurface in several other feeds you're also subscribed to. Hence the need to subscribe to many feeds.
What about the fact that, with technology, we should really have something that's better than the way we used to read newspapers? Well you have a better way already. First, you don't have to go outside to get the newspaper. Second, you don't have to pay for it (well, the price is bundled with your internet access). Third, you could be reading more targeted stuff by filtering your feeds with keywords and search queries. Yahoo Pipes and other similar services can help you with that if that's your thing, and you know you won't be interested in stuff that you don't know you're interested in yet (which is an interesting paradox). But at the end of the day, you still need to filter out some stuff.
This whole thing is really about being okay with leaving lots of unread stuff. Recently, there's been some hype about the "zen mailbox", where people tell you that it's okay to delete email or not reply to it. This is the same philosophy, applied to RSS feeds.
A common pattern in .NET is the “provider pattern“, where you have an abstraction for pulling data out of something (a database, a file, your ass, etc.), and one or several implementations of this interface (usually, one for each “something” you can pull data out of).
For this example, we’re going to get cookies (the biscuit, not the browser token, you sad nerd) from some “cookie provider”.
public class Cookie
{
public string Flavor { get; set; }
}
public interface ICookieProvider
{
Cookie ProvideCookie();
}
class Program
{
static void Main(string[] args)
{
ICookieProvider provider = GetCookieProvider();
Cookie cookie = provider.ProvideCookie();
while (cookie != null)
{
Console.WriteLine("Got {0} flavored cookie.", cookie.Flavor);
}
Console.WriteLine("No more cookies.");
}
}
A common way of setting which provider to use is to set this in the configuration file. Let’s create a custom configuration section for this (you need to add System.Configuration as a reference to your project), with a “cookieProvider” element in it.
public class CookieFactoryConfigurationSection : ConfigurationSection
{
[ConfigurationProperty("cookieProvider", IsRequired = true)]
public CookieProviderConfigurationElement CookieProvider
{
get { return this["cookieProvider"] as CookieProviderConfigurationElement; }
set { this["cookieProvider"] = value; }
}
}
public class CookieProviderConfigurationElement : ConfigurationElement
{
[ConfigurationProperty("type", IsRequired = true)]
[TypeConverter(typeof(TypeNameConverter))]
[CallbackValidator(Type = typeof(CookieProviderConfigurationElement), CallbackMethodName = "ValidateProviderType")]
public Type Type
{
get { return this["type"] as Type; }
set { this["type"] = value; }
}
public static void ValidateProviderType(object type)
{
if (!typeof(ICookieProvider).IsAssignableFrom((Type)type))
{
throw new ConfigurationErrorsException("The cookie provider must implement the ICookieProvider interface.");
}
}
}
We should really use some static ConfigurationProperty members to index our element in the gets/sets, instead of plain strings, but it will do for this example. Also, note the use of the TypeConverter and CallbackValidator attributes, which are pretty neat to let the CLR do all the boring bits to get strongly typed values out of the configuration file. Last, note how we test whether the supplied type implements our interface. This small bit of code has been discussed on other blogs, and I believe this is the best method, until Microsoft decides to add a more straightforward method to System.Type.
Now we can specify the cookie provider in our configuration file:
And implement the GetCookieProvider method without worrying too much about validating arguments since the configuration API did that for us (it’s a required configuration element):
private static ICookieProvider GetCookieProvider()
{
var section = ConfigurationManager.GetSection("cookieFactory") as CookieFactoryConfigurationSection;
if (section == null)
throw new Exception("No cookie factory found!");
return (ICookieProvider)Activator.CreateInstance(section.CookieProvider.Type);
}
The implementation for the SimpleCookieProvider, used in the configuration file, is, well, simple. It just creates up to 10 cookies.
public class SimpleCookieProvider : ICookieProvider
{
private int mProvidedCookieCount = 0;
#region ICookieProvider Members
public Cookie ProvideCookie()
{
if (mProvidedCookieCount++ > 10)
return null;
return new Cookie() { Flavor = "simple" };
}
#endregion
}
We we run the program, we get the following output:
This is all fine, but what if we want to pass some custom (implementation specific) values to initialize our cookie provider? For example, I’d like to specify the maximum amount of cookies to produce, or the flavor for those cookies. Obviously, we can’t do the following:
The Initialize method will get very crowded as we create new providers like, for instance, a provider that will allocate a random number of cookies, picking flavors randomly out of an array of strings.
What would be nice would be to declare “freeform” attributes in the XML of the configuration file as such:
The options would be passed as a collection of name/value pairs, and each cookie provider would be free to do whatever he wants with those options. This is actually what the ProviderBase class does (from the System.Configuration.Provider namespace):
public abstract class ProviderBase
{
protected ProviderBase();
public virtual string Description { get; }
public virtual string Name { get; }
public virtual void Initialize(string name, NameValueCollection config);
}
It gets initialized with a name and a collection of name/value pairs.
We could replace our interface by an abstract class that inherits from ProviderBase, but that’s just too much overhead for our simple project. Let’s just refactor ICookieProvider and SimpleCookieProvider:
public interface ICookieProvider
{
void Initialize(NameValueCollection options);
Cookie ProvideCookie();
}
public class SimpleCookieProvider : ICookieProvider
{
private int mProvidedCookieCount = 0;
private int mMaxCookies = 10;
private string mFlavor = "simple";
#region ICookieProvider Members
public void Initialize(NameValueCollection options)
{
string maxCookiesSetting = options.Get("maxCookies");
if (maxCookiesSetting != null)
mMaxCookies = int.Parse(maxCookiesSetting);
string flavor = options.Get("flavor");
if (flavor != null)
mFlavor = flavor;
}
public Cookie ProvideCookie()
{
if (mProvidedCookieCount++ > mMaxCookies)
return null;
return new Cookie() { Flavor = mFlavor };
}
#endregion
}
Now when we run the program, we get a ConfigurationErrorsException because some unrecognized attributes were found in the configuration file. Getting them to be ignored and stored is easy enough, with the OnDeserializeUnrecognizedAttribute virtual method of the ConfigurationElement class:
public class CookieProviderConfigurationElement : ConfigurationElement
{
public NameValueCollection Options { get; private set; }
[ConfigurationProperty("type", IsRequired = true)]
[TypeConverter(typeof(TypeNameConverter))]
[CallbackValidator(Type = typeof(CookieProviderConfigurationElement), CallbackMethodName = "ValidateProviderType")]
public Type Type
{
get { return this["type"] as Type; }
set { this["type"] = value; }
}
public CookieProviderConfigurationElement()
{
Options = new NameValueCollection();
}
protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
{
Options.Add(name, value);
return true;
}
public static void ValidateProviderType(object type)
{
if (((Type)type).GetInterface(typeof(ICookieProvider).Name) == null)
{
throw new ConfigurationErrorsException("The cookie provider must implement the ICookieProvider interface.");
}
}
}
Let’s not forget to actually call the Initialize method:
private static ICookieProvider GetCookieProvider()
{
var section = ConfigurationManager.GetSection("cookieFactory") as CookieFactoryConfigurationSection;
if (section == null)
throw new Exception("No cookie factory found!");
var provider = (ICookieProvider)Activator.CreateInstance(section.CookieProvider.Type);
provider.Initialize(section.CookieProvider.Options);
return provider;
}
Now when we run the program again, we have the expected output:
This is all fine and dandy for simple programs and simple requirements, but it doesn’t work for more elaborate scenarii (yes, I’m the kind of guy that says “scenarii” instead of “scenarios”). For example, what if we had an “Options” dialog that allowed the user to modify the configuration of the program?
Let’s simulate this by hard-coding a change in the configuration:
private static void SimulateConfigurationChange()
{
var configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var section = configuration.GetSection("cookieFactory") as CookieFactoryConfigurationSection;
section.CookieProvider.Options["maxCookies"] = "6";
configuration.Save();
}
This method is called at the end of the program. When we run it, the configuration file isn’t changed.
What’s wrong? We’ll get on that in part 2 of this series!
In MSBuild, you can specify inputs and outputs for target so that the target is skipped when the outputs are more recent than the inputs. However, you get a strange behaviour when you put a <CreateProperty> task inside such a target.
<TargetName=”DoStuffMaybe”Inputs=”input.txt”Outputs=”output.txt”><ErrorText=”We shouldn’t be there!”/><CreatePropertyValue=”oh my”Condition=””><OutputTaskParameter=”Value”PropertyName=”WhyIsThisCreated”/></CreateProperty></Target>
</Project>
This project creates two files, “input.txt” and “output.txt”. Then, the “DoStuffMaybe” target is tentatively run, but is skipped because “output.txt” is newer. We make super sure that this target won’t be run by adding an <Error> task in there.
But when you run this project, you get the following output:
Somehow, the <CreateProperty> task was processed, and the value of $(WhyIsThisCreated) was set to “oh my“!
I don’t really know what’s going on, but the solution to this problem is, as it is the case most of the time, to read the documentation. The <CreateProperty>page on MSDN informs us that another property is available on the task:
ValueSetByTask
Optional String output parameter.
Contains the same value as the Value parameter. Use this parameter only when you want to avoid having the output property set by MSBuild when it skips the enclosing target because the outputs are up-to-date.
If we replace TaskParameter=”Value” by TaskParameter=”ValueSetByTask” in the MSBuild project, we finally get the expected result:
I do almost all my development at home with Visual Studio Express. These products are wonderful and free. Well… granted, if they were not free, they would also be less wonderful too, probably. But they’re still great pieces of software, and I’m pretty sure they played a critical part in building the vibrant .NET community we have now. I wish Microsoft would also release a free “Express” version of Office, but I guess I can keep on dreaming for a while longer.
The Express versions of Visual Studio have of course less features than their “professional” counterparts. Some features, however, are present, but are just disabled by default. This is the case for the build configurations.
By default, you only get a couple of disabled combo-boxes, and you only know what’s supposed to be there if you’ve already worked with Visual Studio Professional. Visual Studio Express will switch between Debug and Release versions of your project depending on what you’re doing. For example, if you start the debugger by pressing F5, the “play” button, or choosing “Debug > Start Debugging“, it will switch to the Debug configuration. If you start the program without debugging by pressing Ctrl+F5 or choosing “Debug > Start Without Debugging“, it will switch to the Release configuration.
This is fine, but can be annoying at times, especially when you have inputs or outputs. For example, if you write a log file in the same directory as the executable, you’ll have to remember to open the correct one depending on whether you pressed F5 or Ctrl+F5. This can lead to situations where you’re looking for an error when there’s nothing wrong because you’re not looking in the correct directory!
Also, you might want more configurations than just Debug and Release. You might want completely different configurations. If you’ve worked with Visual Studio Professional, you may even be wondering what happened to the Configuration Manager in the Express versions.
To fix this, choose “Tools > Options“, and then check “Show all settings” on the bottom left corner of the dialog. You’ll get all the advanced options, including the “Projects and Solutions” category. Check the option called “Show advanced build configurations“.
Click OK, and look at those beautifully enabled combo-boxes!
Now you can set the current build configuration, and whether you start your project through the debugger or not won’t change the executable being launched.
Also, the Configuration Manager is back, and will let you create new configurations:
You will soon find that other parts of the UI have now more options related to build configurations, such as the Project Properties interface.
First, that's right, I said "cloud". In this day and age, you have to keep up with all the hype terms and buzzwords, otherwise you sound like you're from the 20th century.
Second, yes, here's anther blog about programming (mostly in .NET), even though there are thousands of those already. But Jeremy Miller, over at CodeBetter, posted about how I should really blog (well, not me specifically, but since I was reading, I'm pretty sure he was talking to me too):
I've been asked several times over the past month "Should I start a
blog? What if…?" The answer is yes, you should. Or more
accurately, if you're interested in blogging you shouldn't feel afraid
to blog.
He then goes on and gives some pretty sensible "Good", "Bad" and "Ugly" points about starting a blog, along with demystifying the most common excuses for not starting a blog… And guess what? Well, too bad now, here's mine!
Now, however, I made Jeff Atwood sad and angry, as I've committed the sin of meta-blogging, but I guess you get a free pass for the first post, what with the need to introduce yourself and all.
Well, enough ranting for now. I hope to see you again later!