patkua@work

The intersection of technology and leadership

Page 50 of 53

Onboarding Strategy: Domain Driven Design And Readable Code

Its Purpose?
This helps people new to a project answer questions about the domain more effectively and where the system fits into it.

Domain Driven Design

Image taken from Kakutani.com’s flickr stream under the Creative Commons Licence.

How Did We Execute It?
We followed domain driven design as much as possible applying several techniques described in the book. We aimed for a Ubiquitous Language, reducing the number of terms for the same thing to a single one. This flowed into the code as well, where domain terms were used for domain classes, and namespaces for related concepts.

We tried to model all of the business processes and rules in a domain layer (the inner most tier on an onion ring model of our system), so that they were easily testable and people knew the first point to look for when answering a question about the domain. A side benefit of this is not tying the domain rules to a particular choice of technology or framework, and makes inconsistencies in the domain much more visible.

Many different factors affected the way in which we coded including aspects from Domain Driven Design, Object Oriented Design (such as encapsulation, responsibility, decoupling and reuse), testability, and readability. Our standards by default exclude comments where possible replaced by representing as much intent as possible in the code itself. We focus on what it does and why. I’ve found “What” tends to be best represented by production code, whilst “Why” is better explained in tests because you can better represent different contexts there.

Given that I’ve been with the project for some time and seen quite a few people flow on and off, I believe that given a handful of system patterns and a high level picture of how it fits together, it’s much quicker to bring people on board. Equipping them with knowledge of where to find information and seek answers for their own questions, you spend less time answering questions and it fits much better into their own mental model.

Why Is It Important?
Following Domain Driven Design and well refactored code brings many more benefits than just effective onboarding (think flexible, adaptable and much more robust and consistent) though I want to specifically focus on its impact on onboarding for the purpose of this entry. Even though these are great development practices, an emphasis on both of these has such a significant positive impact on onboarding of people.

Enabling others to find the answers to their own questions is much more effective because they depend less on others to work out their mental model and help them fill the gaps in that model.

Well Finally…

I’ve seen several projects use FIT and thankfully I didn’t hang around on them too long. I’ve not been a huge fan of FIT (though I will admit it has its purposes). Thanks to James Shore for writing a blog entry about when not to use FIT (and hey, it’s really not that often you should be!). He’s also very humble enough to admit his mistake around promoting it with his articles on “executable specifications”.

If you’re a FIT fan, have a good read of this.

Onboarding Strategy: Respect Individual Needs

Its Purpose?
Many of the techniques I’ve written about are ideal for covering a broad range of people and a broad range of topics. Each is useful for their own particular purpose, but I feel it important that you understand who you’re onboarding, and customise each of your techniques or at least the way you execute them to help them become more effective.

Individuals

Image taken from Dogwelder’s flickr stream under the Creative Commons Licence.

How Did We Execute It?
Although everyone on our team went through many of the same onboarding strategies and techniques, I sat down with each new person to find out a little bit more about them. I found it important to ask questions such as:

  • What do they want to get out of the project?
  • What have they accomplished that they’re particularly proud of in the past?
  • How do they think they learn the best?
  • What are they worried about?

Each of their answers don’t immediately necessitate the change to any session, but it gave me a much better idea of how I should adapt it, or expand on the session in the way that best suits each individual.

Why Is It Important?
Everyone that I’ve worked with is very different – some learn more effectively in different ways, and many have very different backgrounds and experiences. I feel it’s important as a coach to understand where they come from, and their different needs, tailoring content and the way information is conveyed to their particular style. Some people feel that the Socratic method is always an effective technique, though is often executed in a way that can be patronising and demeaning, particularly for more experienced people. Telling war stories or success stories is sometimes more effective, with the little anecdotes sticking in their memories. For others, visual techniques for conveying information is the most effective way they can learn. Others just need to do it themselves.

In short, there is no “Golden Hammer”, so don’t try to use it on everyone.

In Bangalore

A quick note to say that I finished up on my project in London on Friday, flew to Bangalore on Saturday and started in a new training role on Monday. It’s not quite the same material that I would have covered had the trip in January eventuated but it’s still great to meet with new TW people and share my experiences with them.

My initial impressions of everything so far is very light on. The Bangalore office is just thriving with amazing talent and all in one location, although I also see the importance of bringing in people from overseas for different perspectives – so many people just seem to have things nailed, and I think you do generate better ideas when you have several different opinions and approaches. I look forward to talking to people about their experiences on agile projects here from a coaching and process perspective (please get in touch with me if you’re interested in talking about your experiences).

It’s also been great to catch up with a few people that I’ve met over the last couple of years. I’ll give more of an update and reflections on the things that I’m doing these days, but probably another night. I have a class to teach in the morning.

Seeking out project smells

Our project has had enough time lately to really focus on some good clean up around the codebase. The project has been under major development for well over a year with plenty of people having worked on it so I find it an interesting experience to see from a high level how things are. FxCop helps us to a certain degree but here’s some very simple metrics I’ve been using to help draw out things to fix:

  • ToDo‘s indicating unfinished tasks or notes made by other people. Each represents a signpost that forces people to pause or question what’s there. Each should be considered individually and should be completed, or deleted where possible. Resharper makes it even easier to find them with their TODO Explorer. Our project had a total of five of them.
  • Ignored tests are large potential sources of problems, indicating that code could be untested, or a test is not providing the feedback that it should be. There tests should be rewritten, implemented or deleted if they are no longer needed so people don’t need to maintain them. Our project’s grand total… 12 out of 2390.
  • Commented code is an obvious code smell, often created by many different reasons (the trick, like the above items are to find out why they’re there). Sometimes the code surrounding the comment may not be readable enough for someone to follow through and that’s easy to fix by applying a variety of refactoring techniques. Other times, commented code may be out of date and is left there because someone wanted to show how something is different – I would use refactoring such as extract method or variable, rename method or variable to help give additional context to get rid of the old code as it’s more important for people to understand what is working now more so than what it is. As a last resort, comments may be there to help explain to other developers why something is there and may be a pragmatic solution to an otherwise convoluted context. These should be exceptional and I would be greatly concerned if these were everywhere. My metric for this was very high, at 6730 lines out of 173122 lines of code although I think most of them are the .Net designer generated code for Winforms and ASP.Net pages.

Overall I was surprised at how little there was to fix with these considering how quickly the codebase has been moving and how many developers have been involved. It’s great to see everyone living the values and I think it shows in the quality of the software.

Onboarding Strategy: Letting Go

Its Purpose?
Individuals progress through different stages of learning. Not everyone will progress at the same pace, and at some point, people will move beyond the initial learning stage and will start to learn more if they are doing it by themselves with less explicit direction.

Letting Go

Image taken from Ruojo’s flickr stream under the Creative Commons Licence.

How Did We Execute It?
As individuals new to the team demonstrated more knowledge and understanding about the system, we started giving them more ownership of a particular story card. They would create the Tiny Tasks for a story, and own the design for it. As the technical lead, I would only intercede if they wanted an opinion about a particular design, other than that they would be given space they needed to finish a story card without any explicit instructions.

Why Is It Important?
There are many different ways that people learn and many different models describing each way. In Aikido, they describing learning using Shu-Ha-Ri and is one often used as an analogy of learning software concepts and patterns. Another model talks about the 4 Stages of Learning where an individual progresses from Unconscious incompetence towards the ultimate stage of Unconscious Competence though may progress via two others stages of Conscious incompetence and Conscious Competence. The common theme between most learning models is recognising an initial stage for a person who needs explicit direction and further stages where explicit direction is no longer required.

Many of the onboarding (and really just learning) techniques help address most of the initial stages (Shu or Unconscious Incompetence) of learning and it’s important to keep in mind that individuals will reach the second stage at different rates. If you continue to apply the same approach to teaching students who have transcended to the next level, you will find they become more resistant, and less appreciative and more than likely much more argumentative and resentful.

The key to Letting Go is recognising when individuals progress to that next level and give them the appropriate freedom to accomplish specific goals with little to no guidance. It’s important to still create a safe environment for them to make mistakes but they will learn much more by doing it themselves.

Events, Reflection and how they don’t work in C#

Although the .Net reflection APIs make some tasks easier, we’ve found recently that those related to events and their delegates have been fairly poorly designed. Our task was very simple: dynamically manipulate the event handlers attached to a set of events.

It’s easy enough to get a declaration about an event of some sort using code like:

EventInfo infoAboutEvent = someObject.GetType().GetEvent("MyEvent"); 

Given your EventInfo class it’s easy to add an a new event handler. Unfortunately going the other way around ended up much harder. Unlike things like FieldInfo that give you direct access to get the field instance from the object using GetValue(owner), finding the event field isn’t as easy. First we had to look at all the fields, and filtered out things that looked like a Delegate so we could do some useful things with them, like finding out what subscribers were hooked up to our event.

Our ultimate goal of being able to dynamically remove EventHandlers at runtime further ran into problems when we were trying to unhook methods from private events. The result of trying to unhook a handler from a private event via the EventInfo.RemoveEventHandler method results in an InvalidOperationException with a message of “Cannot remove the event handler since no public remove method exists for the event.”

One more simple use of reflection and soon we were able to automatically unhook a variety of delegates from our events regardless of their access mechanism (although using code that wasn’t as nice as we wanted). A few refactorings later and we ended up with something actually quite useful in the end.

ReflectUtil.RemoveEventHandlersFrom(
 delegate(Delegate subject) { return subject.Method.Name.StartsWith("On"); }, 
  objectWithEvent);

And here’s the class that we ended up with. Although I can’t recommend people use reflection lightly, if you need to delve into the world of reflection with events, I hope you find this example useful.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;

public sealed class ReflectUtil
{
  private static BindingFlags PrivatePublicStaticInstance 
    = BindingFlags.NonPublic | BindingFlags.Public |
      BindingFlags.Instance | BindingFlags.Static;

  public delegate bool MatchesOnDelegate(Delegate subject);

  public static void RemoveEventHandlersFrom(
    MatchesOnDelegate matchesOnDelegate, params object[] objectsWithEvents)
  {
    foreach (object owningObject in objectsWithEvents)
    {
      foreach (DelegateInfo eventFromOwningObject in GetDelegates(owningObject))
      {
        foreach (Delegate subscriber in eventFromOwningObject.GetInvocationList())
        {
          if (matchesOnDelegate(subscriber))
          {
            EventInfo theEvent = eventFromOwningObject.GetEventInfo();
            RemoveSubscriberEvenIfItsPrivate(theEvent, owningObject, subscriber);
          }
        }
      }
    }
  }

  // You can use eventInfo.RemoveEventHandler(owningObject, subscriber) 
  // unless it's a private delegate
  private static void RemoveSubscriberEvenIfItsPrivate(
    EventInfo eventInfo, object owningObject, Delegate subscriber)
  {
    MethodInfo privateRemoveMethod = eventInfo.GetRemoveMethod(true);
    privateRemoveMethod.Invoke(owningObject,
                               PrivatePublicStaticInstance, null, 
                               new object[] {subscriber}, CultureInfo.CurrentCulture);
  }

  private static DelegateInfo[] GetDelegates(object owningObject)
  {
    List delegates = new List();
    FieldInfo[] allPotentialEvents = owningObject.GetType()
      .GetFields(PrivatePublicStaticInstance);
    foreach (FieldInfo privateFieldInfo in allPotentialEvents)
    {
      Delegate eventFromOwningObject = privateFieldInfo.GetValue(owningObject) 
        as Delegate;
      if (eventFromOwningObject != null)
      {
        delegates.Add(new DelegateInfo(eventFromOwningObject, privateFieldInfo, 
          owningObject));
      }
    }
    return delegates.ToArray();
  }

  private class DelegateInfo
  {
    private readonly Delegate delegateInformation;
    private readonly FieldInfo fieldInfo;
    private readonly object owningObject;

    public DelegateInfo(Delegate delegateInformation, FieldInfo fieldInfo, 
      object owningObject)
    {
      this.delegateInformation = delegateInformation;
      this.fieldInfo = fieldInfo;
      this.owningObject = owningObject;
    }

    public Delegate[] GetInvocationList()
    {
      return delegateInformation.GetInvocationList();
    }

    public EventInfo GetEventInfo()
    {
      return owningObject.GetType().GetEvent(fieldInfo.Name, 
        PrivatePublicStaticInstance);
    }
  }
}

Onboarding Strategy: Student to Teacher

Its Purpose?
Acting as a teacher, coach or mentor helps to reinforce the concepts on all the different subject matters you cover whilst mentoring, therefore turning a student into a teacher is an opportunity you should make the most of. Vocalising your opinions and thoughts on a particular subject works to further deepen your understanding of the topic matter. It also has another benefit of exposing any gaps you may have when your student asks you questions.

Students to Teachers

Photo taken from Golbog’s photostream on Flickr under the Creative Commons license

How Did We Execute It?
We’re lucky enough on our project to pair program and we’ve found it an extremely effective technique at spreading knowledge about the system. When are team formed, we co-ordinated some strategic pairing, understanding that we had people at various stages of learning about the system. We made sure that people who’ve been working on the system pairs with people newer the system, effectively positioning them in the role of a “mentor” for newer people.

Why Is It Important?
Continuous cycling between student and teacher are common patterns you see in all types of martial arts classes because they recognise the importance of putting a student in the position of a teacher. Often you see many of the senior students instructing newer students on how to improve their technique even though they themselves haven’t yet achieved mastery.

Teaching others is an important part of the learning cycle, strengthening and deepening the things that you think you know so it’s important to create these opportunities and take advantage of them where you can.

Upgrading from NHibernate 1.0.2 to 1.2.0.GA Experience Report

We recently upgraded to the latest version of NHibernate to make use of many of its new features. There are plenty of good reasons to upgrade including proper support of .Net 2.0, bug fixes, multi queries, new database dialects (including SQL Server 2005) and the ability to use generic types. We anticipated a few issues upgrading NHibernate, and though not the hardest upgrade ever, we did end up with a few more issues than expected. Here’s our experience upgrading to the latest version.

Things they warned you about

The NHibernate guys did a fantastic job writing their migration guide. They warned us that it wasn’t just simply a drop-in replacement and included a number of breaking API changes. Things that we found easy and had been documented included:

  • Updating our XML files from urn:nhibernate-mapping-2.0 to urn:nhibernate-mapping-2.2
  • Replacing outer-join="true" to fetch="join" and outer-join="false" to fetch="select"
  • Adding default-lazy="false" to each mapping file to deal with the change in default lazy loading behaviour
  • The HSQL count had been upgraded from an int type to a long type and our code had to cast it to the correct types
  • Deprecation of the CreateSQLQuery with parameters changed to ISQLQuery(String)

Things not on the label

  • Strange behaviour around the nosetter.camelcase access strategy – We had a property exposing a primitive type (string) of a more complex type, given the same field name and we kept getting a null result. It looked like it was trying to set the field using the type of the get property, even though the set should have been using the more complex user type. We fixed this by changing our mappings to field.camelcase instead of using the nosetter.camelcase.
  • SQL statement logging has changed – Our application listens very carefully to the Log4Net output that NHibernate generates, capturing each SQL statement and its parameters. Previous versions of NHibernate used to log their parameter values separately from their SQL statements, instead they are now logged on the single line. Thankfully our change was contained to two very small classes.
  • Replacing IClassPersister with IEntityPersister – We had to add a different constructor to our custom user types (also different from the current documentation), with a signature of PersistentClass model, ICacheConcurrencyStrategy cache, ISessionFactory required, IMapping mapping. Additionally we had to implement the new property Factory that came along with this interface. Now I had no idea where ISessionFactoryImplementor came from. Looking at the code, they had cast ISessionFactory in their constructor, and then returned that when the property Factory was called. It is a small inconsistency in their API that we ended up having to duplicate. This would be a problem if you ended up writing your own ISessionFactory but thankfully we haven’t done that ourselves. There were plenty more methods that we had to implement though none of them were actually very insteresting for the things that we had to do. Our solution: Cast ISessionFactory to ISessionFactoryImplementor and store it in the constructor just to be returned in the property.
  • IUserType Classes Disappearing – They had warned you that IUserType had moved into another namespace though I wasn’t quite clear what you had to do if you were using one of the old versions. In the end new Int16SqlType() is replaced by SqlTypeFactory.Int16, new Int32SqlType() by SqlTypeFactory.Int32, new Int64SqlType() by SqlTypeFactory.Int64, and new GuidSqlType() by SqlTypeFactory.Guid. I’m guessing it would be the same for any other IUserTypes you may be using.
  • IUserType New Methods – Four new methods appeared on the interface, GetHashCode, Replace, Assemble, Disassemble. Implementing GetHashCode we ended up delegating to our object, replace we delegated to using disassmemble then assemble, and implemented assemble and disassemble using DeepCopy, emulating what NHibernate Types do. It wasn’t really clear to me from documentation or upgrade guides what it should be
  • NHibernate.HibernateException : Could not instantiate cache implementation – It look like second level caching was now enabled by default and we hadn’t added configuration for it. We kept getting “Second-level cache is not enabled” messages. We disabled it and fixed this problem by explicitly turning it off. The property key is hibernate.cache.use_second_level_cache and turn it off by using the value false.

For the most part, considering how much of the core hibernate functionality had changed, we haven’t had too many issues although it’s still early days. We are noticing slightly different behaviour in the way that the flush semantics seem to be working (maybe auto flush mode is on by default now) though everything is still working quite pleasantly.

Announcing the Release of SharpZebra 0.90

Printing to the Zebra branded thermal transfer printers requires knowledge of their proprietary EPL2 language. Searching the net for a nice way of using EPL2 to communicate with these printers turns up a number of small projects, though none of them particularly ideal for integrating with a well written C# application, with most of them effectively getting you to copy and paste code into your project that you shouldn’t have to maintain.

Sharpzebra is a new open source project, written in C# that gives you access to a better printing API that abstracts away the EPL2 language concepts. I hope that it helps you spend more time putting together the things you need to print instead of working out how to print. See the Two Minute Quickstart here.

Download the binary release (dll), or binary with the project source code here.

« Older posts Newer posts »

© 2024 patkua@work

Theme by Anders NorenUp ↑