Tagged with Design

I like to dance

A couple of years ago me and my wife took dance lessons. I thought it was very challenging since I had no idea of how to get my body to move like the instructor showed us, in pace with the music and at the same time leading my partner and protecting her on the dance floor from getting hit by other dancers. After weeks and months of practice I managed to master dance after dance and it just got more and more of a joy. Why? Simple! I had learned to master the steps. Learned how to feel the music. Learned how to plan and create a choreography that was suitable for me and my partner – for our team.

As a software developer I have made many mistakes. I have been in scenarios where I have been to junior for the responsibility given to me. I have produced bugs and misinterpreted specifications. I have produces architectural solutions that didn’t make the cut. For every failure though, I have gone home, sat my self down, trying to evaluate and come up with other ideas. Studying other developers work to see alternative solutions. Everything for evolving my skills. And that’s a good start but still, no matter how smart solutions you produce, they mean nothing if the team isn’t on the same track. It doesn’t matter if you understand how every part works together. What matter is that everyone in the team feels comfortable with the solution and feel that they can be productive. It should also be easy to introduce new members in the team. That’s something I think is foreseen. To much focus is put on creating “hyped solutions” using the latest frameworks and “buzziest” patterns without looking at the maturity of the team. Without thinking about the developers that will administer the software when all consultants and/or initial staffing has left.

Balance. Yes, I know it’s a vague word, but you must try to balance the complexity of the solution seen to the team. That’s one of the most important thing I have learnt and used. Listen, back down and adapt and you will conquer. I know it’s tempting to be “cool”, but sometimes a step in another direction might be better. Keep this in mind and remember to be open minded.

//Daniel

Tagged , ,

Let business scenarios be reflected in your code

I’m working with a project where I use something I call “scenarios”. The idea is that each scenario in the businessmodel is represented by three classes.

Command – Contains the inputdata needed to perform the Scenario. Is optional since the operation might not need any input parameters.

Scenario – Validates and Executes the Command and is where the logic is kept. It is not ment to cross boundraries. It also provides an eventmodel, publishing events for Validated, Executed etc.

Result – Contains the command (input data), any exception and violations generated by the Validation- or Execution step in the scenario, as well as scenariospecific outputdata.

The reason for why I wan’t this is that I want each scenario easily detected in my coding-model. I want to be able to quickly look in the solutionexplorer in the Scenarios namespace, and directly see what the system targets in the domain. By looking at the Command- and the Result-classes I can also see what the scenario accomplishes. By isolating each scenario-flow-logic to one single class, I hopefully achieve a more cohesive and readable class.

An example

The example is not drawn from the business model since it’s about signing in to the system, hence it’s sort of an indirect business scenario, since you can’t run the “Place order scenario” if you’r not an authorized user.

The shown example is about logging in to the system and is using OpenId in an Asp.Net Mvc 2 application. This concludes two steps. First a request has to be initiated to an OpenId-provider. Second, we need to handle the callback request from the provider, hence the enum LogOnSteps. (I guess it would have been more clear to put these in two different scenarios.)

[Serializable]
public enum LogOnSteps
{
    Initiate,
    Finalize
}

The Command contains properties that are required for Step 1 as well as a flag indicating where we are in the process so that the validation and execution in the scenario-class nows what to do.

[Serializable]
public class LogOnCommand
{
    public LogOnSteps Step { get; set; }

    public string OpenId { get; set; }

    public string ReturnToUrl { get; set; }

    public LogOnCommand(LogOnSteps step)
    {
        Step = step;
    }
}

The implemented scenario extends a baseclass so that boilerplate code for catching exceptions etc. is kept away. The scenario is defined in an interface and is accessed via an IoC-container.

public class LogOnScenario : Scenario<LogOnCommand, LogOnResult>, ILogOnScenario
{
    public IOpenIdAuthenticationService AuthenticationService { protected get; set; }

    public IMembershipService MembershipService { protected get; set; }

    public LogOnScenario(
        IOpenIdAuthenticationService authenticationService,
        IMembershipService membershipService)
    {
        AuthenticationService = authenticationService;
        MembershipService = membershipService;
    }

    protected override IViolations OnValidate(LogOnCommand command)
    {
        var violations = new Violations();

        if (command.Step == LogOnSteps.Initiate)
        {
            violations.AddIf(command.OpenId.IsNullOrEmpty(), new Violation(
                ResourceStrings.LogOnCommand_OpenId_IsRequired, CommandName, "OpenId"));
            
            violations.AddIf(command.ReturnToUrl.IsNullOrEmpty(), new Violation(
                ResourceStrings.LogOnCommand_ReturnToUrl_IsRequired, CommandName, "ReturnToUrl"));
        }

        return violations;
    }

    protected override LogOnResult OnExecute(LogOnCommand command)
    {
        return command.Step == LogOnSteps.Initiate
            ? HandleInitiateStep(command)
            : HandleFinalizeStep(command);
    }

    private LogOnResult HandleInitiateStep(LogOnCommand command)
    {
        var logOnResult = new LogOnResult
        {
            Command = command,
            MvcActionResult = AuthenticationService
                                .InitiateMvcAuthentication(command.OpenId, command.ReturnToUrl)
        };

        return logOnResult;
    }

    private LogOnResult HandleFinalizeStep(LogOnCommand command)
    {
        var logOnResult = new LogOnResult { Command = command };
        var openIdAuthentication = AuthenticationService.AuthenticateRequest();

        if (openIdAuthentication.Violations.IsNotEmpty)
        {
            logOnResult.Violations.Add(openIdAuthentication.Violations);

            return logOnResult;
        }

        var mapper = IoCContainer.Instance.GetInstance<IObjectMapper>();
        var identity = mapper.Map<OpenIdAuthentication, Identity>(openIdAuthentication);
            
        logOnResult.UserSession = new UserSession(identity);
        logOnResult.Member = MembershipService.GetByOpenId(identity.OpenId);

        return logOnResult;
    }
}

Since we want every scenario to return any caught exception and violations, we have a base-class that the ScenarioResults can extend, which contains members for this.

[Serializable]
public class LogOnResult : ScenarioResult
{
    public LogOnCommand Command { get; set; }

    public ActionResult MvcActionResult { get; set; }

    public IUserSession UserSession { get; set; }

    public Member Member { get; set; }
}

Now if we take a look at some consumer code, I think it gets a bit easier to understand, and the application controller only handles logic for controlling which view and viewdata should be presented.

Step 1 – Initiate the scenario

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOn(LogOnViewModel viewModel)
{
    if (!ModelState.IsValid)
        return View(viewModel);

    var returnToUrl = Url.AbsoluteUrlFromAction("AuthenticateOpenIdRequest");
    var command = new LogOnCommand(LogOnSteps.Initiate)
                      {
                          OpenId = viewModel.OpenId, 
                          ReturnToUrl = returnToUrl
                      };

    var scenario = IoCContainer.Instance.GetInstance<ILogOnScenario>();
    var scenarioResult = scenario.Execute(command);

    if (!scenarioResult.Succeeded)
    {
        this.HandleScenarioResult(scenarioResult);
        return View(viewModel);
    }

    return scenarioResult.MvcActionResult;
}

Step 2 – Finalize the scenario

public ActionResult Authenticate()
{
    WebUserSession.SetGuest();

    var viewModel = new LogOnViewModel(OpenIdProviders);
    var command = new LogOnCommand(LogOnSteps.Finalize);
    var scenario = IoCContainer.Instance.GetInstance<ILogOnScenario>();

    var scenarioResult = scenario.Execute(command);
    if (!scenarioResult.Succeeded)
    {
        this.HandleScenarioResult(scenarioResult);

        return View("LogOn", viewModel);
    }

    if (scenarioResult.Member == null)
        return View("SetupNewMembership");

    if (!scenarioResult.Member.IsActivated)
        return View("ConfirmMembership");

    WebUserSession.Set(scenarioResult.UserSession);

    if (WebUserSession.Current.IsAuthenticated)
        return Redirect("~/");

    return View("LogOn", viewModel);
}

That’s it.

//Daniel

Tagged , ,
Follow

Get every new post delivered to your Inbox.