On the inadequacy of language

Published by marco on in Quotes

“He knows that there are in the soul tints more bewildering, more numberless, and more nameless than the colours of an autumn forest… Yet he seriously believes that these things can every one of them, in all their tones and semitones, in all their blends and unions, be accurately represented by an arbitrary system of grunts and squeals. He believes that an ordinary civilized stockbroker can really produce out of his own inside noises which denote all the mysteries of memory and all the agonies of desire.”
Words by G.K. Chesterton (The Language Log)

The first comment in the post includes a similar quote from Flaubert:

“Language is a cracked kettle on which we beat out tunes for bears to dance to, while all the time we long to move the stars to pity.”

5 days Ago

YouTube UX Suggestions 2015

Published by marco on in Design

I harshed on the YouTube UX in a recent article about GrooveShark. I figured I would take a few screenshots and explain exactly what I am trying to do with YouTube and why it feels so awkward.

Use Case

The user wants to watch vides in a list that he has not yet watched.

 'Mark as unwatched' would be nice

It is not immediately obvious how or even if the user can mark a video as “unwatched” so that the little sash is no longer shown across the video in a list. As it stands, the sash is pretty much useless because the video almost always autoplays before the user can click “watch later”.

Use Case

The user would like to manipulate multiple videos in the list at once.

 No multi-select actions in list view

Also, the lists are really sensitive to clicks and default to launching a video with every missed pixel—which marks the video as “watched” (see above).

 List view really wants to play videos

In contrast, GrooveShark[1] has relatively intuitive support—nothing fancy—for manipulating multiple media items. Clicking the song selects it by default, rather than playing it. Only a click on the play button at the front of the row actually plays the song.

 Copy/move multiple items in GrooveShark

GrooveShark also has the notion of a “queue”, which is a kind of ad-hoc list to which media items are added for playing. Food for thought.

Use Case

The user has already-watched videos in a list and wishes to upvote/downvote a video.

 No video ratings in list view

Rating multiple videos at once, up or down, would complete the UX.

Use Case

The user would like to move or copy a video to another list from the list view.

 'Move' and 'copy' are missing in list view

This is currently only possible from the video player, which necessitates playing the video (again) and jumping back and forth between the list view and the player.

Here’s what moving a single song looks like in GrooveShark.

 Copy/move single item in GrooveShark

Use Case

The user has already watched videos in a list and wishes to upvote/downvote or move or copy the video to another list.

There is no good way to do this from the list. Instead, the user has to navigate to the video, auto-playing it and clicking the “Add” dropdown multiple times until the video has been added to the new list and removed from the “Watch later” list.

Use Case

The user is watching the videos in a list and wishes to organize them as he watches subsequent videos in the list.

 No commands for play list when watching videos

In order to add a video to another list (e.g. “favorite Comedy” or “Suggestions for wife”), the user must click that video to start it again or open the list in another window. None of these options are as convenient as just making list commands available from the video player, so the user is not forced to leave the context of the currently playing video.

Use Case

The user wants to move or copy a video to another list.

 Management dropdown on video page

The dropdown gets the job done, but it’s not a pleasant user experience. Instead, to move a video, the user must click multiple times, instead of just twice (to remove the video from the current list and to add it to the other list).

Use Case

The user wants to, well, do anything but watch videos in the YouTube app for Samsung SmartTVs. Some stuff that would be nice:

  • Upvote/downvote
  • Add to “watch later” / build an ad-hoc queue of videos to watch
  • Move/copy video to list

The range of functionality doesn’t have to be as wide as for the desktop-browser application, but basic commands like upvote, downvote or watch later/add to list should easily be possible, even given the limited input of a TV remote control.

Use Case

The user wants to find a video in a longer list on the Samsung SmartTV YouTube app.

The YouTube app doesn’t make it very easy to find a video either. The user can only move forward in the list, but cannot wrap around to the end of the list from the beginning or vice/versa. This is really tedious when you want to watch a movie that you just added to the end of a longer list.

Some way of filtering would be most welcome, but being able to cycle backwards would be very useful for getting to the most recent content.

[1] And also Google Play, which I’ve recently discovered has quite a good UX for multiple-object selection and manipulation.

Grooveshark: A lesson in why we can’t have nice things

Published by marco on in Finance & Economy

Grooveshark is no more.

Why should we lament this? They were, after all, a company that delivered music without heeding copyrights and without recompensing the artists that wrote the music. Once you read more about their business model, one could only say that they operated in a gray area if one squinted really hard. Once you learned how they delivered what they delivered, you were amazed that they lasted as long as they did.

But let’s take a step back and examine what else they provided and why it might be OK to lament their passing. What follows is a bit of rant—no surprise there—and an exploration of what we’re actually talking about when we talk about music or films or TV shows or books. We’re so accustomed to the only system for access to culture being one of direct remuneration to license-holders, piecemeal for each bit of culture to which you’d like access

Is this really the only way?

The Grooveshark Service

What did Grooveshark do?

  • They had almost everything you ever searched for—and lots of stuff you never knew existed. Their collection was truly enormous: The only things I would have trouble finding were some very-local Swiss-jazz artists
  • They apparently also worked the same from every country instead of throwing up region-specific restrictions for every other song—or just not returning results not licensed in the country from which you searched
  • The search was great, showing a lot of cross-connections and opening you up to so many new artists and music
  • Their UI—old and new—was intuitive and provided a tight, complete set of features. You could build your own playlists as well as listen to other people’s playlists as “radios”.
  • Music played cleanly and well and reliably

So the service was exactly what you’d be looking for in a media service. Hell, it would have been a great service if it showed movies or TV shows, too. The only part missing was that Grooveshark didn’t come up with a way of directly remunerating the artists—and more importantly, their publishers.

Just to be crystal clear: the service was technically correct, but it didn’t play by the current rules for media distribution, so it operated in a gray-going-on-black area. Why express this so cagily? Because it’s hard to imagine that, even as soon as 10 years, we won’t be accessing media through something very like GrooveShark.

We already get access to all of the crappy music that we haven’t personally chosen whenever we turn on a radio. If you want to be able to choose what you listen to, though, instead of just listening to what’s shovel-fed to you by your betters, you’ll have to cough up a lot of cash and put a lot of personal time into building your collection. Either that, or listen to whatever’s on the radio. Which is probably commercials.

Since the owners of the music weren’t interested in unsnarling the knot of remuneration to myriad artists, they just shut it down and removed the service from existence.

In its stead, we were told to go to one of the bigger providers, like Spotify or Google Music.

Fine. No problem. Let’s see what those have to offer.


  • No web client. You have to download and install it. Ok, it turns out that there is a web client, but it’s not at-all well-linked from their homepage because they’d much rather you downloaded the executable so that they can set up shop in your startup-applications list and phone home about everything you’re doing. I’m not, so far, impressed with the legal way of doing things.
  • Good selection so far; didn’t find some stuff I had on Grooveshark, though
  • Available in a free version for a month
  • Free version has commercials, but not too often so far; OK, in Switzerland, it’s basically the same two commercials.
  • You can test the premium version for 30 days
  • Premium shuts off the ads, but costs 2.5 times as much as GrooveShark
  • The $.99 for 3 months offer is only available to U.S. subscribers

I played a couple of albums with Spotify, but didn’t like the dark-only UI and didn’t like that I couldn’t view my play history (or couldn’t find it), so I moved on to Google Play to see how things were over there.

Google Play

  • The free version lets you upload your own music from iTunes, but not browse music like GrooveShark
  • You can try premium for 60 days; this feels much more like GrooveShark
  • The UI is quite nice and very comparable to GrooveShark. Hey, YouTube, could you please, for the love of God, just walk down the hall and steal the GooglePlay UI? Pretty please? It’s kind of what we’ve all wanted for YouTube.
  • It also costs 2.5 times as much as GrooveShark
  • The selection is quite good, but the search is a bit dodgy—I know, right?

I signed up and was in quite quickly. The UI is fluid, intuitive and pretty. So far, so good.

I search for an album that I’m listening to on Spotify (Hugh Laurie’s “Let Them Talk”). Google found Hugh Laurie. There’s one of his albums, where’s the other one? The one I’m searching for? It’s not possible that I already ran into a limitation in Google’s collection? What if I search by album name?

There it is.

This is Google, right? Google couldn’t find Hugh Laurie’s other album because they had it filed under “Various Artists”. The album cover, however, shows it as “Hugh Laurie: Let them Talk”.

Google can’t Google.

This is unexpected, actually. Google Play is stumbling hard out of the gate because the search sucks. I’d never thought of Grooveshark’s search as especially good, but their search had led me to expect higher-quality results than even the mighty Google is capable of delivering.

And then, when I do find what I want, Google Play can’t play anything. Pity. Just zips through the songs in the list and whines that it can’t reach the servers. Which it clearly can.

I finally figured out what the problem with Google Play was on my Mac. I have click-to-play on for all plugins and good, old super-high-tech Google still uses FLASH for a couple of things, … like playing music. Are you kidding? What is up with the modern Google Play using Flash to play music? It’s 2015, right? Don’t we have an HTML5 audio tag now? On top of that, Google Play couldn’t tell me that the plugin that they absolutely need in order to run wasn’t enabled?

GrooveShark could. Just sayin’.

We can’t have nice things

Why couldn’t we just take the GrooveShark concept and software and make it legal?

With Grooveshark, we flew too close to the sun, but from our lofty aerie we were able to glimpse what listening to music and discovering music could be.

From these heights, we’re now dropped back into the morass of crappy software and arbitrarily limited collections fighting it out for the next several years until we finally settle on something like GrooveShark again. Google Play is decent, has a lot of music and a good UI, but it nearly gave me a frustration aneurysm straight out of the gate and costs 2.5 times as much as my previous solution for that pleasure.

It’s like the Internet in the 90s. They wanted us to pay for every scrap of information we got. 20 years later and we now have all of the world’s information at our fingertips. We want all of the world’s music at our fingertips as well. And books and movies and TV shows, while you’re at it.

In Switzerland, we pay several hundred francs per year for our media subscriptions (video and audio). The price covers the costs of Swiss sporting events, but also pays for syndication and licensing fees for songs, movies and TV shows. The Swiss Jazz station is fantastic. But I can’t make a my own playlist from it.

I will gladly pay money for media. I do not like wasting my time, though. I don’t like having to investigate to find out where stuff is playing, to which service I have to subscribe in order to get something, slot it in for viewing before it expires or hoping that the service continues to provide access to the content I’ve actually purchased.

The rent-seekers as gatekeepers to culture

But that’s not exactly the point, though, is it? Why should only people with enough money have access to the music of the world? What happened to the concept of the public library? Now that we have the means to provide a worldwide, digital public library, we’re still stuck in the stone ages, dragged down by the albatross of a primitive remuneration model.

Is there really no way to provide this access at an affordable price? The cost of access is not the true cost or production, but that cost plus a healthy profit. With a nice multiplier for repeated, licensed use. Instead of technology liberating the content, it’s used to artificially fetter it.

In a way, our approach to broadband is the same: we have access to the Internet at all but the highest levels and fastest speeds. For most of us, the cost is relatively cheap. But that’s only from home or the office, and it costs more than it should.

If you want it on the go, you need an extra data plan for your phone. That is, you get to pay for access to the Internet twice. Why are data plans still special, still so limited? Why do you have to worry about tethering? About your data cap? Ridiculous. We have wonderful things now that should be cheap, but that are artificially expensive so that exorbitant rents can be extracted.

There might not be anything you can do about it right now, but it’s important to remember that this is the way it is for now. The limitations are artificial and imposed by society, and many of those limits are imposed on society by an economy jury-rigged to benefit the rent-seekers. Their grasp on our worldview seems to be quite solid, but there are rumblings. We should help turn that into a roar.

So, no, you’re not a fool for thinking you should have access to unlimited internet or music or movies or books. You’re a fool if you believe that there is no other way. It’s about political will, as usual. The sums involved are relatively paltry. See Dean Baker’s Artistic Freedom Voucher for a workable proposal that would cost peanuts for each taxpayer.

While we’re at it, could we also ensure that everyone in the world has access to clean drinking water or to sufficient food? No, of course not. That would cost billions. Who has that kind of money? Governments are busy buying planes that don’t fly with that money and corporations are busy…sitting on it, waiting for a good investment opportunity.

Our civilization is absolutely not geared toward providing services. It is geared toward providing rent.

Encodo’s configuration library for Quino: part III

Published by marco on in Programming

 This discussion about configuration spans three articles:

  1. part I discusses the history of the configuration system in Quino as well as a handful of principles we kept in mind while designing the new system
  2. part II discusses the basic architectural changes and compares an example from the old configuration system to the new.
  3. part III takes a look at configuring the “execution order”—the actions to execute during application startup and shutdown


Registering with an IOC is all well and good, but something has to make calls into the IOC to get the ball rolling.

Something has to actually make calls into the IOC to get the ball rolling.

Even service applications—which start up quickly and wait for requests to do most of their work—have basic operations to execute before declaring themselves ready.

Things can get complex when starting up registered components and performing basic checks and non-IOC configuration.

  • In which order are the components and configuration elements executed?
  • How do you indicate dependencies?
  • How can an application replace a piece of the standard startup?
  • What kind of startup components are there?

Part of the complexity of configuration and startup is that developers quickly forget all of the things that they’ve come to expect from a mature product and start from zero again with each application. Encodo and Quino applications take advantage of prior work to include standard behavior for a lot of common situations.

Configuration Patterns

Some components can be configured once and directly by calling a method like UseMetaTranslations(string filePath), which includes all of the configuration options directly in the composition call. This pattern is perfect for options that are used only by one action or that it wouldn’t make sense to override in a subsequent action.

So, for simple actions, an application can just replace the existing action with its own, custom action. In the example above, an application for which translations had already been configured would just call UseMetaTranslations() again in order to override that behavior with its own.

Most application will replace standard actions or customize standard settings

Some components, however, will want to expose settings that can be customized by actions before they are used to initialize the component.

For example, there is an action called SetUpLoggingAction, which configures logging for the application. This action uses IFileLogSettings and IEventLogSettings objects from the IOC during execution to determine which types of logging to configure.

An application is, of course, free to replace the entire SetUpLoggingAction action with its own, completely custom behavior. However, an application that just wanted to change the log-file behavior or turn on event-logging could use the Configure<TService>() method[1], as shown below.

  s => s.Behavior = LogFileBehavior.MultipleFiles
  s => s.Enabled = true


A Quino application object has a list of StartupActions and a list of ShutdownActions. Most standard middleware methods register objects with the IOC and add one or more actions to configure those objects during application startup.

Actions have existed for quite a while in Quino. In Quino 2, they have been considerably simplified and streamlined to the point where all but a handful are little more than a functional interface[2].

The list below will give you an idea of the kind of configuration actions we’re talking about.

  • Load configuration data
  • Process command line
  • Set up logging
  • Upgrade settings/configuration (e.g. silent upgrade)
  • Log a header (e.g. user/date/file locations/etc.; for console apps. this might be mirrored to the console)
  • Load plugins
  • Set up standard locations (e.g. file-system locations)

For installed/desktop/mobile applications, there’s also:

  • Initialize UI components
  • Provide loading feedback
  • Check/manage multiple running instances
  • Check software update
  • Login/authentication

Quino applications also have actions to configure metadata:

  • Configure expression engine
  • Load metadata
  • Load metadata-overlays
  • Validate metadata
  • Check data-provider connections
  • Check/migrate schema
  • Generate default data

Application shutdown has a smaller set of vital cleanup chores that:

  • dispose of connection managers and other open resources
  • write out to the log, flush it and close it
  • show final feedback to the user

Anatomy of an Action

The following example[3] is for the 1.x version of the relatively simple ConfigureDisplayLanguageAction.

public class ConfigureDisplayLanguageAction<TApplication> 
  : ApplicationActionBase<TApplication>
  where TApplication : ICoreApplication
  public ConfigureDisplayLanguageAction()
    : base(CoreActionNames.ConfigureDisplayLanguage)

  protected override int DoExecute(
    TApplication application, ConfigurationOptions options, int currentResult)
    // Configuration code…

What is wrong with this startup action? The following list illustrates the main points, each of which is addressed in more detail in its own section further below.

  • The ConfigurationOptions parameter introduces an unnecessary layer of complexity
  • The generic parameter TApplication complicates declaration, instantiation and extension methods that use the action
  • The int return type along with the currentResult parameter are a bad way of controlling flow.

The same startup action in Quino 2.x has the following changes from the Quino 1.x version above (legend: additions; deletions).

public class ConfigureDisplayLanguageAction<TApplication>
  : ApplicationActionBase<TApplication>
  where TApplication : ICoreApplication
  public ConfigureDisplayLanguageAction()
    : base(CoreActionNames.ConfigureDisplayLanguage)

  publicprotected override void int DoExecute(
    TApplication application, ConfigurationOptions options, int currentResult)
    // Configuration code…

As you can see, quite a bit of code and declaration text was removed, all without sacrificing any functionality. The final form is quite simple, inheriting from a simple base class that manages the name of the action and overrides a single parameter-less method. It is now much easier to see what an action does and the barrier to entry for customization is much lower.

public class ConfigureDisplayLanguageAction : ApplicationActionBase
  public ConfigureDisplayLanguageAction()
    : base(CoreActionNames.ConfigureDisplayLanguage)

  public override void Execute()
    // Configuration code…

In the following sections, we’ll take a look at each of the problems indicated above in more detail.

Remove the ConfigurationOptions parameter

These options are a simple enumeration with values like Client, Testing, Service and so on. They were used only by a handful of standard actions.

These options made it more difficult to decide how to implement the action for a given task. If two tasks were completely different, then a developer would know to create two separate actions. However, if two tasks were similar, but could be executed differently depending on application type (e.g. testing vs. client), then the developer could still have used two separate actions, but could also have used the configuration options. Multiple ways of doing the exact same thing is all kinds of bad.

Multiple ways of doing the exact same thing is all kinds of bad.

Parameters like this conflict conceptually with the idea of using composition to build an application. To keep things simple, Quino applications should be configured exclusively by composition. Composing an application with service registrations and startup actions and then passing options to the startup introduced an unneeded level of complexity.

Instead, an application now defines a separate action for each set of options. For example, most applications will need to set up the display language to use—be it for a GUI, a command-line or just to log messages in the correct language. For that, the application can add a ConfigureDisplayLanguageAction to the startup actions or call the standard method UseCore(). Desktop or single-user applications can use the ConfigureGlobalDisplayLanguageAction or call UseGlobalCore() to make sure that global language resources are also configured.

Remove the TApplication generic parameter

The generic parameter to this interface complicates the IApplication<TApplication> interface and causes no end of trouble in MetaApplication, which actually inherits from IApplication<IMetaApplication> for historical reasons.

There is no need to maintain statelessness for a single-use object.

Originally, this parameter guaranteed that an action could be stateless. However, each action object is attached to exactly one application (in the IApplication<TApplication>.StartupActions list. So the action that is attached to an application is technically stateless, and a completely different application than the one to which the action is attached could be passed to the IApplcationAction.Execute…which makes no sense whatsoever.

Luckily, this never happens, and only the application to which the action is attached is passed to that method. If that’s the case, though, why not just create the action with the application as a constructor parameter when the action is added to the StartupActions list? There is no need to maintain statelessness for a single-use object.

This way, there is no generic parameter for the IApplication interface, all of the extension methods are much simpler and applications are free to create custom actions that work with descendants of IApplication simply by requiring that type in the constructor parameter.

Debugging is important

A global exception handler is terrible for debugging

The original startup avoided exceptions, preferring an integer return result instead.

In release mode, a global exception handler is active and is there to help the application exit more or less smoothly—e.g. by logging the error, closing resources where possible, and so on.

A global exception handler is terrible for debugging, though. For exceptions that are caught, the default behavior of the debugger is to stop where the exception is caught rather than where it is thrown. Instead, you want exceptions raised by your application to to stop the debugger from where they are thrown.

So that’s part of the reason why the startup and shutdown in 1.x used return codes rather than exceptions.

Multiple valid code paths

The other reason Quino used result codes is that most non-trivial applications actually have multiple paths through which they could successfully run.

Exactly which path the application should take depends on startup conditions, parameters and so on. Some common examples are:

  • Show command-line help
  • Migrate an application schema
  • Import, export or generate data

To show command-line help, an application execute its startup actions in order. It reaches the action that checks whether the user requested command-line help. This action processes the request, displays that help and then wants to smoothly exit the application. The “main” path—perhaps showing the user a desktop application—should no longer be executed.

Non-trivial applications have multiple valid run profiles.

Similarly, the action that checks the database schema determines that the schema in the data provider doesn’t match the model. In this case, it would like to offer the user (usually a developer) the option to update the schema. Once the schema is updated, though, startup should be restarted from the beginning, trying again to run the main path.

Use exceptions to indicate errors

Whereas the Quino 1.x startup addressed the design requirements above with return codes, this imposes an undue burden on implementors. There was also confusion as to when it was OK to actually throw an exception rather than returning a special code.

Instead, the Quino 2.x startup always uses exceptions to indicate errors. There are a few special types of exceptions recognized by the startup code that can indicate whether the application should silently—and successfully—exit or whether the startup should be attempted again.


There is of course more detail into which we could go on much of what we discussed in these three articles, but that should suffice for an overview of the Quino configuration library.

[1] If C# had them, that it is. See Java 8 for an explanation of what they are.
[2] This pattern is echoed in the latest beta of the ASP.NET libraries, as described in the article Strongly typed routing for ASP.NET MVC 6 with IApplicationModelConvention.
[3] Please note that formatting for the code examples has been adjusted to reduce horizontal space. The formatting does not conform to the Encodo C# Handbook.

Encodo’s configuration library for Quino: part II

Published by marco on in Programming

In this article, we’ll continue the discussion about configuration started in part I. We wrapped up that part with the following principles to keep in mind while designing the new system.

  • Consistency
  • Opt-in configuration
  • Inversion of Control
  • Configuration vs. Execution
  • Common Usage

Borrowing from ASP.NET vNext

Quino’s configuration inconsistencies and issues have been well-known for several versions—and years—but the opportunity to rewrite it comes only now with a major-version break.

Luckily for us, ASP.NET has been going through a similar struggle and evolution. We were able to model some of our terminology on the patterns from their next version. For example, ASP.NET has moved to a pattern where an application-builder object is passed to user code for configuration. The pattern there is to include middleware (what we call “configuration”) by calling extension methods starting with “Use”.

Quino has had a similar pattern for a while, but the method names varied: “Integrate”, “Add”, “Include”; these methods have now all been standardized to “Use” to match the prevailing .NET winds.

Begone configuration and feedback

Additionally, Quino used to make a distinction between an application instance and its “configuration”—the template on which an application is based. No more. Too complicated. This design decision, coupled with the promotion of a platform-specific “Feedback” object to first-level citizen, led to an explosion of generic type parameters.[1]

The distinction between configuration (template) and application (instance) has been removed. Instead, there is just an application object to configure.

The feedback object is now to be found in the service locator. An application registers a platform-specific feedback to use as it would any other customization.

[1] The CustomWinformFeedback in the Quino 1.x code at the end of this article provides a glaring example.

Hello service locator

ASP.NET vNext has made the service locator a first-class citizen. In ASP.NET, applications receive an IApplicationBuilder in one magic “Configure” method and receive an IServiceCollection in another magic “ConfigureServices” method.

In Quino 2.x, the application is in charge of creating the service container, though Quino provides a method to create and configure a standard one (SimpleInjector). That service locator is passed to the IApplication object and subsequently accessible there.

Services can of course be registered directly or by calling pre-packaged Middleware methods. Unlike ASP.NET vNext, Quino 2.x makes no distinction between configuring middleware and including the services required by that middleware.

Begone configuration hierarchy

Quino’s configuration library has its roots in a time before we were using an IOC container. The configuration was defined as a hierarchy of configuration classes that modeled the following layers.

  • A base implementation that makes only the most primitive assumptions about an application. For example, that it has a RunMode (“debug” or “release”) or an exit code or that it has a logging mechanism (e.g. IRecorder).
  • The “Core” layer comprises application components that are very common, but do not depend on Quino’s metadata.
  • And, finally, the “Meta” layer includes configuration for application components that extend the core with metadata-dependent versions as well as specific components required by Quino applications.

While these layers are still somewhat evident, the move to middleware packages has blurred the distinction between them. Instead of choosing a concrete configuration base class, an application now calls a handful of “Use” methods to indicate what kind of application to build.

There are, of course, still helpful top-level methods—e.g. UseCore() and UseMeta() methods—that pull in all of the middleware for the standard application types. But, crucially, the application is free to tweak this configuration with more granular calls to register custom configuration in the service locator.

This is a flexible and transparent improvement over passing esoteric parameters to monolithic configuration methods, as in the previous version.

An example: Configure a software updater

Just as a simple example, whereas a Quino 1.x standalone application would set ICoreConfiguration.UseSoftwareUpdater to true, a Quino 2.x application calls UseSoftwareUpdater(). Where a Quino 1.x Winform application would inherit from the WinformFeedback in order to return a customized ISoftwareUpdateFeedback, a Quino 2.x application calls UseSoftwareUpdateFeedback().

The software-update feedback class is defined below and is used by both versions.

public class CustomSoftwareUpdateFeedback : WinformSoftwareUpdateFeedback<IMetaApplication>
  protected override ResponseType DoConfirmUpdate(TApplication application, …)

That’s where the similarities end, though. The code samples below show the stark difference between the old and new configuration systems.

Quino 1.x

As explained above, Quino 1.x did not allow registration of a sub-feedback like the software-updater. Instead, the application had to inherit from the main feedback and override a method to create the desired sub-feedback.

class CustomWinformFeedback : WinformFeedback
  public virtual ISoftwareUpdateFeedback<TApplication> GetSoftwareUpdateFeedback<TApplication, TConfiguration, TFeedback>()
    where TApplication : ICoreApplication<TConfiguration, TFeedback>
    where TConfiguration : ICoreConfiguration
    where TFeedback : ICoreFeedback
    return new CustomSoftwareUpdateFeedback(this);

var configuration = new CustomConfiguration()
  UseSoftwareUpdater = true

WinformDxMetaConfigurationTools.Run(configuration, app => new CustomMainForm(app), new CustomWinformFeedback());

The method-override in the feedback was hideous and scared off a good many developers. not only that, the pattern was to use a magical, platform-specific WinformDxMetaConfigurationTools.Run method to create an application, run it and dispose it.

Quino 2.x

Software-update feedback-registration in Quino 2.x adheres to the principles outlined at the top of the article: it is consistent and uses common patterns (functionality is included and customized with methods named “Use”), configuration is opt-in, and the IOC container is used throughout (albeit implicitly with these higher-level configuration methods).

using (var application = new CustomApplication())
  application.UseSoftwareUpdaterFeedback(new CustomSoftwareUpdateFeedback());
  application.Run(app => new CustomMainForm(app));

Additionally, the program has complete control over creation, running and disposal of the application. No more magic and implicit after-the-fact configuration.

What comes after configuration?

In the next and (hopefully) final article, we’ll take a look at configuring execution—the actions to execute during startup and shutdown. Registering objects in a service locator is all well and good, but calls into the service locator have to be made in order for anything to actually happen.

Keeping this system flexible and addressing standard application requirements is a challenging but not insurmountable problem. Stay tuned.