MVVM – This might hurt a little…
14 November 09 07:23 AM | Avi Pilosof | 4 Comments   

This is an attempt at a collaborative post; I’ll fill in more data if/when people make suggestions; please add comments on more problems and other/better solutions – I’ll add the links.

Overall, MVVM is very attractive – but all the screen casts I’ve seen avoid some confusing pitfalls that you’ll come up against in the real world. The landscape at the time of writing is a plethora of frameworks that attempt to solve similar problems; I expect the community will settle on a small number eventually, and certain patterns will emerge.

Until then, I hope this will help.

Overall

Some things that you take for granted will seem impossible to do in MVVM (without breaking the rules). Sometimes this is due to Silverlight missing WPF features, other times it has nothing to do with that. Most of these holes are pluggable in some sense, which is why…:

Using a Framework

I recommend you use a framework. You can write your own, but please consider that it needs to handle quite a few things in order to solve the various problems in this article.

I can’t recommend which framework to use because I have no experience with them, but I do recommend considering the problems below and finding out how each framework solves them. If the framework doesn’t have a “reference application”, stay away – you’re going to need one.

Here are a few that I know of:

PRISM2.0, which is from the MS Patters&Practices group.

SilverlightFX, by NikhilK. Does alot more than just MVVM; great samples/posts.

MVVM Light

Lots of others 

 

Reacting to a click

Scenario: User clicks button; you want something to happen.

Problem: You’re “not allowed” to use the codebehind and an event-handler, so it needs to be done in the ViewModel. However, the ViewModel is ignorant of the view, so it doesn’t know about the button’s existence – it can’t hook into the click event.

Solution: You need support for “commanding”. Put very simply, this is usually a broadcast/listen mechanism where a “command” gets raised by someone, and someone else chooses to listen to it. In this case, the button would raise a command, and the ViewModel would be listening for it, and act.

WPF has it built-in, Silverlight does not – but the various frameworks have tacked it on, and it’s a basic pillar of MVVM.

 

Opening a dialog

Scenario: You have a listbox, the user double-clicks on an element, and you want an edit dialog to pop up with that element’s data to be edited.

Problem: You’re not allowed to have logic in your code-behind, so you can’t simply react to the event there. So you raise a command, and the ViewModel listens to it… But it’s not allowed to reference a UI component such as a dialog!

Solution: Much as above, you use the broadcast/listen pattern… However, instead of having the ViewModel listen, you have some central app “router” listening, and it knows how to open a dialog.

 

Passing a value to a dialog

Scenario: Same as above.

Problem: You’ve raised the command, and it knows to open a dialog – but how does it know to pass in the currently selected item from the listbox?

Solution 1: Perhaps your framework allows that item to be set as the command argument as part of the XAML. If so, perfect. If not (or if you need something more complex):

Solution 2: Raise the command, but have the ViewModel listen to it instead of a central “router”. The ViewModel figures out what needs to be passed in (for example, a “CurrentlySelected” bound property on itself), and raises an appropriate command.

 

Closing a dialog

Scenario: You opened the dialog, the user made their edits and clicked “Save”, then the dialog’s ViewModel called the web service to save the changes. Now the dialog should be closed.

Problem: The last bit of code that ran was on the dialog’s ViewModel; it can’t tell the dialog to close because it has no notion on the dialog’s existence…

Solution 1: Some frameworks have built-in support for dialogs and will handle this.

Solution 2: Cheat; if you’re not a purist, try this: The ViewModel raises an event (“TimeToClose”) with an argument of success/failure. The View’s codebehind subscribes, and closes the view itself.

 

Animations

Scenario: Your app shows a list of servers, and their status is all “good”. The ViewModel loads some new data, and one of the server’s changes to “bad”. The UI needs to react by playing an animation for that server.

Problem: Fundamentally, you don’t want your ViewModel to know anything about animations, storyboards, VisualStates, etc. It changed the data, but all we have on the view side of things is how to display the data; what we really want is the ability to trigger a storyboard, or to bind an element from the ViewModel to a VisualState on a framework element.

Solution 1: You can try to cheat here by using the codebehind, but depending on your exact scenario it might not help at all.

Solution 2: This article seems to do a good job of replicating DataTrigger for Silverlight (although I’ve yet to experiment with this):

http://blois.us/blog/2009/04/datatrigger-bindings-on-non.html

 

 

Avi

Real-time list filtering with Silverlight, MVVM, and PagedCollectionView
30 October 09 02:51 PM | Avi Pilosof | 6 Comments   

The Model-View-ViewModel pattern is very good for forcing clean UI code. Ideally, you want to end up with zero code in your .xaml.cs file – everything should be data-bound.

As nice as this sounds, sometimes it can get so tempting to break this rule in order to do something that should be simple. Here’s one example:

You have a ListView and a TextBox in the view; they are bound to an ObservableCollection and a string in the ViewModel. You want them to behave such that entering text into that box causes the ListView to filter its items:

image

The initial train of thought is like this: In the event handler for the TextBox, address the ListView and hide all the items that don’t match the filter. At least one problem with this is that you’ve broken your promise to keep logic in the ViewModel.

The second train of thought is: Since the TextBox is bound to a property on the ViewModel, add code to the property setter to remove all the items from the ObservableCollection which don’t match the filter.

This will “work”, and suck. The problem is that you’ve actually removed data, not filtered it. When the user changes the filter text, your collection no longer has the items you’ve removed – you need to reload them.

This is where the PagedCollectionView comes in. It’s a wrapper around another collection which serves the following purposes:

  • You can bind UI elements to it, and it will work like any other collection.
  • When wrapping a collection that implements ICollectionChanged, it bubbles the notification changes.
  • It has properties for setting filters (as well as sorting, paging, grouping).

So what you do is insert this object between your UI and your ObservableCollection, and just modify the filters on it. The data remains untouched, but the UI reacts perfectly.

Before:

image

After:

image

 

Here’s a simple example of the steps to take:

 

1) Create both the ObservableCollection and the PagedCollectionView, but only expose the latter as a property:

// This is the actual container of items that we're storing
private ObservableCollection<string> _RandomItemsBase;

// And this is the wrapper around it which we bind to. The PagedCollectionView
// allows for easy filtering, sorting, grouping.
private PagedCollectionView _RandomItems;
public PagedCollectionView RandomItems
{
    get { return _RandomItems; }
    set
    {
        _RandomItems = value;
        RaisePropChange(() => this.RandomItems);
    }
}

 

2) In the constructor, wrap the real collection with the PagedCollectionView:

_RandomItemsBase = new ObservableCollection<string>();
RandomItems = new PagedCollectionView(_RandomItemsBase);

 

3) When the entered text changes, call a method to filter things:

public string EnteredText
{
    get { return _EnteredText; }
    set {
        _EnteredText = value;
        RaisePropChange(() => this.EnteredText);
        UpdateFilter(); // Real-time filter
    }
}

 

4) And here’s the code to actually apply the filter to the view:

private void UpdateFilter()
{
    if (string.IsNullOrEmpty(EnteredText))
        RandomItems.Filter = null;
    else
        RandomItems.Filter = (o) => o.ToString()
                  .Contains(EnteredText);

    // Make sure to force a refresh of the view
    RandomItems.Refresh();
}

There is one interesting thing about the above snippet. Notice the lambda expression used to filter takes one argument (“o”), and I just call ToString() on it. Since the PagedCollectionView isn’t templated, the filter delegate is called with an argument of type object. You can then cast that object to whatever type you know the underlying colleciton uses. In this case, I have an ObservableCollection<string>, so I just call the ToString() method.

 

That’s it. It gets even cooler when you start applying sorting, paging and grouping to this view, then bind to it with a DataGrid, or something similar.

 

Avi

Filed under: ,
Useful C# method for unit testing
16 July 09 02:37 PM | Avi Pilosof | 3 Comments   

I’m unit testing a UI that needs to show some lists in various sorted orders, and I wanted to ensure that my tests would cover that. I found this method to come in handy:

 

   1:  public static bool IsOrderedBy<T>(this IEnumerable<T> coll,
   2:                     Func<T, IComparable> val)
   3:  {
   4:      if (coll == null || coll.Count() == 0)
   5:          return true;
   6:   
   7:      var curVal = val(coll.ElementAt(0));
   8:      for (int i = 0; i < coll.Count(); i++)
   9:      {
  10:          if (val(coll.ElementAt(i)).CompareTo(curVal) < 0)
  11:              return false;
  12:   
  13:          curVal = val(coll.ElementAt(i));
  14:      }
  15:   
  16:      return true;
  17:  }

 

Here’s how to determine if a simple array is in order:

var arr = new int[] { 1, 2, 3, 5 };
bool ordered = arr.IsOrderedBy(i => i);

 

Here’s how you’d call it on a more complex object:

var arr = Enumerable.Range(1, 10)
    .Select(e => new
    {
        Name = "bob",
        Salary = 10 * e
    });
bool ordered = arr.IsOrderedBy(i => i.Salary);

 

 

Avi

Filed under:
Silverlight RPG: Steel Saga
24 March 09 03:34 PM | Avi Pilosof | 0 Comments   

My friend Darren who wrote the hilarious Buddy Knavery game has released a preview of his new project called Steel Saga.

http://www.steelsaga.com

It’s an old-style RPG written in Silverlight, and seems quite deep. At the moment there are only two “zones” (one outdoor and one dungeon), but Darren hates having a life, and is going to spend the coming weeks writing plenty more content.

Check it out; I still can’t believe one guy is doing all this work (programming, art, music).

 

Avi

Filed under: ,
Live Mesh Applications – whoah.
17 February 09 08:52 AM | Avi Pilosof | 1 Comments   

I’ve been playing with Live Mesh for a long time now, and have been loving it. During this time I’d been hearing about applications for Live Mesh, and while it sounded interesting in theory I didn’t really get what the point would be.

Then I watched this video:

http://briangorbett.com/mesh/mesh-video-player/

 

The video walks you through the development process of a Live Mesh app. The “whoah” moment is when I realized that the one codebase - without any special code - created an application that ran identically on the web and on the desktop. Money shot starts at about 25:30; but it helps to watch the whole vid.

This is fascinating; this is a “Web OS” (I hate that term).

 

Avi

Silverlight Game Contest: $5000 prize
16 February 09 09:51 AM | Avi Pilosof | 3 Comments   

The site is a little low on details/rules, but the prize seems pretty sweet:

http://www.serverquestcontest.com

 

Filed under:
Be Paranoid. Be Very Paranoid.
03 December 08 01:29 PM | Avi Pilosof | 2 Comments   

Do you maintain an application with a backend database? Does that application ever write to the database? Be afraid.

The worst situation to be in with respect to the above is when a customer mails you and says: “Why is my data gone?”

99% of the time, it’s because they clicked on the “Delete” button; but sometimes you need proof – this is what I want to discuss.

Log every interesting write to the database. There are various levels at which you can do this:

  • Application logic level: This gives you the most context, the most usable logs, and in fact gives you data which can generally be exposed directly to the customer, preventing lots of questions. The problem is that it’s not reliable: The app could succeed in writing then fail in logging. Alternatively, a dev on the app might forget to add logging to a new feature.
  • Application object model level: A little less context/readability than above, a little more reliability.
  • Data-Access-Layer level: Less context than above, more reliability.
  • Sproc level: Same tradeoff.
  • Table level (triggers): And same again.

As you can see, the lower you go, the less chance for error and the less value a log entry gives you. You can increase the value of a “deep” log entry by forcing a set of arguments up the stack. For example, you can force every sproc which writes data to require username/machine/reason arguments – but this can become costly to maintain.

So which is right? Depends on your app, your level of paranoia, your customer’s needs, etc. Generally I stay away from triggers and try to add logging at the sproc level for critical sprocs, and at the app/OM level for extra context; better to have too much logging than too little.

Here’s a nice trick for creating a footprint log table that your sprocs (or triggers) can use quite easily - Create a simple table with the following columns (at least):

 

Name Default value Comment
LogEntry   The text you want to log.
TimeStamp getdate() Automatically fills in the current datetime.
User system_user Automatically inserts the logged in user’s ID.
Machine host_name() Automatically inserts the user’s client machine name.
Application app_name() Automatically inserts the name of the application running this code (provided you set it in the connection string, which you should!)

 

Inserting into this table requires only the one column, but you capture lots of extra data for free. If this is done from a trigger, then you’ll even catch slackers with access to the DB who are updating it manually.

 

Oh, don’t forget to age off old entries before the table ends up at 50GB ;)

 

Avi

WPF: Allow your users to define their own styles using XAML
27 October 08 11:55 AM | Avi Pilosof | 0 Comments   

An application I’ve been working on has the vague property of “displaying items on the screen”, and a fairly unusual requirement which specifies that users be able to completely define how the items look.

Our items are displayed on a timeline and can represent pretty much anything (up to the user), hence the flexibility required for the visuals.

In order to support this, we do the following:

  1. Have a generic class (DataItem) that represents a rendered item and which supports a few basic properties (name, start date, etc).
  2. Support any number of custom properties for that class (stored as an internal collection).
  3. Allow the user to define a “Style name” for any item (think of a CSS style name).
  4. Allow them to define a global list of styles (think of a CSS stylesheet), each with custom XAML.
  5. Allow that XAML to bind to any custom property of an item.
  6. Lookup the style at runtime, load the XAML then display it in the user control.

There are a few small tricks that make this possible:

 

Binding To Custom Properties

Because custom properties on an item are just key-value pairs (in our case, strings), we needed a unified way to read any property (whether native or custom) from an item so that XAML binding could use a single syntax.

First, we create a method on our item class that returns the value of any property:

   1: public string GetFieldValue(string fieldName)
   2: {
   3:     // First attempt to get an actual item property using reflection.
   4:     PropertyInfo prop = typeof(DataItem).GetProperties()
   5:         .SingleOrDefault( p => p.Name.EqualsIgnoreCase(fieldName) );
   6:     if (prop != null)
   7:     {
   8:         object val = prop.GetValue(this, null);
   9:         return val == null ? "" : val.ToString();
  10:     }
  11:  
  12:     // Failing that, attempt to get it from the custom field collection.
  13:     if ( _CustomFields.ContainsKey(fieldName) )
  14:         return _CustomFields[fieldName];
  15:     // Failing that, just return an empty string.
  16:     else
  17:         return "";
  18: }

So now we can get the value of an item’s property whether it’s native or custom – but how do we use XAML data binding to bind to the results of this method? Use a Value Converter:

   1: /// <summary>
   2: /// This takes as a parameter the name of the field to read from the
   3: /// DataItem, and returns the value of that field from the bound-to.
   4: /// DataItem.
   5: /// </summary>
   6: public class DataItemPropertyReader : IValueConverter
   7: {
   8:     public object Convert(object value, Type targetType,
   9:         object parameter, System.Globalization.CultureInfo culture)
  10:     {
  11:         return (value as DataItem)
  12:           .GetFieldValue(parameter.ToString());
  13:     }
  14:  
  15:     public object ConvertBack(object value, Type targetType,
  16:         object parameter, System.Globalization.CultureInfo culture)
  17:     {
  18:         throw new NotImplementedException();
  19:     }
  20: }

Declare an instance of this guy which is app-wide (say, in Styles.xaml):

   1: <!-- This is used by individual DataItems to bind to custom properties in items -->
   2: <MyNamespace:DataItemPropertyReader x:Key="DI" />

And now the users who write the XAML can bind like this:

   1: <TextBlock Text="{Binding Converter={StaticResource DI}, ConverterParameter=Name}" />
   2: <TextBlock Text="{Binding Converter={StaticResource DI}, ConverterParameter=Custom1}" />
   3: <TextBlock Text="{Binding Converter={StaticResource DI}, ConverterParameter=Address}" />

 

Displaying Custom XAML Dynamically

Now it comes time to read this XAML and display it. This has been shown before many times, so I won’t go into it too much. It’s fairly simple; the only trip-ups are name-spaces and data contexts.

At runtime, use user control replaces the contents of its layout as such:

   1: private void RedrawItem()
   2: {
   3:     string XAML = GetXAMLByStyleName( Item.StyleName );
   4:  
   5:     UIElement el = Common.CreateUIElementFromXAML(XAML);
   6:  
   7:     // Remove what was there, and add the new stuff.
   8:     LayoutRoot.Children.Clear();
   9:     LayoutRoot.Children.Add(el);
  10:  
  11:     // Set the context, so that data binding knows
  12:     // what to look at.
  13:     LayoutRoot.DataContext = this.Item;
  14: }
  15:  
  16: public static UIElement CreateUIElementFromXAML(string XAML)
  17: {
  18:     // Wrap the XAML in a grid, to guarantee one root element
  19:     XAML = string.Format("<Grid>{0}</Grid>", XAML);
  20:  
  21:     byte[] XAMLbytes = System.Text.Encoding.UTF8.GetBytes(XAML);
  22:     MemoryStream memstream = new MemoryStream(XAMLbytes);
  23:  
  24:     // Can only load the XAML if we know about the right namespaces.
  25:     // (You'd do well to centralize this bit of code)
  26:     ParserContext pc = new ParserContext();
  27:     pc.XmlnsDictionary.Add("",
  28:       "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
  29:     pc.XmlnsDictionary.Add("x",
  30:       "http://schemas.microsoft.com/winfx/2006/xaml");
  31:     pc.XmlnsDictionary.Add("mc",
  32:       "http://schemas.openxmlformats.org/markup-compatibility/2006");
  33:     
  34:     UIElement el = (UIElement)XamlReader.Load(memstream, pc);
  35:     return el;
  36: }

As for performance; it’s not too bad. My app doesn’t need to do this for more than a few dozen items, so we haven’t really pushed it.

 

Avi

Filed under:
WPF: Supporting command line arguments and file extensions
27 October 08 11:05 AM | Avi Pilosof | 1 Comments   

Traditionally, handling command-line args in an app has been a simple case of reading arguments from the “int main()” function (or equivalent). In WPF this changes somewhat.

The usual setup is that you have your App.xaml.cs, which loads your initial window. While it’s the former that  has access to the arguments, it’s the latter that is likely to use them. So the steps are:

  1. In App.xaml.cs, catch the event that gives you the args.
  2. Store them somewhere.
  3. Access them from your main window.

Here’s one way to do it (demonstrating a single argument). Firstly, in App.xaml.cs:

   1: protected override void OnStartup(StartupEventArgs e)
   2: {
   3:     if (e.Args != null && e.Args.Count() > 0)
   4:     {
   5:         this.Properties["ArbitraryArgName"] = e.Args[0];
   6:     }
   7:  
   8:     base.OnStartup(e);
   9: }

Then in the main window, you can access Application.Current.Properties to get at your args. However, if this happens to be the name of a file you want to load, you should probably wait until after your window has finished loading so that you can react to that file load (eg; give an error, display data, etc):

   1: public MainContainer()
   2: {
   3:     InitializeComponent();
   4:  
   5:     // Make sure we handle command line args:
   6:     this.Loaded += new RoutedEventHandler(MainContainer_Loaded);
   7: }
   8:  
   9: void MainContainer_Loaded(object sender, RoutedEventArgs e)
  10: {
  11:     if (Application.Current.Properties["ArbitraryArgName"] != null)
  12:     {
  13:         string fname = Application.Current.Properties["ArbitraryArgName"].ToString();
  14:         // Act on the file...
  15:     }
  16: }

 

Launching via a double-click on a custom file type.

I created an application that supports a custom document format and I wanted a double-click on that document to open my application. I assumed that the application would open normally with the document presented as a command-line arg, but that’s not the case. Instead, it’s stored in the following tongue-twister:

AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0]

So, if you revisit the OnStartup method in App.xaml.cs, you can query this location and store it in the same way you did the command-line arg:

   1: protected override void OnStartup(StartupEventArgs e)
   2: {
   3:     // Check if this was launched by double-clicking a doc. If so, use that as the
   4:     // startup file name.
   5:     if (AppDomain.CurrentDomain.SetupInformation
   6:         .ActivationArguments.ActivationData != null
   7:     &&  AppDomain.CurrentDomain.SetupInformation
   8:         .ActivationArguments.ActivationData.Length > 0)
   9:     {
  10:         string fname = "No filename given";
  11:         try
  12:         {
  13:             fname = AppDomain.CurrentDomain.SetupInformation
  14:                     .ActivationArguments.ActivationData[0];
  15:             
  16:             // It comes in as a URI; this helps to convert it to a path.
  17:             Uri uri = new Uri(fname);
  18:             fname = uri.LocalPath;
  19:  
  20:             this.Properties["ArbitraryArgName"] = fname;
  21:  
  22:         }
  23:         catch (Exception ex)
  24:         {
  25:             // For some reason, this couldn't be read as a URI.
  26:             // Do what you must...
  27:         }
  28:     }
  29:  
  30:     base.OnStartup(e);
  31: }

Notice the little trick with using the “Uri” class; this is because the string you’ll see will look like this:

file:///c:/temp/my%20test%20doc.blah

 

Avi

Filed under:
You’re asking for the wrong thing.
16 October 08 08:50 AM | Avi Pilosof | 7 Comments   

Just stumbled upon this article by John Dvorak titled “My Windows 7 Wish List”, and I see the same pattern as many of the other fruitless wish list articles. Maybe IHBT

As a user, the user experience (UX) is the only thing that ever matters to you – the implementation is never the issue.

Take for example item (1) on the list:

“Build a new file system based on database technologies”. Why do you care about how the file system works internally? Do you actually want a file system with a DB in the backend, or do you just want to be able to run fast, useful searches? My guess is that it’s the latter.

Another one:

“Get rid of the miserable registry”. Is it the registry you care about, or the fact that it’s difficult to upgrade/migrate?

Another:

“Get off the cloud”. You’re worried that “suddenly the machine wants to contact the Internet for some reason or other”. This has nothing to do with the “cloud strategy”; you just want a machine that doesn’t use the network. Or something. I don’t really know based on that rant :)

 

Alternatively just read this:

http://shippingseven.blogspot.com/2008/07/20-features-windows-7-should-include.html

 

Basically (and I’m talking about customers in general – not just MS/Windows) people often request implementation changes, but what they really want are UX changes. Do you want a powerful engine, or just a fast car? Do you want high carbon steel, or just a knife that’s very sharp and stays that way? Do you really care how the sausage is made? ;)

 

As a customer, it’s important to understand what you actually want since it makes it much easier to ask for it (and hence get it).

 

Avi

Trivial but useful extension method
30 September 08 04:34 PM | Avi Pilosof | 3 Comments   

Don’t know why I didn’t write this before; it makes code very readable. Often when you write anything graphics related, you want to constrain coordinates to window edges (for example).

So a simple method:

   1: /// <summary>
   2: /// Ensure that the given number falls within the
   3: /// given min/max constraints.
   4: /// </summary>
   5: public static double Constrain( this double num,
   6:                         double min, double max )
   7: {
   8:     if (num < min)
   9:         return min;
  10:     else if (num > max)
  11:         return max;
  12:     else
  13:         return num;
  14: }

It’s just a Floor combined with a Ceiling, but it reads nicely:

   1: xform.X = dx.Constrain(-this.ActualWidth, 0 );
   2: xform.Y = dy.Constrain(-this.ActualHeight, 0 );

 

Avi

On using Arrays
23 September 08 11:52 AM | Avi Pilosof | 0 Comments   

Eric Lippert has a great article on arrays:

http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx

 

I think this is especially useful to consider if you’re writing an API. Consider not just arrays, but any time you’re returning any collection: Are you returning values or a variables? Did you mean to?

 

Avi

Microsoft Bacon Home Edition, RC0
11 September 08 06:39 PM | Avi Pilosof | 2 Comments   

Totally unrelated to programming, but I deem this worthy of a blog post. A few weeks ago I decided to make my own bacon.

 

Why? Don't ask stupid questions; bacon is an axiom.

How? turns out that it's actually not so complex:

  1. Buy some pork belly.
    • Any butcher (even the one inside the supermarket) will be able to get you a piece. I used about 1.5Kg worth (~3lbs).
  2. Brine it for a week in the fridge.
    • I used salt+sugar+pepper. Next time I'll add honey or maple syrup.
  3. Smoke it.
    • I had a little trouble here, since I don't have anything resembling a smoker. Next step is to build one.

The details are in this great book, and I recommend that you read it before you accidentally make your own botulism. The truth is that I didn't, but only because the bookstore was out of stock! But seriously, there are risks involved - the fridge temperature has to be just right.

Here are some photos from the adventure:

Before the brine

Salting the meat

The Poor-Man's Smoker. Yes, that's just a cast iron pan with wood in it.

Removing the skin

Sacrificial tasting slice

 

How was it? Delicious. You can slice it thick, giving a good combination of crunch and chew.

My next project will either be some salami, or perhaps a more complex Silverlight physics sample. Depends on how hungry I get, and whether the book store can get that Charcuterie book in stock!

 

I'm so hungry now.

 

Avi

Computer Programming isn't Art
25 August 08 01:24 PM | Avi Pilosof | 6 Comments   

(Sorry, Mr Knuth)

My uncle's hobby is building beautiful furniture from wood. I noticed something last time I spoke with him about it: He doesn't talk about a table, or a book case, or a dresser; at least, that's not what he talks about with emotion. You only get a sense for what he loves doing when he describes how everything fits together, how he makes it. He cuts and dries trees to make the timber, he cuts it all down to size, and then he never use screws or nails - all the joints fit perfectly.

Similarly, when I talk to my colleagues about software that they're writing, they might be excited about what the software does, but they're more interested in discussing how it does it, how they put it together. They're proud of code which is efficient, clean, inventive, performant. A crafty data structure, a SQL query which performs 10x faster than its predecessor, an intelligent cache that cuts processing requirements by 80%. Those are cool - those get you the street cred :)

I see large parallels between the two. They don't fit my understanding of what "Art" is; they sound alot more like a craft. Art is about evoking and exploring emotion, about connecting with the viewer. When I hear "craft", I think of a blacksmith, a woodworker, a chef; someone who takes pride not just in the end result, but in the path used to reach it. It's not just about creating something nice, it's also about doing it with pride. This seems to fit more closely to the practice of writing software, to the constant need for study and improvement that characterizes it. At least; those are the kinds of engineers I would prefer to work with.

 

Avi

 

Back in Seattle
18 August 08 02:19 PM | Avi Pilosof | 0 Comments   

I recently came back from visiting Seattle (where I'd lived and worked for 7 years before returning to Sydney). My wife was presenting at TechReady, so I figured I'd hitch a ride and make a vacation of it. It was also a good opportunity to meet up with my team and try to remember what their faces looked like :)

Random thoughts from the trip:

  • The Pacific Northwest is just stunning in summer. Mind you, I'm not convinced that cold and grey for 7 out of 14 days should really qualify to be called "Summer".
  • Due to TechReady, downtown Seattle was packed with MS nerds from all over the world; Almost 6000 from what I heard. It was definitely evident when walking around in the morning and seeing a whole sea of TechReady badges converging on Pine St. It was also weird seeing restaurants and pubs packed on weekday evenings. The city seemed to have a little more vibrancy to it.
  • In what might be the coolest technological feat I've seen since the Amiga, building 41 (and probably the rest) now has tiny touch-screen LCDs outside every conference room. You can see who's supposed to be there, find a replacement room, etc. They even make beeping noises.
  • Microsoft is going even greener: The new eating utensils are all bio-degradable. I'm told that the forks/knives/spoons are made from a weird mixture of potatoes and/or corn and/or interns. They definitely have a faint smell of corn oil (interns?), but contrary to what I was told I couldn't get them to melt in either hot water or diet coke. Judging by the latter experiment, perhaps NASA might have a new material for the Shuttle's construction?
  • Downtown Bellevue looks like Dubai, and areas around the main MS campus are similarly festooned with cranes. The amount of construction going on in the area is scary.
  • In the past 5 years or so, my weight has fluctuated between about 170 and 171 lbs; even on vacation; even when being force-fed by in-laws. However, after 2 weeks in Seattle of hanging out with friends who have an inhuman capacity for drinking beer, I suddenly find myself about 7lbs heavier. Ouch.

It was a great trip, great to see the old friends, who now need to plan a trip to Sydney :)

 

Avi

Search

This Blog

Syndication

Page view tracker