Sean Feldman 的个人资料ברוכים הבאים照片日志列表 工具 帮助
2008/6/27

IDs to Objects

A few months ago I blogged about Domain Objects vs. Primitive Types. Back then it felt right to me to transform a primitive type, like a Guid that represented, to an Organization domain object. Unfortunately at that time I was not educated enough to know that this is a common idiom in among many object designers. Apparently it is. Craig Larman writes it nicely in his book (in my case Organization is what Craig references to as a Customer):

Why bother? Having a true Customer object that encapsulates a set of information about the customer, and which can have behaviour , frequently becomes beneficial and flexible as the design grows, even if the designer does not originally perceive a need for a true object and thought instead  that a plain number of ID would be sufficient.

The other important note is when this transformation is taking place - when an ID or a Key leaves the UI layer and gets to the Domain Layer.

2008/6/19

Have Honest Opinion

It is very hard to provide an honest opinion when you are involved in a situation. I found it always difficult for myself and admired people of being able to do it, lifting themselves from emotional attachments to the matter.

I am a big fan (if not huge) of the whole Google Apps platform. I use heavily Gmail, rely a lot on Google Calendar, abandoned Excel for simple-to-average stuff and went with Google spreadsheets. I used Google Maps, because it was better than Microsoft's competitive version of the product. Till I had a chance to re-evaluate it again. This time around Microsoft has produces a better result. Microsoft Live Maps gives me more than Google Maps does (weird even to think it, not mentioning writing it :).

What made the difference? The level of details, an option of having a closer look, real images. Anyway, I am not using Live Maps.

2008/6/16

Command-Query Separate Principle

A few days ago read in Larman's book about Command-Query Separation Principle. Funny to mention  that I heard about the concept many times ago, but this is the only source that stated it as a principle. And it makes total sense once you evaluate all the pros and cons of the idea.

What's the principle? Simple. There are two kinds of messages to objects:

  • Commands - ones that are affecting the state of the object
  • Queries - ones that are querying an object for its' state without affecting its' state at all

A Command message would be "void Calculate()" or "void Add(double value)". Command message never returns a value, and that's for clear separation of the messages and easier maintenance of the object state (i.e. no surprises). A Query message would be what Command isn't "int GetValue()" or "IsVisible()".

One exception the author brought up was internal/private messages that are not a part of the interface, and therefore can violate the principle - I guess this is a matter of personal preference.

An example is an implementation of a Die (for a monopoly game) modified by myself.

    public interface IDie 
    {
        void Roll();
        int GetFaceValue();
    }
    
    public class Die : IDie
    {
        private int faceValue;
        private Random rand = new Random();
        
        public void Roll()
        {
            faceValue = rand.Next(6) + 1;
        }
        
        public int GetFaceValue()
        {
            return faceValue;
        }
    }

I added the interface on purpose, to have DbC, where implementation doesn't matter that much, because the contract is expressing well enough the intension of how to use an implementer of  an IDie. Thanks to the CQS Principle it becomes crystal clear. It is easy to determine a value of a die, and there's no surprises when a die is queries for it's value.

Now imagine a system with a significant number of components that violate this principle versus a system where components follow it. Can you imagine the difference?

2008/6/15

3 Years

Today is 3 years since I started working with the company I work today. It's being a long journey from figuring out what I want, till realizing what I am and need to be. The team has accepted all of my wildest ideas about the code and was very tolerant to the fact that I cannot wait to get something done. We've made a long way.

Besides improving as a software developer, I also realized a few bitter realities - it doesn't matter how good I am, still need to strive to be better. Besides the excellence in code, there must be a proficiency in human relationships. The code is not only about a single developer level, but about team level, because if you are the only one who can have fun with it, it is no longer fun.

Lessons are good, but I have to look forward and setup certain goals for myself, what do I want to achieve the next year? A lot.

  • I want the team to get to the point where I am right now, and I can do more for that
  • I want to have more fun while working, because without it work is useless
  • I want be more influencing people, help them realize themselves better, without getting into conflicts
  • I want to improve a lot myself, and by doing that to show, that you can achieve if you want to

Some of my targets will change or get updated, but the core set of goals will remain.

A lot ahead, I better start moving towards it.

2008/6/12

Code Smell vs. Code Stench

Interesting difference I picked up from a book this morning - code smell vs. code stench.

Code smell might indicate there's a problem in code that requires refactoring, but a closer evaluation might prove the smell is false alarm.

Code stench is an obviously bad/poor code that has to be refactored.

From now on I will be more accurate on describing the code issues :)

Google Shortcut Keys - Awesome

For all keyboard junkies out there - if you are also hooked on Google products (GMail, Reader, Calendar, etc), don't miss the option of using GMail with keyboard shortcuts. The are awesome. I loved the navigation shortcut (combination of pressing first G and then another key, neat).

To enable keyboard shortcuts, you will have to go to the settings under you GMail account and check off the option to enable it.

2008/6/11

Two Loosely Coupled Code - Part 2

In the

I raised the question of "Too loosely coupled design". There's a lot to discuss about it, and I am not going more time on it, except showing one more sample that IMHO shows the benefits and outcomes of the principle being applies, or consequences of not doing so.

Table 1

namespace Local.ADL.Home
{
  public class HomePresenter : IPresenter
  {
    private readonly IHomeModel model;
    private readonly IHomeView view;

    public HomePresenter(IHomeView view): 
                        this(view, new HomeModel()){}

    public HomePresenter(IHomeView view, IHomeModel model)
    {
      this.view = view;
      this.model = model;
    }

    public void Initialize()
    {
      view.Load += View_OnLoad;
    }

    private void View_OnLoad(object sender, EventArgs e)
    {
      if (!view.IsPostBack)
      {
        view.AssignInitialData(model.IsUserMemberOfPlanAOrPlanB(),
                model.CanShowSomething());
      }
    }
  }
}

Table 2

namespace Local.ADL.Home
{
  public class HomeModel : IHomeModel
  {
    public bool IsUserMemberOfPlanAOrPlanB()
    {
      return UserSession.IsPlanAorB;
    }

    public bool CanShowSomething()
    {
      return UserSession.ShouldSeeSomething;
    }
  }
}

Q: Can HomePresenter be tested based on the code in Table 1?

A: Yes. It has a parameterized constructor that accepts all dependencies for HomePresenter as contracts (interfaces) without knowing or carrying who are the real components that implement those contracts. Loosely coupled code, where we depend upon abstraction and not concrete implementation.

Q: Does HomePresenter is loosely coupled at run-time?

A: No. It has a direct dependency on HomeModel class. This is a tight coupling, meaning that anywhere in the code we used this type of coupling, we made HomeModel “visible” for HomePresenter, i.e. we violated the principle of depending upon abstraction and not concrete implementation. What would be a solution? Dependency Injection Principle with a standard container (lets call it DependencyResolver). Using this simple principle would change the code to be something similar to the code in Table 3. Now HomePresenter is loosely coupled to the implementer of the IHomeModel contract. Some configuration file / startup code will determine who is the actual implementer at run-time. Testing is still possible.

Table 3

namespace Local.ADL.Home
{
  public class HomePresenter : IPresenter
  {
    private readonly IHomeModel model;
    private readonly IHomeView view;

    public HomePresenter(IHomeView view): 
       this(view, DependencyResolver.GetImplementerOf(IHomeModel)){}

    public HomePresenter(IHomeView view, IHomeModel model)
    {
      this.view = view;
      this.model = model;
    }

    // ...

Q: Can HomeModel be tested based on the code in Table 2?

A: No. It is tightly coupled to the UserSession, which in its’ case is a static class and cannot be mocked / faked / taken out as a component that is not required to be tested at this moment.

To solve it:

  • UserSession has to be implementer of a contract, lets call it IUserSession
  • The implementer of IUserSession has to be supplied / injected as a dependency during construction time either directly or through container, similar to the example in HomePresenter code in Table 3