Devlico.Us
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @devlicious

Christopher Bennage

Our WPF book is now available!
follow @bennage on Twitter!
 

August 2008 - Posts

  • Building a WPF Application: Part 3

    Table of Contents

    Application Architecture

    I'm going to back up and bit discuss my overall approach to structuring this WPF project. So far the solution consists of four projects:

    solution
    • ChumChase is the actual WPF project.
    • FriendFeed is the official .NET api I downloaded from here, and patched so that it would compile. :-)
    • IntegrationTests is for testing the bits of the application that interact with the FriendFeed api.  I separated this out because it is much slower to run than my Specifications tests, and goes beyond the trust boundary of the app.
    • Specifications is the bulk of the unit tests for the project. I'm influenced by the whole BDD approach, and I like to think of my unit tests as executable technical specifications.

    Project Structure

    projectIn the main project you'll find the following:

    • Presenters - This folder contains the presenter classes. I usually name these classes with the suffix "Presenter, though that's a bit of a hang over from other frameworks (MonoRail, RoR). This directory is where I have the HomePresenter class we've been discussing.
    • Views - These are usually user controls or some derivative thereof. I name them to correspond to their presenter. So you would expect, since we have HomePresenter, to find HomeView.xaml. (Actually, I goofed and the current source has the view named HomeFeedView.xaml).
    • Model - This is the object model that represents the "business problem" I'm trying to solve. In this case it happens to mirror the actual api quite a bit.
    • Repositories - Here I am influenced by Eric Evans' book on Domain-Driven Design. Repositories are classes that allow me to access/persist data in a way that makes sense to my business domain. It's also a place where I can hook in orthogonal concerns such as logging, caching, or security. Repositories differ from the traditional data access layer in that there is an emphasis on the domain model (as opposed to following the semantics of a relation database).
    • Services - These are supporting classes. They are not necessarily part of the business or problem domain. A classic example is an SMTP provider. Classes in your model or presenters might utilize these.
    • Framework - These support the framework of application, but don't have anything to do with the business concern. If we need to create a base class for views, we'd put it here. Currently, I have a class there that is going to assist us with binding to commands. This is code that could likely be pushed out to a reusable library.

    Aside from these folders you will also find:

    • App.xaml - This is the starting point for the application. It will kick off our Windsor configuration, and launch the first window for the application. Eventually, we'll include some application-wide resources in the xaml, primarily for styling.
    • Shell.xaml - This is the main window of the application. I call it Shell, because there is very little to its UI. It's content is bound to view of our current presenter. This class might have some logic in it's code-behind if we need to do some things like managing a set of tabs. It also provides the overall layout of the application.
    • ApplicationController - I briefly mentioned this in the last post. Honestly, I've waffled a bit on what to call it. It's responsibility is to coordinate the presenters for the application. For example, if presenter X needs to load presenter Y it passes that request to the application controller. In this, it also handles some statefulness for the overall application. This will become more clear as we begin to work with the class.

    What's Not Here Yet

    There are several other things that usually appear in my projects. I often end up with a base class for test fixtures, though I think the new Rhino.Mocks features might affect that. However, the big piece that's missing is the folders and files related to organizing the XAML.

    It's common for me to have the following:

    • Colors & Brushes - I typically have a  resource dictionary dedicated to defining the colors and brushes used in the application.
    • Default Styles - When I provide a completely custom style for an application, I'll have a resource dictionary that defines all of the default styles for controls. It useful to note that I avoid putting control templates inline in this dictionary.
    • Control Templates folder - In this folder, I will have a file for each control template in the application. I'll usually have a "manifest" resource dictionary where I merge in all of the individual templates. This helps to keep the structure clean in other areas. These are the control templates that are referenced in my default styles dictionary.
    • Data Templates folder - Inside the Views directory, I will have a sub-folder for data templates. Data templates really are views.

    What Happens at Runtime?

    A synopsis of what happens at runtime, well, what will happen once we've finished:

    • App.xaml starts off.
    • In its constructor, we configure our container, which in this case is Windsor.  The container is told how to resolve resources, such as where do I find the actual implementation of IFriendFeedProxy.
    • Still in the constructor, we then request an instance of IApplicationController, and call StartApplication().  Note that we don't set the StartupUri in the XAML for App.
    • StartApplication() might handle some things like loading up user preferences, but mostly it will initialize and open Shell.xaml.
    • Somewhere around here we'll request the HomePresenter from the container, and inject into the shell.
    • As the user interacts with the application, presenters may be removed and new ones injected (probably into a tab, or new window). The shell's code-behind has the code for actually placing these presenter's views into the layout.
    • The presenter will have use commands as properties that can be bound to in there views. These commands are coordinators of individual activities in the application.

    I'm certain that parts of this are confusion, but I believe it will make sense as we continue to build the application. As always, your feedback is welcome.

    More to come!

    Continue to Part 4.

  • Error Message UX Fail

    I encountered this nugget while signing up to get developer access to a certain high profile web-based service. It turns out that my first choice for a password did not meet the site's policy and I greeted with this:

    stupid_tiny_warning

    This is puts a big capital S in front of UX.

  • Building a WPF Application: Part 2

    Table of Contents

    So let's get back to this whole building a WPF application thing.

    A number of things went down since my last post: I was out sick with a stomach bug for few days, my infant son caught the same bug and subsequently we spent a few days in the hospital (he's fine now, it was nothing serious), and I finally caught up on the AAA syntax in Rhino.Mocks.

    Changing My Testing Style

    Lots of people have blogged about the AAA syntax here, here, and here (to list a few). I won't go in depth, but briefly the idea is that you arrange your unit test thusly:

    • Arrange: do the minimal setup required to execute the test
    • Act: execute the actual code under test
    • Assert: assert that the code did what you expected

    I decided to adopt this style. It seems to yield more readable, more focused, and less brittle tests. I rewrote the test from my last post using AAA.  The original test was this:

    [TestFixture]
    public class The_presenter_for_the_home_feed : TestFixtureBase
    {
        private HomePresenter _presenter;
        private IFeedRepository _feedRepository;
    
        protected override void given_the_context_of()
        {
            _feedRepository = Mocks.StrictMock<IFeedRepository>();
            _presenter = new HomePresenter(_feedRepository);
        }
    
        [Test]
        public void can_refresh_the_home_feed()
        {
            using (Record)
            {
                Expect.Call(_feedRepository.FetchHomeFeed())
                    .Return(new List<Entry>());
            }
    
            using (Playback)
            {
                _presenter.RefreshHomeFeed();
            }
        }
    }

    and I rewrote it as this:

    [TestFixture]
    public class The_presenter_for_the_home_feed : TestFixtureBase
    {
        private HomePresenter _presenter;
        private IFeedRepository _feedRepository;
    
        protected override void given_the_context_of()
        {
            _feedRepository = MockRepository.GenerateStub<IFeedRepository>();
            _presenter = new HomePresenter(_feedRepository);
        }
    
        [Test]
        public void can_refresh_the_home_feed_when_credentials_are_available()
        {
            _presenter.RefreshHomeFeed();
            _feedRepository.AssertWasCalled(x => x.FetchHomeFeed());
        }
    }

    Again, you can gather more details about this approach in one of the links above.

    One interesting note though is that AssertWasCalled is an extension method and we're using it to assert the method FetchHomeFeed() was actually called on feedRepository.

    (I also think that I should not have used StrickMock in the original test, as that added to fragility of the test.)

    I tend to think of my code in terms of sentences and paragraphs, at least when it comes to the use of white space. You'll notice as the tests get a little larger that there will usually be three "paragraphs" in the code: arrange, act, assert.

    Focusing on the Story

    I said in my last post that the core story for this application is to retrieve the home feed. As such, I'd like to take the shortest path to getting that feature fully functional.  The next few steps are roughly:

    • Write a proxy to wrap the existing FriendFeed api, but just enough to fetch the home feed.
    • Write a repository that will manage the home feed data. Even though this seems superfluous at the moment, it's a seam in the application where I will add future functionality (such as caching, logging, etc.).
    • Provide support for authentication.  The FriendFeed api requires a username and remote key for accessing the home feed.

    Very soon, I want to be able to launch the application, click a Refresh button, and see my feed. If I haven't provided credentials, I want the application to prompt me for them.

    The Credentials Problem

    The parts of the story regarding credentials raise some interesting design questions. Let's consider some of the pieces of the puzzle.

    The HomePresenter is going to initiate the act getting the home feed. We've already seen that HomePresenter is going to invoke some implementation of IFeedRepository. The repository will talk to the FriendFeed api through a wrapper (IFriendFeedProxy) . Inside the wrapper class is the official .NET FriendFeed client, and it is the class that is really interested in the credentials. It's what talks to the FriendFeed web service, and that needs to be authenticated with the credentials. So at the bottom of this, somewhere in our code, we'll have this:

    FriendFeedClient client = new FriendFeedClient("username", "remoteKey");

    classesI'm using the Dependency Inversion Principle (which I'll talk about more later). However a consequence of this is that the constructor for HomePresenter takes an IFeedRepository and an IApplicationController.

    In turn, my implementation of IFeedRepository, cleverly named FeedRepository, requires an instance of IFriendProxy in its constructor. My implementation of IFriendProxy wraps the official api. Did you follow all of that?

    When I first began working through the design, I thought that I'd have to request the credentials from the user at the presenter level, and then pass them down to the repository, then to the proxy which would in turn set them on the actual client. But I could tell quickly that this smelled bad. The repository doesn't need to be concerned with credentials, and neither the HomePresenter. So far there are really just two classes that need to know about credentials: some sort of UI for getting the credentials from the user (that is a presenter of some sort) and FriendFeedProxy.

    Oh and what's this IApplicationController interface all about? Um, I'll come back to that in the next post.

    Single Source

    Ideally, what I want is a single source for the credentials: a class whose sole responsibility is managing the current set of credentials. This lead me to create an ICredentialsSource interface. In order to flesh out what the interface should look like I began writing tests for how the client proxy would interact with it:

    [TestFixture]
    public class The_client_for_FriendFeed
    {
        private const string _username = "your_username";
        private const string _remotekey = "your_remotekey";
        private ICredentialsSource _credentials;
        private FriendFeedProxy _client;
    
        [SetUp]
        public void given_the_context_of()
        {
            _credentials = MockRepository.GenerateStub<ICredentialsSource>();
            _client = new FriendFeedProxy(_credentials);
        }
    
        [Test]
        public void can_get_the_home_feed_when_authenticated()
        {
            _credentials.Stub(x => x.UserName).Return(_username);
            _credentials.Stub(x => x.RemoteKey).Return(_remotekey);
            _credentials.Raise(x => x.CredentialsChanged += null, _credentials, EventArgs.Empty);
    
            var feed = _client.FetchHomeFeed();
    
            IList<Entry> entries = feed.ToList();
            Assert.That(entries[0].Id, Is.Not.Null);
            Assert.That(entries[0].Title, Is.Not.Null);
            Assert.That(entries[0].Published, Is.Not.Null);
        }
    
        [Test]
        [ExpectedException(typeof (WebException))]
        public void cannot_get_the_home_feed_when_not_authenticated()
        {
            var feed = _client.FetchHomeFeed();
        }
    
        [Test]
        public void updates_credentials_when_the_credentials_source_changes()
        {
            //arrange
            _credentials.Stub(x => x.UserName).Return(_username);
            _credentials.Stub(x => x.RemoteKey).Return(_remotekey);
    
            //act
            Assert.That(_client.DoesClientHaveCredentials, Is.False);
            _credentials.Raise(x => x.CredentialsChanged += null, _credentials, EventArgs.Empty);
    
            //assert
            Assert.That(_client.DoesClientHaveCredentials, Is.True);
        }
    }

    These tests live in my IntegrationTests assembly, separate from my "real" unit test is the Specifications assembly. I consider these tests to be integration tests because they actually interact with the web services. They are not run as often as my Specifications.

    I found these tests hard to write, and I would appreciate any feedback on how to improve them.

    My point here though is to illustrate how these tests led me to create ICredentialsSource. I know that there will be a little more to it, a method perhaps that will allow me to set the credentials, but we'll get to that when we need it.

    Right now, the interface looks like this:

    public interface ICredentialsSource
    {
        string UserName { get; }
        string RemoteKey { get; }
        event EventHandler CredentialsChanged;
    }

    I obviously need the username and remote key (and I was tempted to create a class that represented them as a unit.) I also discovered that I wanted the credentials source to raise a change notification event so that the proxy client would be aware when the user changed them.

    Some other places in the application will actually set the credentials on this source, perhaps a yet-unwritten presenter whose job will be to request them from the user. This really helps to decouple responsibilities and keep the code clean. For this approach to work however, our application will need a single instance of this class. I'll show how I'll handle that when we cover dependency injection.

    Next

    I had a lot of interruptions trying to complete this post, and I had to go back reread what I've written so far. In doing so, I realized that I ought to take a step back and explain my overall default architecture that I'm using. That will be the subject of my next post; and I promise to get the actual WPF bits soon!

    On to Part 3.

  • Why Red Gate Rocks

    I've been working with the eap release of ANTS Performance Profiler from Red Gate. While I don't have a lot of experience with other tools of this nature, I've been pretty impressed.

    My intention was to hold off and blog a full review after I've had to time to really use the application, but today my installed version expired and I just had to share the notification message I received:

    I'm lovin' these guys

    Every tool I used from these guys just plain rocks, I should really do them more justice by blogging about it.

    Disclaimer: I am a Friend of Red Gate, and I get free licenses for their tools.

More Posts

Our Sponsors

Proudly Partnered With