Multiplayer Point ‘n Click Adventure Games: Long Overdue

“What are adventure games?”, you might ask. When confronted with this question I usually reply they are interactive movies, where you need to solve puzzles in order for the plot to progress. As you interact with objects and characters within the game, the backstory is revealed. The first few minutes of Resonance provide a good first impression of what a point ‘n click adventure game has to offer: captivating cutscenes, followed by seemingly trivial interactions with the game environment, which regardless reveal a rich underlying story.

resonance

Example of a point ‘n click game (Resonance), where the player needs to interact with objects in the game environment in order to progress the plot.

Adventure games have gone somewhat out of fashion over the years, making way for more fast-paced action-packed video games, like first-person shooters. However, a few—mainly independent—developers have kept the genre alive, and true gems (like Resonance) are still released sporadically. They generally adhere to the core game mechanics (as well as witty dialogues) introduced by the classics, and often still prefer old school pixel artwork over modern graphics.

One overlooked feature of adventure games is they are inherently suitable to be played by multiple players; not true multiplayer, but for the lack of a better word, lets call them potential ‘audience games’. At countless occasions I have invited friends over to kick back in the couch, open a beer, and gaze at a projection or screen as somebody point ‘n clicks his way through the game’s narrative. Similar to watching a movie, but different in that shouting throughout (to point out what to click next) is not only appreciated, but in fact encouraged. 1394641-200px_rubberchickenThere is something suspiciously entertaining about listening to people’s concoctions on what item to combine with the “rubber chicken with a pulley in the middle” in order to finally put it to good use; usually followed by a short silence and a subsequent “Why on earth would you want to do that?”. I dubbed such evenings (and late nights) ‘Adventure Game Nights’, and wanted to report on what works and what does not. In addition, I see opportunities for making adventure games true multiplayer experiences.

After years of hosting such events for uninitiated and seasoned players alike (I once even played a game over Skype), some things became apparent:

  • It is best to pick games with a strong narrative, rather than a shallow story line. In other words, games like Resonance, The Inner World, Still Life, and The Blackwell Legacy appeal to a wider audience than true classics like Monkey Island. Games on the far end of this spectrum, interactive dramas like The Walking Dead, are the perfect gateway drug for people to get hooked on the genre, but unfortunately lack the complexity which make adventure games stand out.
  • Spoken dialogues are essential! It is near impossible to stay focused as a group when everyone needs to read on-screen text at their own leisure and pace.
  • If you cherish your night rest, start early, and pick a game which doesn’t last too long (aim for a maximum of seven hours). Short episodic adventure games offer a solution, although they generally aren’t as captivating (the Blackwell series being the exception). Ideally, in case you have a core group of point ‘n click addicts, you can decide on a longer game and play it over several evenings.
  • Pixel hunting (scrutinous scanning of the screen to find anything clickable) is exacerbated when playing in group; you’ll hear people shouting “Can you click on the red thingy in the bottom corner?”, at times followed by “We already clicked that!”. A quick primer on how to tell whether something is clickable or not in advance is recommended.

The takeaway message for game designers and developers is there might be a broader audience for point ‘n click adventure games than they traditionally anticipate. Rather than solely tailoring adventure games to single player experiences, there is an opportunity to design adventure games with group experiences in mind. Besides changing the overall format so it can be consumed in one sitting (similar to movies), it would be worthwhile experimenting with features which account for multiple players wanting to interact with the game environment simultaneously. To this end designers could leverage the fact that players each carry a powerful computer in their pockets (smartphones) allowing for rich interactions. Some obvious candidates: maintain a history of interactions and dialogues, ‘vote to skip’, suggested puzzle resolutions including a point system, …

The possibilities are endless … A multiplayer point ‘n click game is long overdue!

Leave a comment

Non-generic Wrapper instead of Base Class or Interface

A common solution to treating a generic type as non-generic is to implement an interface or make the generic type extend from a non-generic base class. Among other reasons, this allows you to instantiate a collection of generic types. There are varying implementations of this pattern, but they all seem to share this common strategy. In this article I present an alternate approach favoring composition over inheritance which I argue is more appropriate in circumstances where the intent is to break type safety.

To clarify, I will follow Steven Lowe’s argumentation on misuse of inheritanceSemantically, the statement “SomeType<T> is SomeType” is not always true; SomeType<T> is not a proper subtype of SomeType when the base type exposes type-specific bits (as Jon Skeet puts it). In this case the extending type imposes more restrictions than the base type. When there is a need to expose type-specific bits (implying type casts are involved), using inheritance does not follow the Liskov substitution principle (LSP). Regardless, such subtypes seem common. Just consider Microsoft’s List<T> implementing a non-generic IList which to quote Eric Lippert, “is a bit odd, since List for any type other than object does not fulfill the full contract of IList”.

From this it becomes clear there are real-world scenarios where a generic type needs to be accessed in a non-generic way (e.g. during reflection as I argued previously). Type safety is temporarily broken, leaving it is up to the caller to guarantee only the correct types are used. How then to improve on the following common implementation? Note that since the non-generic interface is implemented explicitly, the caller consciously needs to cast to ISomeType, somewhat alleviating the problem of possible misuse.

public interface ISomeType
{
    object Value { get; set; }
}

public class SomeType<T> : ISomeType
{
    public T Value { get; set; }

    // Explicit implementation (cast to ISomeType needed to be used).
    object ISomeType.Value
    {
        get { return this.Value; }
        set { this.Value = (T)value; }
    }
}

We need a non-generic interface but are given a generic interface, so why not apply the adapter pattern?

An adapter helps two incompatible interfaces to work together. […] Interfaces may be incompatible but the inner functionality should suit the need.

Since the class we are trying to create an adapter for is generic, our adapter implementation needs to be generic too. However, we can expose the non-generic interface which will be used by the client. Just like a usual adapter, the non-generic wrapper contains the adaptee and refers all of the IAdaptor calls to it, casting to T where necessary.

 

public interface IAdaptor
{
    object Value { get; set; }
}

class NonGenericWrapper<T> : IAdaptor
{
    private readonly Adaptee<T> _adaptee;

    public NonGenericWrapper(Adaptee<T> adaptee)
    {
        _adaptee = adaptee;
    }

    public object Value
    {
        get { return _adaptee.Value; }
        set { _adaptee.Value = (T) value; }
    }
}

Furthermore, to facilitate the creation of this non-generic wrapper (and in addition hiding its implementation) the wrapper can optionally be initialized from within the adaptee and added as a member. This approach seems similar to how user interface controls in .NET expose the window handle they operate on as a member variable, allowing for unsafe operations when the control class does not offer the required functionality.

public class Adaptee<T>
{
    public T Value { get; set; }

    public IAdaptor NonGeneric { get; private set; }

    public Adaptee()
    {
        NonGeneric = new NonGenericWrapper<T>(this);
    }
}
Pattern which can be used to expose a non-generic interface from within a generic class.

Pattern which can be used to expose a non-generic interface from within a generic class.

This approach still requires boiler-plate code to be written and maintained (NonGenericWrapper<T>), but no longer breaks the Liskov substitution principle. Ideally creating non-generic wrappers can be automated, of which I created an early prototypical solution before (not functional in all scenarios). Until then, this solution provides a more robust implementation for complex scenarios using generics, like collections of generic types with varying type parameters on which the same operations need to be performed. This might be the topic of a future post.

Leave a comment

Missing Affordances in Windows 10

Before heading out to the shooting range and placing Windows 10 on the target stand, let it be said that Windows 10 is a great improvement over Windows 8 and definitely a step in the right direction. However, this post is not concerned with overall impressions, neither with minor bugs which I’m certain will be ironed out over time. Rather, it sets out to highlight (call it nitpicking if you want) several annoying aspects of the redesigned window manager which I don’t expect to see changed any time soon. At first these seem like minute manageable details. However, when it comes to usability seemingly small issues can become a major annoyance when running into them on a regular basis, especially when they occur during moments of high workload where the window manager is already put under a great amount of stress.

Affordances

There is no need to go into detail about the notion of affordances (and its many interpretations), except for presenting one of the earlier definitions (The Psychology of Everyday ThingsNorman 1988, p.9):

“…the term affordance refers to the perceived and actual properties of the thing, primarily those fundamental properties that determine just how the thing could possibly be used. […] Affordances provide strong clues to the operations of things. Plates are for pushing. Knobs are for turning. Slots are for inserting things into. Balls are for throwing or bouncing. When affordances are taken advantage of, the user knows what to do just by looking: no picture, label, or instruction needed.”

Within user interface (UI) design, this means UI components should thus ‘afford’ clicking, dragging, moving, or any other operation that is supported by presenting the user with clear visual clues.

Window Manager in Windows 10

As Windows evolved, the styling of application windows was designed to be more and more in line with current minimalistic trends in interface design. Styling preferences aside, unfortunately this also introduces changes in the visible affordances to work with windows. In the following figure, notice in particular how the distinction between the title bar, the menu bar, and the window border are removed in subsequent versions of Windows.

window chrome_smaller

Different styling of application windows in (from top to bottom) Windows 7, Windows 8, and Windows 10.

You might wonder, which affordances does this affect? Take a look at the old documentation on how to manipulate windows. In particular, I notice two major changes which bother me.

Resizing windows: 


Resizing windows in Windows 7.
In Windows 7, there was a visible border above which the mouse pointer changed to a resize icon. There was thus an easy visible target to point to when resizing windows.Resizing windows in Windows 10.

In Windows 10, all borders (except the top border) are invisible. To resize a window you need to hover over the empty area surrounding the window in order for the resize option to appear. Even more challenging is resizing the top right corner. Try figuring out where the resize option appears, as opposed to where the close button lights up! This is complicated immensely since the top border is visible (but overlayed by the close button starting from Windows 8), and the side border is invisible. Hovering over this area is quirky and unpredictable to say the least.

Moving windows:

The title bar can be used to move the application window using the mouse (click and drag). However, in Windows 10 there is no longer a visible separation between the title bar and the menu bar. [UPDATE: Microsoft has since released an update reintroducing colored title bars.] Note that the menu bar can not be used to drag the window. The pointing task to move a window is thus complicated since there are no visual clues to determine whether a window can be dragged from a given position (not even on hover). However, since it seems the menu bar has been removed for modern Windows applications, this is mainly a problem for classic desktop applications (and will be until they are phased out).

Discussion

In line with the concept of affordances, Microsoft’s user experience checklist for desktop applications states the following:

Never require users to click an object to determine if it is clickable. Users must be able to determine clickability by visual inspection alone.

  • Primary UI (such as commit buttons) must have a static click affordance. Users shouldn’t have to hover to discover primary UI.
  • Secondary UI (such as secondary commands or progressive disclosure controls) can display their click affordance on hover.
  • […]

For your convenience, the definitions (taken from Microsoft’s glossary) of some of the more obscure concepts listed above:

commit button—A command button used to commit to a task, proceed to the next step in a multi-step task, or cancel a task. […]
primary command—A central action that fulfills the primary purpose of a window. For example, Print is a primary command for a Print dialog box. […]
secondary command—A peripheral action that, while helpful, isn’t essential to the purpose of the window. For example, Find Printer or Install Printer are secondary commands for a Print dialog box. […]
progressive disclosure—A technique of allowing users to display less commonly used information (typically, data, options, or commands) as needed. For example, if more options are sometimes needed, users can expose them in context by clicking a chevron button.

Using this terminology it can thus be argued Microsoft now considers window operations to be ‘secondary commands’, as opposed to ‘primary commands’. Personally I don’t find what in essence are invisible UI components good design, regardless of whether their functionality becomes visible on hover. More importantly, the lack of any visual distinction (even on hover) between the title bar and the menu bar contradicts Microsoft’s own design guidelines. It seems like usability took a backseat to styling, just for the sake of having a ‘flat’ look.

Leave a comment

Core Values Theory: Hacking Emotions

Underwood: “And you don’t make decisions on emotions?” Tusk: “Decisions based on emotions aren’t decisions at all. They’re instincts, … which can be of value. The rational and the irrational complement each other. Individually they’re far less powerful.”

This exchange between the manipulative protagonist Frank Underwood and billionaire Raymond Tusk in House of Cards highlights a key argument I’ve been raising during discussions on relationships for years—decisions based on emotions aren’t decisions at all. It sets the scene for a rational account on relationships I’ve come to refer to as ‘core values theory‘ during many heated conversations late into the night. My own understanding of the concept, based on nothing else but the experience of life, seems to have solidified sufficiently in order to recount it here. Although you are reading a software design blog, don’t expect anything IT related beyond the title “Hacking Emotions” from here on out.

What do you want?

what do you want

Seems like a simple question doesn’t it? “What do you want in life?” The truth though is that the majority of people you ask this question either greet you with a blank stare, or simply state they “just want to be happy”. Try it out for yourself! Next time, rather than discussing the newest episode of Game of Thrones, catch a friend off guard by asking this very question. You might be surprised to discover a general consensus that we are all just pawns in the grand scheme of things; passive bystanders whose roles are limited to either jumping on the passing train, or waiting for the next one. “Carpe Diem” offers a rich perspective on life, make the most out of each moment, but does it exclude glancing at the train schedule so you know where you are headed?

The problem with the blank stare, or solely relying on emotions to decide on a course of action, is you assume a passive role in life. You let your environment decide for you and simply express approval or disapproval. You do not grow as a person—you do not learn what it is that makes you happy or unhappy, what your goal is in life. Ultimately, it is counterproductive; simply pursuing the experience of happiness does not guarantee it in the long run, as you do not gain an understanding of how to maintain it. A case in point being our current materialistic society; quick-fix possessions do not lead to true happiness, on the contrary, it is self-destructive.

In his book “The 7 habits of highly effective people”, Stephen R. Covey’s advocates becoming aware of one’s own internal ‘maps’: where you stand, and where you want to be headed.

Each of us has many, many maps in our head, which can be divided into two main categories: maps of the way things are, or realities, and maps of the way things should be, or values. We interpret everything we experience through these mental maps. We seldom question their accuracy; we’re usually even unaware that we have them. – Stephen R. Covey

Far from being a book I would recommend, it still contains valuable ideas, including the suggestion of being proactive as opposed to reactive in lifeBeing proactive does not simply mean taking matter into your own hands, but also implies identifying that which concerns you, in order to work towards enlarging your influence on that which truly matters to you. It implies a positive stance in life, asking yourself “What can I do?”, rather than “Why does this happen to me?”, the result of which is a rewarding sense of empowerment.

Part of what makes us human is we do not have control over our emotions. It is outside of our circle of influence, but most definitely within our circle of concern. How then, to take a proactive stance when emotions are involved?

So, what DO you want?

Relationships, being one of the most fundamental building blocks in life, give rise to the strongest of emotions: love, hate, loneliness, jealousy, … and happiness. While I imagine that most people readily agree with the earlier quote from House of Cards, I have yet to meet anyone that truly applies it in all aspects of life, including relationships. On the contrary, mainstream culture seems to disregard any sense of rationality when it comes to love. Love is impenetrable to human thought, and should be left to destiny. Media does a good job of reinforcing this simplistic view, even in nontraditional “Once upon a time …” movies: “It just happened. […] I just woke up one day and I knew.” – 500 Days of Summer

Unless you aren’t looking for ‘happy ever after’, the problem is relationships (and marriages) also “just happen” to end because “the love is gone“. This common view on relationships is a reactive one.

One of my most controversial viewpoints in life is that relationships should not be dictated by feelings. I look at emotions as a manifestation of an underlying cause which you do have some level of control over. I am not declaring war on feelings here. Feelings (or lack thereof) are useful signposts put up by your body. However, it is your mind’s job to follow the right ones and decide where to go. A proactive approach by no means guarantees a ‘happy ever after’, but more importantly increases your awareness of what you are looking for and allows you to learn from past experiences (what to repeat, and what not to repeat). I do not believe in relationships built solely on top of feelings, and consider them a fruitless endeavor; emotional roller-coasters that make you feel alive, but in the end you still need to exit the theme park.

There is a need to identify who you are, what you want in life, i.e. to identify your identity—your core. As often expressed: “Find yourself before you find love.”

Core Values

In a nutshell, core values theory advocates identifying objective values you expect your partner to have in a relationship, based on your expectations in life. They are testable, meaning, as you get to know someone, you can objectively judge whether or not they fit these criteria. They are ‘core‘ values in the sense that they make up your identity; changing them would imply changing your nature, your personality. Emotions do not come into play. Within Stephen R. Covey’s diagram it could be depicted as an unbendable center you are unwilling to change.

core_values_theory

Ironically, a common response to this is “But how can you be so picky? If one thing on the list doesn’t work out, you give up? You do not open up yourself to new experiences”. The truth though is most people already have a similar list, but just aren’t aware about it. By externalizing and objectifying it for some reason it becomes a faux pas. Their list however is usually longer, transient, more restrictive than the core values I am talking about here, and includes subjective values like “it needs to feel right”, or “it needs to be love at first sight”. The ‘list’ is nothing more than a mental exercise, identifying key aspects in your life on which to make more rational decisions when clouded by emotion, or even in the absence of emotion. If anything, it is more in line with the idiom, “There are plenty of fish in the sea”, recognizing you are not after ‘the one’, but after anyone you can fully respect, and love.

There is some reasoning behind this madness. Firstly, you should not think less of your spouse; a relationship is built on mutual respect. In the case of conflicting core values I argue this is unsustainable. It easily turns into recurrent arguments throughout the relationship, where you want to out-argue the other, causing resentment and loss of respect. Secondly, you should not expect to change or ‘fix’ your partner in a relationship; do not expect the core values of your partner to change, it is outside of your circle of influence. Your energy should be focused elsewhere, where you can actually make a change, and where you can still discover yourself.

This ‘theory’ has some controversial implications. There is nothing wrong with dating someone you have no feelings for, yet are sexually attracted to. Consider it an opportunity to discover your core values. From my own experience I can tell you either feelings will follow, or you learn something new about yourself to take with you into subsequent relationships. But more importantly, a breakup should be indicative of discovering a mismatch in core values, which makes it less of a loss, and more of a learning experience.

Conclusion

This perspective on relationships comes at a price. Most people want to be swept off their feet, where emotions take center stage. I’m a rational person, and prefer placing rationality at the center. Either way, the stage is big enough, and there is room for both. It might seem hard to believe in a long-term relationship with such conflicting perspectives, but luckily, a rational center is not a core value to me. I know I can learn a lot from an emotional counterpart, and I like to think this works both ways.

2 Comments

Generic TypeConverter for XAML

TypeConverter‘s in WPF are part of the underlying mechanism which allow you to assign values to attributes of complex types within XAML using plain strings. For example, whenever you specify Point‘s.

<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">

Typically, you specify a TypeConverter for a certain type by applying the TypeConverterAttribute to it.

[TypeConverterAttribute( typeof( PointConverter ) )]
public struct Point : IFormattable

Since attribute arguments cannot use type parameters, this prevents you from specifying a generic TypeConverter for a generic class. I came across this issue while implementing a type converter to support specifying instances of my generic Interval class from XAML. The following is not possible.

// attribute argument cannot use type parameters
[TypeConverter( typeof( IntervalTypeConverter<T, TSize> ) )]
public class Interval<T, TSize>

However, you can write a non-generic TypeConverter which is capable of converting strings to several different target types. When using XAML you can obtain a IDestinationTypeProvider service through the context which is passed to the ConvertFrom method. From here you can retrieve the fully specified target type, including generic type parameters. Through reflection you can then call a Parse method on the specific type to take care of initializing an instance of the desired type. An example for Interval can be found in my library.

public override object ConvertFrom(
    ITypeDescriptorContext context,
    CultureInfo culture,
    object value )
{
    var typeProvider =
      (IDestinationTypeProvider)context.GetService( typeof( IDestinationTypeProvider ) );
    Type targetType = typeProvider.GetDestinationType();

    // ... convert to desired target type using a parsing method

    return base.ConvertFrom( context, culture, value );
}

However, it is important to note that this type provider will only work for XAML, since the IDestinationTypeProvider service is only provided by XAML’s ServiceProviderContext. It is thus not desirable to add this TypeProvider to types which work independent from XAML, like my Interval class. In addition this would require referencing the System.Xaml assembly.

How then to make XAML use this type provider without applying the attribute to the type definition? One option is applying the TypeConverter attribute on a per-property basis.

The per-property type converter technique is particularly useful if you choose to use a property type from Microsoft .NET Framework or from some other library where you cannot control the class definition and cannot apply a TypeConverterAttribute there.

However, this implies a lot of redundancy, having to apply the attribute to every property of that specific type. Using TypeDescriptor.AddAttributes() you can assign a TypeConverter at runtime.

TypeDescriptor.AddAttributes(
  typeof( Interval<,> ),
  new TypeConverterAttribute( typeof( IntervalTypeConverter ) ) );

Any subsequent TypeDescriptor.GetConverter() call will then return the converter for the specified type. Unfortunately this does not work for XAML, since XAML does not seem to take component modifications at runtime into account. Therefore, in order for this to work, we need to implement this runtime behavior ourselves. Recall that XAML does load TypeConverter‘s specified in TypeConverterAttribute‘s. We can thus use a special type converter which redirects its implementation to a converter loaded through TypeDescriptor to hook into XAML’s type conversion runtime. I implemented a RedirectTypeConverter which can be used as a base class for this exact purpose. Each of its methods first ensures the converter is initialized using TypeDescriptor, and then redirects the call to this converter. When TypeDescriptor.GetConverter( _type ) returns the redirecting type converter itself, this means no converter was specified using TypeDescriptor, hence no conversion is supported for this type.

protected RedirectTypeConverter( Type type )
{
	_type = type;
}

public override object ConvertFrom(
	ITypeDescriptorContext context,
	CultureInfo culture,
	object value )
{
	InitializeConverter();
	return _converter.ConvertFrom( context, culture, value );
}

public void InitializeConverter()
{
	if ( _converter != null )
	{
		return;
	}

	_converter = TypeDescriptor.GetConverter( _type );
	if ( _converter.GetType() == GetType() )
	{
		string message = string.Format(
		  "Conversion failed. Converter for {0} is missing in TypeDescriptor.", _type );
		throw new InvalidOperationException( message );
	}
}
class RedirectIntervalTypeConverter : RedirectTypeConverter
{
	public RedirectIntervalTypeConverter()
		: base( typeof( Interval<,> ) )
	{
	}
}

Applying this converter using TypeConverterAttribute to generic types thus allows redirecting type conversion to a converter which supports multiple target types in environments which provide information about the target type (like XAML using IDestinationTypeProvider). You only need to add the converter once, and it will be supported for all of your dependency properties using them.

TypeDescriptor.AddAttributes(
  typeof( Interval<,> ),
  new TypeConverterAttribute( typeof( IntervalTypeConverter ) ) );

Leave a comment

Interval: Generic Ranges in C#

There is no doubt about it; out of all the programming languages I ever experimented with, C# has offered me the most streamlined positive development experience so far. It is a modern, ever-evolving language, which now that C# and the whole .NET framework is turning to open source, is guaranteed an even greater future. However, some core constructs commonly available in other languages, like intervals which I introduce an implementation of in this post, are missing. E.g., Ruby has had Ranges for quite some time.

A Range represents an interval—a set of values with a beginning and an end.

Straightforward, but due to the lack of support for generic calculations in C#, a hassle to implement. However, as introduced by Marc Gravell, with some runtime compilation trickery involving expression trees, far from out of reach. I’ve had an Interval<T> class within my core library for quite some time, but just now refactored it to also support more complex intervals, e.g. an interval between two DateTime instances, which thus represents a TimeSpan.

Without further ado, an example of what using this looks like in practice.

// Mockup of a GUI element and mouse position.
var timeBar = new { X = 100, Width = 200 };
int mouseX = 180;

// Find out which date on the time bar the mouse is positioned on,
// assuming it represents whole of 2014.
var timeRepresentation = new Interval<int>( timeBar.X, timeBar.X + timeBar.Width );
DateTime start = new DateTime( 2014, 1, 1 );
DateTime end = new DateTime( 2014, 12, 31 );
var thisYear = new Interval<DateTime, TimeSpan>( start, end );
DateTime hoverOver = timeRepresentation.Map( mouseX, thisYear );

// If the user clicks, zoom in to this position.
double zoomLevel = 0.5;
double zoomInAt = thisYear.GetPercentageFor( hoverOver );
Interval<DateTime, TimeSpan> zoomed = thisYear.Scale( zoomLevel, zoomInAt );

// Iterate over the interval, e.g. draw labels.
zoomed.EveryStepOf( TimeSpan.FromDays( 1 ), d => DrawLabel( d ) );

As you might notice, the timeRepresentation interval has just one generic parameter (Interval<int>), whereas thisYear has two (Interval<DateTime, TimeSpan>). The less generic (one type parameter) class is a simple wrapper around the more generic base type which has two type parameters; the first denotes the type used to represent any position within the range, whereas the second type is used to represent differences between these positions. When these types are the same, the simplified wrapper can be used. Likewise, a TimeInterval wrapper can easily be created if you find Interval<DateTime, TimeSpan> to be too verbose.

Worth noting here to understand how it works under the covers is the constructor which sets two public static fields used during operations when conversions to double are needed. Arguably, this could be improved by having a factory creating the intervals and using constructor injection instead.

public TimeInterval( DateTime start, bool isStartIncluded, DateTime end, bool isEndIncluded )
	: base( start, isStartIncluded, end, isEndIncluded )
{
	ConvertDoubleToSize = d => new TimeSpan( (long)Math.Round( d ) );
	ConvertSizeToDouble = s => s.Ticks;
}

Once you start incorporating the notion of an interval in your programming arsenal you will be amazed by the opportunities which present themselves where to use them! Some actual examples within my core library:

To get an impression of the full range of currently supported operations, check out the unit tests.

1 Comment

From Personal Information Management to Humane Interaction

While discussing file management in the paper on Laevo I presented today at the UIST conference, I conclude …

[…], in essence files are a remnant of the original desktop metaphor. Users are forced to mentally connect window representations to the files they represent. When restoring window configurations users are [unnecessarily] confronted with finding all the related files.

I reflect on this later in the discussion:

[…], raising interesting questions for further research on how window management can be redesigned to outgrow its original purpose. Further research on Laevo is therefore to increasingly move away from files, as their main intent of persisting information could be replaced by persisting window configurations […]

This is in line with an old post of mine on window management, where I concluded:

Taking this to the extreme: assume closing a window would be the same as deleting a file. Would you actually ever have to know about the underlying file system again? Window management and file management could become one and the same thing.

Originally I titled the current post, “From File Management to Time Management”, since one of the conceptual challenges I like to confront myself with is to design for never having to reopen a file again. Rather, I want to support revisiting the full context (including the window representation of the file) which the original file was part of. As a desktop interface, Laevo uses a temporal representation allowing you to revisit any prior, or planned activity in time.

However, after a yet again inspiring talk by Bret Victor on “The Humane Representation of Thought: a trail map for the 21st century” as the closing keynote of the UIST 2014 conference, I realized that just as file management is a remnant of the original desktop metaphor, so is window management. Windows are a side effect of the digital rectangles we’ve grown so accustomed to within our lives. Window representations are mere visual abstractions of richer concepts and ideas which could be expressed in entirely different ways using all of our senses, rather than being restricted to visual and symbolic notations. The reason why we stick to them is because they allow for dynamic (connected) behavior, which is where the tangible all-around-us world falls short. Following the same argument that we should be phasing out file management, so should we attempt to eliminate the need for window management. The more intermediate abstractions we can remove to interact with the concepts and ideas we actually want to address, the better.

Nonetheless, my underlying thesis remains. The temporal (and associated contextual) dimension is a very tangible, humane concept, we should continue to design for.

1 Comment

Follow

Get every new post delivered to your Inbox.