Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Monday, May 12, 2008

Why I hate Frameworks: from hammer to "general-purpose tool-building factory factory factory"

A recent discussion with a smart guy reminded me of an article I read years ago. I wanted to think I read it on Joel on Software. I wanted to think it had something to do with "hammer factories".

Google did the rest.

The write-up, Why I Hate Frameworks comes from Joel's discussion group. Written by Benji Smith.

"So, instead, we started selling schematic diagrams for hammer factories, enabling our clients to build their own hammer factories, custom engineered to manufacture only the kinds of hammers that they would actually need."

"Let me guess. You don't sell those anymore."

"Nope. Sure don't. As it turns out, people don't want to build an entire factory just to manufacture a couple of hammers. Leave the factory-building up to the factory-building experts, that's what I always say!!"

Like most good content on the internet, brilliant and hilarious.

Friday, March 14, 2008

Reader Question: "Why WrapperElement<T> instead of Decorator?"

Yuval, via a comment, asks:

Can you explain why you chose to define WrapperElement<T> instead of simply inheriting from Decorator? They seem to be doing the same thing.

Ah, it is good to read my post "Don't subclass a Panel, unless you're making a Panel".

First, where do I used WrapperElement<T>? Well, at the moment, it's used in three places: FlipTile3D, Set, and Transition3D. In all cases it simply wraps a Viewport3D.

Now, could I simply use Decorator? Sure. I could subclass Decorator and do basically the same thing. Even easier: I could subclass Viewport3D.

Why don't I?

It's all about API usability and correctness.

When I write a control (especially for the bag-o-tricks) I try to make it "right".

If these controls subclassed Viewport3D, they should act like Viewport3D. Meaning, they should support someone added arbitrary lights, models, etc. They should support messing with and removing elements that are already added.

I don't want this.

Wrapping everything with a Decorator, just exchanges problems.

If I subclass Decorator, it would imply that I mean people to treat the control like a Decorator, which means accessing and changing the Child property.

I don't want this, either.

WrapperElement<T> does some very simple things.

  • Stores a Framework element as a child visual.
  • Adds it to its visual tree (via AddVisualChild)
  • overrides GetVisualChildCount
  • overrides VisualChildCount
  • overrides MeasureOverride
  • overrides ArrangeOverride
  • Provides protected access to the child so the subclass can play with it, but not the end user.

One should use WrapperElement<T> when one wants to use the implementation of an existing component--Viewport3D, Grid, etc.--but doesn't want the object model of that component exposed.

Make sense?

Thanks for the question, Yuval.

Happy hacking.

Wednesday, March 12, 2008

Consolas: the Coder's Font

Consolas is one of a set of new ClearType fonts that shipped as part of Windows Vista and Office 2007.

It's absolutely beautiful. I love to code in it.

The problem: no applications seem to be smart enough to use it by default. In this post, I'll go through all the places I use monospaced fonts

Visual Studio

Tools->Options->Environment->Fonts and Colors

Set "Plain Text" under "Display Items" to Consolas.

image

Firefox

Tools->Options

Under the Content tab, in the "Fonts & Colors" box, pick "Advanced". In Monospace, pick Consolas.

image

Internet Explorer

Tools->Internet Options

General tab, under Appearance, pick 'Fonts'.

Under "Plain text font:" pick Consolas.

image

.NET Reflector

View->Options

Under 'Appearance', 'Code Font': Consolas.

image

CMD.EXE

(Thanks to Walter for pointing this out to me.)

Yes, even the command window. If you're running Vista, make sure to run this command 'elevated'. You'll have to restart your machine before the setting takes effect.

reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" /v 00 /d Consolas

image

Next, right click on the command window header and pick 'Properties'. You'll probably want to up the font size, too.

image

And there you go. All your most important applications using the nicest monospaced font.

Happy hacking!

Saturday, March 8, 2008

Bag-o-Tricks March '08 Edition

January 12 was my last update to the bag-o-tricks. I couldn’t let two months go by without another refresh. There is a lot of stuff here I've already talked about. The code has been available via SVN for a while, but not in the convenient package.

The Goods

Binaries and Source [zip, 4.17MB]. Tested with Visual C# Express 2008.

The Details

  • VS Copy-to-HTML - New!
    • Blogged about it here.
  • NotifyWorker - New!
    • Blogged about it here.
  • HueConverter - New!
    • Makes it easy to create a pretty spectrum of colors for a number of items
  • Animating Tile Panel
    • Renamed AnimateNewItem property to AnimatesNewItem
    • Made initial load not animate new items
    • Polished the demo code
  • CompositionTargetRenderingListener
    • Added Dispose and used it where appropriate
    • Added WireParentLoadedUnloaded helper method
  • DemoCollection
    • Added Reset command
    • Moved to library assembly
  • Extentions
  • FlipTile3D
    • Moved to WrapperElement<Viewport3D>
  • FolderPicker
    • Moved to new SelectRecursive implementation
  • WPFUtil
    • Added HSB-RGB converter
    • Created ‘Animate’ methods to abstract physics model. Moved FileTile3D, AnimatingTilePanel, and ZapDecorator to these.
  • ZapScroller
    • A lot cleaner. Removed a completely unnecessary layer of complexity.
    • Added the ability to template the buttons. Thanks for the suggestion, Atul.
  • WPF Set
  • General
    • A bunch of renaming of namespaces. Most of the new stuff will exist under J832.Wpf

As always, the SVN location has been updated. Patches are always welcome. (I've had one taker on this. Very cool to do an apply patch. Would love to do it again.)

Enjoy and happy hacking!

Tuesday, January 22, 2008

Responsive UI with Unresponsive Data: NotifyWorker

Yes, I finally got off my SelectRecursive kick. This is penance.

The 3-box Visio Diagram

How many user interfaces do you design that follow this pattern?

image

Okay, almost all of them.

A frequent refrain from users (well, at least me):

Regardless of what you're doing behind-the-scenes, the interface should never hang, stutter, or lag. Ever.

Easily said, right?

Well, while hacking on one of my side projects, I ran into this problem.

I put on my "framework guy" hat and asked, "Can I formalize this into a pattern?"

My answer: NotifyWorker.

Now before I get into NotifyWorker, I should mention BackgroundWorker: a frequently used and well thought-out component supplied by our friends in the Baseclass Library (BCL) for this kind of thing.

The trick performed by BackgroundWorker is simple, but important: allow start/stop/cancel of a task on another thread. It also keeps developers sane who have to deal with strict rules about what can only be done on the UI thread.

The type of tasks for which NotifyWorker was designed fit into a special niche that I think BackgroundWorkre misses:

  • Tasks that are long enough to lag the interface (0.1+ seconds) but are too short to require tracking of percent complete (so shorter than, say, 5 seconds).
  • Tasks that are repeated constantly as the UI updates. Think of recalculating a math/physics model or checking a server-hosted word list for a type-a-head find control.
  • Tasks where the work to be done is--in relative terms--longer than the work to update the user interface. If the task takes 0.1 seconds, but updating the 1,000 controls in your window takes 2 seconds, you should start by tweaking your architecture before using NotifyWorker.

How does it work?

(Reflector is how I learn all of my new APIs.)

image

The constructor takes three parameters that outline the diagram above and the workings of NotifyWorker:

  • Func<bool> prework: this is a delegate that is called on the Dispatcher (UI) thread in a WPF application. Delegate passing is a trick I use a lot, and you should, too. The method does the work to take interesting parameters from the UI (control values, etc.) and puts them in a spot where NotifyWorker can safely play on a non-UI thread. If you decide there is nothing interesting to do, you can return false, telling NotifyWorker "never mind".
  • Action work: this is where the magic happens. This function is called on a background thread which will leave your UI nice and responsive. Be super careful that 'work' only touches state (fields, etc) that you've safely set aside during prework.
  • Action postWork: the last box in our diagram. It takes the work done in 'work' and updates the UI accordingly. This method, as well as 'preWork', synchronizes the UI and background threads, so you don't have to worry about locking.

How do you kick things off? Call NotifyNewWork. This method can be called often, if you want. Put it in the 'Changed' handler of your favorite Slider or TextBox. If NotifyWorker is idle, it will wake up and immediately call preWork. If NotifyWorker is busy, it'll loop right around to get new input values as soon as postWork is done.

A demo

image

Sexy, huh?

The scenario is simplistic and contrived, like so many good demos.

Both sets of UI do the same thing: take the values from two sliders and sum them. Not too complicated.

For some strange reason, the sum 'routine' takes 0.25 seconds to return a result.

Maybe it's that new math...

Eh, it's probably the Thread.Sleep(250) I put in the method.

Anyway, use your imagination. You'll notice that the 'slow' UI is, well, slower. It lags a bunch as you drag the sliders since it's calling the expensive sum method on the UI thread.

The NotifyWorker controls do much better because the expensive call is hidden off-thread.

Simple, but useful.

Odds and ends

You'll notice a LastClientExceptionEventArgs property and a ClientException event. These are designed to make it a bit easier to handle non-critical exceptions during 'work'. The demo code actually shows this off pretty well.

You'll also notice that NotifyWorker implements IDisposable. Dispose will make sure to end any background work when you're done with NotifyWorker.

Under the covers, NotifyWorker uses LockHelper and some of the pulse/monitor tricks I wrote about a few months ago.

That's about it.

Since NotifyWorker is hard-wired to the notion the Dispatcher, it lives in J832.Wpf.BackOTricksLib. The demo is in the Bag-o-Tricks app under NotifyWorker.

I'm not going to do an official release (zip with binaries/source) of the bag for this sample. It's cool, but not cool enough to warrant a whole new drop.

It also gives you an excuse to play with SVN, if you haven't already. You can always just manually download the code from my SVN share using your browser, too.

Let me know if this works well for you.

 

Happy multi-threaded hacking!

 

Note: I've had some funky auth issues with Firefox on the SVN server lately. Let me know if you have any trouble.

Friday, January 18, 2008

Recursion, Linq, etc. - 3rd Times the Charm

The joke about Microsoft is that it always takes them three times to get it right.

If you look at my posts on the game Set in WPF, it would seem I follow the same pattern.

Well, here I go again.

Let's start simple: I have a path to a directory and I want to enumerate over all of it's subdirectories recursively. To be super concrete:

string[] startPaths = new string[] { @"D:\j832_svn\PublicSoftware\" }; 
IEnumerable<string> subPaths = SelectRecursivePaths(startPaths);

Easy enough.

What's the scenario-specific implementation of SelectRecursive? Well, our friend System.IO.Directory provides what we need.

private static IEnumerable<string> SelectRecursivePaths(IEnumerable<string> paths)
{
    foreach (string path in paths)
    {
        yield return path;
        foreach (string subPath in SelectRecursivePaths(Directory.GetDirectories(path)))
        {
            yield return subPath;
        }
    }
}

This code does the job for doing an in-order, recursive traversal of all of all of the directories. But it isn't very Linq-ish, is it?

Getting Linq-ish: SelectRecursiveSimple

Could there be a way to extract out the call to Directory.GetDirectories such that this method could be used over any homogenous, hierarchical structure? Yup.

public static IEnumerable<TSource> SelectRecursiveSimple<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TSource>> recursiveSelector)
{
    foreach (TSource element in source)
    {
        yield return element;
        foreach (TSource subElement in recursiveSelector(element).SelectRecursiveSimple(recursiveSelector))
        {
            yield return subElement;
        }
    }
}

Now we change the call site to embody the call to GetDirectories:

IEnumerable<string> subPaths = startPaths.SelectRecursiveSimple(path => Directory.GetDirectories(path));

I love lambda expressions and extension methods.

With me so far?

Getting Clever: SelectRecursiveClever

Now we go back to my clever idea from Tuesday and Wednesday about flattening recursion. The code I ended up with:

public static IEnumerable<TSource> SelectRecursiveClever<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TSource>> recursiveSelector)
{
    Stack<TSource> stack = new Stack<TSource>();
    source.Reverse().ForEach(stack.Push);
    while (stack.Count > 0)
    {
        TSource current = stack.Pop();
        yield return current;
        recursiveSelector(current).Reverse().ForEach(stack.Push);
    }
}

Note: ForEach is an extension method I created that does what Array.ForEach does: calls an Action<T> delegate on each item. In this case, pushing every item in the sequence into the stack.

Now the caller-side behavior of this is exactly the same as the "simple" version above. The implementation tries to be "clever" though, by discarding the "naive" use of recursion by replacing the call stack with a local stack. I was quite proud of this implementation. As I said on Tuesday:

If you can flatten a recursive implementation, you will have a better understanding of what's really going on under the covers.

Gulp. Perhaps I spoke to soon.

The Problem with Clever

I showed a co-worker this code. It took a bit of work to explain the use of .Reverse(). Stacks are Last-in-first-out, so if you want to get the first item out first, you have to put it in last.

Explaining this hurt my head a bit. In the "simple"--read "naive"--implementation, one didn't have to reverse the enumeration. Why should the flattened version be different?

The answer: it shouldn't.

At some point in the "clever" implementation, every item is on the stack. This means if you have a very wide tree, the stack could grow to be huge.

Imagine your recursiveSelector is smart about not loading all items at a given level into memory at one time--the benefit of sequences, right? It doesn't matter, because SelectRecursiveClever will load everything in one level into a stack. It trades the potential benefit of a smaller call stack with the potential blow-up of your working set when iterate over a folder with 10,000 sub-folders.

Oops.

You have to keep track of your depth in the recursion somewhere: either the runtime stack or your own stack.

But all you have to keep track of is where you are in each sequence at each level. You don't have to queue up all of the items at a given level.

Turns out the CLR has this obscure feature to handle this: IEnumerator<T>.

Yeah, not so obscure.

It's actually what the simple version of this code does. When you call down into the nested SelectRecursiveSimle, an IEnumerator<T> will be waiting patiently at the the current spot for the call to return.

Getting Smart(er): SelectRecursive

The code is more ugly, but it also does a better job of illuminating what is happening in the truly recursive, "simple" version.

public static IEnumerable<TSource> SelectRecursive<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TSource>> recursiveSelector)
{
    Stack<IEnumerator<TSource>> stack = new Stack<IEnumerator<TSource>>();
    stack.Push(source.GetEnumerator());

    while (stack.Count > 0)
    {
        if (stack.Peek().MoveNext())
        {
            TSource current = stack.Peek().Current;
            yield return current;
            stack.Push(recursiveSelector(current).GetEnumerator());
        }
        else
        {
            stack.Pop();
        }
    }
}

2008-01-19: Turns out this code is wrong, too.

The stack now holds on to what it should: the IEnumerator<T> at each level. The while loop runs through IEnumerator<T>.MoveNext(), going deeper with every stack.Push() until there are no more items and then "returning" with stack.Pop().

Popping the stack

It's pretty easy to implement a recursive construct using Linq. The first "simple" implementation works great and it's really useful when partying over the file system or any other hierarchy.

I still claim that flattening recursive code is a good thing to do for reasons I mentioned on Tuesday.

Just make sure you do it correctly.

Put another way: pay attention to your masters.

If you can't be smart, be simple.

Don't ever be clever.

Clever will burn you.

 

Happy hacking.

 

kick it on DotNetKicks.com

PS: SVN has been updated again with the latest code. Hopefully the last time I'll touch RecursiveSelect for a while.

Tuesday, January 15, 2008

Flattening recursive algorithms is like taking the stairs...

...it's rarely necessary, but you'll be better for it.

Okay, a forced analogy.

2008-01-19: I've learned a lot since Tuesday. Please read!

I'm sure many remember their first algorithms class and their first introduction to recursion: the infamous Tower of Hanoi problem. I'd been coding for a while when I was presented with this puzzle and wondered (probably out loud), "Why don't we use a more concrete example, like the file system?"

I guess I've always been more of a software engineer than a computer scientist.

While the idea of recursion is useful in many situations, the costs are rarely discussed. As our friends at Wikipedia mention:

...in today's programming languages, the stack space available to a thread is often much less than the space available in the heap, and recursive algorithms tend to require more stack space than iterative algorithms.

Well said.

I was hacking on some work stuff that required recursion-- specifically flattening a hierarchy. I realized I'd done this before, in the bag-o-tricks. I also realized how expensive it was.

Call stack for recursive function call

Not only was I paying in call stack space for every nested call, but I was also allocating a lot of enumerators.

Code for the SelectedDirectories getter.

if (m_directories != null)
{
    foreach (SelectableDirectory sd in m_directories)
    {
        if (sd.IsSelected)
        {
            yield return sd;
        }
        foreach (SelectableDirectory sd2 in sd.SelectedDirectories)
        {
            yield return sd2;
        }
    }
}

So how does one improve this? Replace the call stack with your own stack.

Stack<SelectableDirectory> directoryStack = new Stack<SelectableDirectory>();
directoryStack.Push(this);
while (directoryStack.Count > 0)
{
    SelectableDirectory currentDir = directoryStack.Pop();
    if (currentDir.m_directories != null)
    {
        for (int i = (currentDir.m_directories.Count - 1); i >= 0; i--)
        {
            directoryStack.Push(currentDir.m_directories[i]);
        }
    }
    if (currentDir.IsSelected)
    {
        yield return currentDir;
    }
}

The savvy reader will notice that the second implementation is slightly different: the target node is included if it is selected. Just a detail.

So, what has improved? Only one enumerator is created. The call stack space for the recursion is also eliminated. The cost is the creation of the local Stack<> to keep track of the location in the hierarchy, which is likely much smaller than the space required for a call stack frame.

Since we want to keep the original order of items returned, we also have to Push each level of directories into the Stack in reverse order, so that the Stack returns them in the original order.

Now how does this match up with our masters?

It's certainly less readable. Since the code's not documented, it would probably take longer for even a savvy dev to figure out what's going on. This means it's less maintainable--certainly a negative.

On the plus size, the scalability of this algorithm is now limited by the size of the heap, which is much larger than the call stack. This only matters if one plans to parse very deep directory structures, though.

Another plus is likely performance, since fewer objects are instantiated and the cost of manipulating a local Stack<> is likely much cheaper than churning the call stack. I say 'likely' because I'm not really sure. I should absolutely measure the performance to be certain. Even then, the perf gain is likely trivial unless this code is called a lot. In that case, it might make sense to cache the result of the method.

In the end (and as always), context really matters. I think this is a good exercise to understand the costs and to challenge one's understanding of recursion. If you can flatten a recursive implementation, you will have a better understanding of what's really going on under the covers--something that is always useful.

Happy hacking!

Note: the updated code for Folder Picker has been committed to the bag-o-tricks directory in my SVN repository. You can take a look at the old implementation using Tortoise. Right-click on Data.cs in the shell. Pick 'Show log' out of the Tortoise menu. Then right-click on revision 58 and pick 'Update item to revision'.

Update to revision

Tuesday, January 8, 2008

WPF Set - This is a good stopping spot

WPF Set - 2008-01-08

  • The graphics pretty much match the actual game now.
  • Moved the New Game button to minimize accidental clicking.
  • Some small tweaks to the game logic.

URLs are the same as before:

Bleh! The third night this darn game has kept me up past midnight. I need another hobby.

Sunday, January 6, 2008

The Game "Set" in WPF (Redux)

Yesterday (well, early this morning) I posted my first stab at the game Set implemented in WPF.

Amazing what 20 hours of bake time can do.

  • Removed insanely complex and unnecessary optimization that made the code for SetGame.TryPlay almost un-readable.
  • Cleaned up the 'test' mode by removing it. If you build/run DEBUG, you'll get a Test button. If you build/run RELEASE, you won't.
  • Used binding in the WPF app where it makes sense.
  • Added a bunch of caching to the card generation on the WPF side. Re-creating a bunch of brushes and pens is silly.
  • Added a test project: WpfSet_Test to run the data model through its paces.
  • Fixed deployment to actually use Visual Studio Deploy functionality. (Yesterday, I just uploaded the files from the build directory.) If you accessed the XBAP yesterday, please refresh and make sure the title says at least "WPF Set - 2008-01-06" and not "WPF Set - 2008-01-05." If refreshing doesn't move you beyond 2008-01-05, there is something fishy with your application cache. Drop me a line and I'll try to fix it.

The XBAP URL hasn't changed.

I've combined the source and binaries into one zip file [53KB]. I've always thought having dated copies of files was goodness, but then I realized if someone links to the old version, they'll never get updates. I'm going to try to keep an updated read-me in the zip file so folks know what version they've downloaded.

As always, send me an email or a comment if you have questions.

Happy Setting.

The Game "Set" in WPF

Update - 2008-01-06: See this post for new details. Links below have been changed.

In theory, I have so many more important projects to work on. This was one of those ideas that got legs faster than I realized I should be working on something else.

If you haven't heard of Set, check it out company site or the Wikipedia entry.

WPF Set - 2008-01-08

Building the data model was half the fun. This is some of my first code that uses Linq features from .NET 3.5. I'm blown away. Without a doubt as big as generics. Wow!

The UI is super minimal and that was the goal. Get it all working and ponder prettier/sexier things later.

So, if you want to play:

As I've discussed before, you can also take a look at the source on my SVN share using you favorite SVN client.

Future ideas:

  • Add a timer and a notion of players. I think I'd layer this on top of the existing game model to keep things simple and clean.
  • It would be cool to layer a 3D UI on top of the game model, too. I have some crazy ideas based on the Flip3D stuff from the bag-o-tricks.

Hope you enjoy it!

Note 1: Thanks to Karen for the details on making an XBAP project.

Note 2: I'll give a cookie to anyone who sends me an SVN patch that fixes the shapes so they match what's really in the game. (Drop me an email via the link on the right.) 2008-01-08: No cookie for you.

Other bug fixes are always appreciated.

Saturday, December 29, 2007

When you code, do you know your Master(s)?

Master Chief - Everyone's MasterThere are a whole set of blog posts floating around my head. Discussions of immutability, pre-condition checking, etc. I realized I needed to cover a meta-topic first: the notion of "masters" while programming.

This is a concept I think everyone has, but for most, it remains fuzzy, undefined and un-discussed--which is fine, if you work by yourself.

As I've dived into the software engineering role in the last few months, I've been required to justify my implementation decisions and opinions with co-workers. Given the seemingly limitless ways in which one could solve a given problem with a file full of curly braces and semi-colons, why did I choose the approach I did? Why do I want to change a bunch of existing code? Why am I asking my colleagues to change how they write software?

When it's a simple matter of "does it work or not" there isn't much of a problem, but as many know, writing solid code goes well beyond getting things to build and run.

So, what drives how you write software? When you are at a cross roads (with a co-worker or even with yourself) about how to approach implementation, what guides your discussion? These are your masters.

Examples:

  • Minimize code size
  • Minimize code complexity
  • Minimize unnecessary code churn
  • Maximize code readability
  • Maximize correctness
  • Maximize robustness
  • Maximize flexibility
  • Maximize code maintainability
  • Maximize CPU performance characteristics
  • Maximize Memory performance characteristics
  • Maximize API ease-of-use
  • Maximize the chance another dev will use an API correctly (see Pit of Success)
  • Opt for immutable data structures
  • Opt for thread-safe data structures and APIs
  • Verify pre-conditions
  • Follow design guidelines
  • Get it done yesterday!

And none of these have anything to do with solving the problem at hand. They are, for lack of a better term, taxes. Well, except for get it done yesterday.

Some observations:

1) Many (Most? All?) of the masters conflict with at least one other master. CPU vs Memory performance is a trade off for many algorithms. Performance optimizations often hurt code readability. API ease-of-use often bumps up against immutability and thread safety. Therefor...

2) Context really matters. This is an important point to bring up when discussing with co-workers. In this situation, which master is most important?

3) When making your case in a disagreement, make it in terms of the masters you are prioritizing in a given situation. If someone doesn't understand the importance of--say--immutability, you'd better be able to articulate it.

4) Speaking in terms of masters makes everyone a lot more sane. How often have implementation discussions turned into irrational arguments? Using a master-focused format, I've found disagreements turn into pretty simple cases of a disagreement about the relative importance of two masters. Other times, it's a matter of agreeing on an exception to general rule. "While in general, Master A is more important than Master B, in this situation, we should prioritize B because of X, Y, Z..."

5) "Fake" masters get exposed--vices wearing the mask of a real master. This is amazingly important, too. Lazy often wears the mask of code size or get it done yesterday. Clever often wears the guise of unnecessary flexibility or performance improvements, while increasing code complexity and decreasing code readability. (I'm often guilty of this.)

So...

Next time you are struggling with several valid ways to implement something, make the mental check-list: what masters am I serving with each implementation? What masters are really important in this situation?

Next time you disagree with a co-worker about an implementation, ask yourself: what masters is she arguing for? What masters am I arguing for? What masters really matter? Maybe step back a bit and talk through your respective masters and make sure you both understand before you dig in.

Next time you are trying to get it done yesterday, ask yourself: am I just being lazy? :-)

Happy hacking...

Note 1: Huge props to my co-worker, David Potter. A more brilliant, friendly, and fun colleagues I could not ask for. We've been using this master-focused mind set for weeks now and it makes collaborating a blast.

Note 2: I always get a little nervous posting these long, pseudo-philosophical rants with no source code. As always, if you write a comment saying you read this far (and you don't think I'm crazy) you'll make my day.

Thursday, December 20, 2007

Bag-o-Tricks Christmas Edition

Here's a token gift from me to you. An update to the bag-o-tricks. No earth-shattering features, but a bunch of clean-up. I've made everything work under VS 2008 and rolled up a bunch of common files under a 'common' assembly.

I've renamed the assemblies so it's easy to keep track of what comes from me--everything starts with J832.

I've also done some tweaking so that, by default, images are picked up from the users image folder on XP. You can still override this with a command line parameter.

As I hinted to with my post about TortoiseSVN, I've also put all of my code up on an SVN share: j832.com/PublicSoftware.

I'll try to make sure that the bits I check-in are at least building, but no promises. If you want to fix any bugs and send me the patch, I'd love to try it out. Promise that it's your own code and that you're willing to license your work under the MIT License. You can find my email address on my blog.

Happy hacking and happy holidays!

Monday, December 10, 2007

TortoiseSVN Rocks!

Yes, I'm considering writing a book: "Kevin Explores Things That Rock".

My company uses Perforce for source control. It works pretty well (although there is no shell integration and the Visual Studio integration is a bit flaky.)

I have my own projects on the side that I'd like to managed with source control. These are both code projects and non-code (poetry, screen plays, other writing) projects. Like I said, anything that I want backed-up, synced and versioned.

If you're like me, you share a set of conflicting tendencies.

  • First, a tendency to have many machines that you work on.
  • Second, a tendency to be paranoid about keeping important data backed-up and protected with good redundancy.
  • Third, a tendency to hate redundancy! This goes along with SPOT. I hate when things get out of sync. I hate having things spread all over a bunch of machines.

Using a source control system helps a lot with this (especially if you're dealing with text-based data formats).

In the world of OSS, Subversion (SVN) is a big player in source management. It's supported by SourceForge. It's used by a mountain of OSS projects. And (drum roll) it has an amazing Windows shell extension: Tortoise.

  • Step one: install.
  • Step two: make directory somewhere on your machine.
  • Step three: right-click and pick "SVN Checkout..."
  • Step four: type in the URL of a public SVN repository. There are many out there. Check the list above.
  • Step five: laugh at how easy it all is.

Tortoise supports the creation of patches. Renaming and branching. It even has great shell indicators so you know what's checked-in and what's pending check-in. (It works great on XP. So-so on Vista.)

Take a look at TortoiseSVN.

If you're looking for hosting for your SVN repository, check out DreamHost.

Happy Hacking...and don't forget to build an test before you check-in. :-)

Saturday, December 8, 2007

DreamHost Rocks!

I've been all over the map with hosting services. Each has it's own cool features and things that are annoying.

I've finally found one that (almost) has it all: DreamHost.

For $10 a month (paid yearly):

  • 5120 GB per month bandwidth. No, that is not a miss-type. Put another way: 5.120 TB a month. (Now, being realistic, the box it's hosted on would probably melt before you hit that mark. It's almost like offering 50,000 minutes on a cell phone plan when there's only 44,640 minutes in a month. But at least you won't get charged for a Digg hit or something.)
  • 500 GB of storage. Again, not a typo. 0.5 TB.
  • As many domains as you want. You have to buy the domain names, but you can host 'em all on one account.
  • As many MySQL databases as you want. Size comes out of your 500 GB of storage so make 'em as big as you want.
  • Shell access. We're talkin' SSH. (Well, if I could figure out the damn certificate thingy.) I'm using 'ln -s' to create symbolic links for the first time in 6 years. Reminds me of college...
  • The deal-maker: SVN. For those that don't mind (or prefer) OSS source control, this is it. I use it for all of my code and personal writing--all things I want to backup, sync reliably across machines, and keep version history on. I'll post later on my love of Tortoise.
  • Oh, and they're carbon neutral. It's almost silly.

I said almost above. What's the catch?

Well, there's not a huge number of easy-to-install software packages. They don't use cPanel/Fantastico like a lot of Linux hosting shops. The interface they do provide is very clean and one can manually install most things, but it's kinda nice to do a click-and-install for Drupal.

That's my only nit, actually. Everything is super fast. I'm super happy.

Check 'em out.

But Kevin, this is a Linux hosting package. Where's the Windows Server 2008 package?

Sigh. The world is so much larger than the Microsoft stack of technologies. I love VS as much as anyone, but getting a broad skill set is important, right? Plus the OSS web community is insanely strong. The content, energy and enthusiasm are amazing.

Full disclosure: Yes, the links provided are for a referral program. Yes, I get a kick-back if you sign-up. No, I would never pitch anything just for the kick-back.

I've had plenty of services offer kick-backs that I blinked at--that I never felt strongly about. This is proof I have no subtext. These guys are that good.

Tuesday, December 4, 2007

In search of DRY SPOT

I realized there is a concept I come back to often in a lot of my software implementation and in a lot of my discussions. It goes by two common acronyms that are pretty much interchangeable.

DRY: Don't Repeat Yourself.
SPOT: Single Point of Truth.

DRY is articulated in the book The Pragmatic Programmer, although Eric Raymond likes to call it SPOT.

How does this exist in our world of C# and .NET? Well, every time you define a private const string or private const int instead of sprinkling magic values all over your code, every time you generate documentation from your source files, every time you develop a clever data structure to represent both the execution and the description of a process, you are practicing SPOT.

Quite often, my SPOT will live in a static class Util that I create for almost all of my software projects. If I have one way to handle errors, one pay to deal with collection, one way to handle user input, centralizing it makes bug fixing so much easier. It actually minimizes bugs in a lot of cases, which minimizes the need to fix them.

If you haven't heard of these concepts, they are great to add to your software vocabulary.

For many, I'm sure the idea has always been floating around, just without a good name.

Now you have a good shorthand when you are mocking someone else's code.

Happy hacking!

Wednesday, November 21, 2007

Reasons to subclass: Great, Good, Okay

Shout-out to brilliant developer (and my co-worker) David Potter, who--through hours of discussion--helped me arrive at this 'thought'.

FYI: I use a lot of WPF examples in here. Apologies to the non-WPF devs.

Back in June, I wrote a post titled: Don't subclass a Panel, unless you're making a Panel.

In that post, I outlined the 'great' reason to use subclassing (read, inheritance):

I read a great internal paper at MS once--written by one of those brilliant old-guard devs with decades of perspective. The point the author pushed: use inheritance only for polymorphism. Translated: when making MyGrid, only subclass Grid if you mean for people to treat your new MyGrid just like another Grid. Code (and a user, for the most part) that deals with Grid should be able to "deal" with MyGrid without any issues.

I use a strong word there: only.

Now with time and experience comes perspective.

I'm going to make this philosophy a bit more nuanced by introducing categories of subclassing: great, good, and okay.

My argument: there are times to use each, but the further you get away from 'great', the more trouble you can get in and the more careful and thoughtful you should be.

Great subclassing: for polymorphism.

Examples here: Stream (from mscorlib) and UIElement (from WPF).

Stream is worthless by itself. It's meant to be the base class for something else. But there are innumerable features of the CLR that deal with Stream generically, without much concern for any subclass.

UIElement is similar. Basically worthless by itself. Designed to be a baseclass. But things like WPF layout (Measure/Arrange) deal explicitly with UIElement, ignoring any details of any subclass.

If you create a Foo class and have other classes that take a Foo in a constructor or method argument, even though Foo is abstract or rarely used by itself you are playing in the 'great' end of the subclassing spectrum.

Good subclassing: cognitive simplicity

If 'great' subclassing is for software components, 'good' subclassing is for humans.

ContentControl (WPF) is a pretty good example. I can't think of any constructor or method that takes ContentControl as a parameter.

We could imagine Button and Label and ScrollViewer all re-exposing the common properties (Content, ContentTemplate, ContentTemplateSelector) without any changes in functionality.

But! It's really nice that users can look at Label and say "oh, that's a ContentControl" and immediately have a valid mental model of how to use it.

The baseclass, in this respect, provides a grouping paradigm for a user to understand classes of types.

While this is a nice feature, it has its issues.

ButtonBase is a good example.

ButtonBase is the 'clickable' widget in WPF.

Almost everything that is clickable subclasses ButtonBase.

ButtonBase subclasses ContentControl.

ContentControl is the 'content' widget in WPF.

Almost everything in WPF that has content is a content control. Well, almost. ContentPresenter has the same properties that ContentControl has regarding content (Content, ContentTemplate, ContentTemplateSelector).

But they don't share a baseclass. Why?

Well, because ContentControl is a Control.

Control is the 'template-able' widget in WPF. It lets you swap out the chrome.

ContentPresenter doesn't let you swap out the chrome, just the template for the data.

So, we could really imagine three separate classes, all of which derive from FrameworkElement.

  • ClickElement: exposes the click properties/methods/events.
  • ContentElement: exposes the content properties/methods/events (Yes, this class name already exists for text stuff. Play along...)
  • TemplateElement: exposes the template properties/methods/events (this is what Control is now).

The fact that ButtonBase subclasses in a specific order is kinda arbitrary.

One could imagine wanting a template-able, click-able element that doesn't have content.

One could imagine wanting a click-able, element that holds content that isn't template-able.

Single inheritance forces framework authors to choose. This can be annoying if you want a re-mix of the available features.

A great example of this: TransitionPresenter (from the bag-o-tricks).

It has all of the content properties, but it's not a ContentPresenter or a ContentControl. (The way it does its visual tree is different than both of those controls.)

It turns out to be impossible to subclass ContentPresenter and it's confusing to subclass ContentControl (because TransitionPresenter doesn't use a ControlTemplate).

A really smart dev who was doing code clean-up actually changed the baseclass from FrameworkElement to ContentControl, thinking he was making things simpler.

This is bad! A user will then expect to be able to use the Template property to change the chrome. This is the same problem with making MyGrid from Grid unless you want people treating it like any other Grid.

This trap is usually because of the third type...

Okay subclassing: tactical code reuse

If you have 15 classes that all have a Foo, Bar, and Baz property, having a common baseclass just saves code. Less to document. Less to test. Less to mess up.

Fine.

But if sharing some common state is your only goal, just make sure you acknowledge (along with the rest of your team) that is why you're doing it. Put it in the code comments of the class.

In some respects this is less dangerous than the 'good' reason to subclass because the FooBarBaz class probably doesn't have much meaning or use beyond your tactical reasons. As soon as it does, though, you can fall into the MyGrid trap.

In closing

This was a really long write-up.

I guess my final advice is be careful.

As with anything in life, if you try to be clever for clever's sake, you'll get burned.

If you try to use every feature of a language or a framework just to add spice to your afternoon of coding, you'll get burned.

As I discussed in my post about patters and guidelines, always try to understand the implications of the tools/tricks you use when coding.

And that's all I have to say about that.

Happy hacking.

Did you find this interesting? Let me know. I'd hate to think I was riffing all this out just to make my tendinitis worse.