9.25.2013

Usability of Click To X emailed links

It's pretty common to get emails with links like the following:

  • Your package shipped, click to track
  • So and so sent you a friend request, click to accept
  • Your order is complete, click to view

I'm usually annoyed when I click the link and have to login, especially on mobile devices.

Frustration: the information usually isn't that sensitive.

It's beyond me why LinkedIn requires me to login to accept a connection.

Frustration: the sensitive information is already in the email.

Amazon, the tracking number is in the email, why do I have to login to view the tracking information via Amazon's system? This probably is a problem in about every system that sends tracking information.

If you inline the details of my order in the email, why require me to login to get the fancy PDF?

If someone compromised my email they can reset my password. Some could argue I'd know my password was reset, might not matter if the information is that important.

Frustration: I only have to login on a mobile device.

If I don't have to login on a desktop, make sure the same happens for mobile.

Make sure redirects to a "mobile friendly" version of the site don't pooch my ability to follow through on a mobile device (LinkedIn...)

Recommendation: One-time passwords

Many of these links include a random identifier and are prefixed with https, not http. I like to think of these as one-time passwords to access my account. If it makes you feel more secure, only allow access to the part of the account pertinent to the link.

Consider expiring links once the action is executed (accepting a friend request).

Consider expiring links after a time period if the information is sensitive (bank statements).

Why the fuss?

Because these emails are clogging the inboxes of the world, waiting for us to get back to, like we don't have enough of those already :). I'm of the mentality Do it or Defer it. The easier it is to Do the more likely I'll Do it instead of going to the trouble to Defer it.

Possible objections

  • "But after you add a friend, the system may want you to write on their wall or do some other thing?"
    • No problem, the link is basically a one-time password to access my account, have the link open the site to do that.
    • Or, prompt me the next time I login to the site.
  • "What about bank accounts"
    • Banks usually require more than email to reset a password, so I'd suggest either an expiring link or logging in, I'm usually not too annoyed by authenticating when accessing my bank account.
  • "What if someone else gets the link"
    • How did that happen? Probably a bigger problem than accepting my friend requests.
    • If the link is over https, if someone man in the middles that, they can man in the middle your username and password too.
    • No one is shoulder surfing a GUID.
  • Others? Please send them, I'd love to consider how I may be blatantly missing something of importance about this topic :)

Raised objections

  • "What about services that follow links to make sure they aren't viruses?" Ryan Ohs
    • Good point, in these cases if the link is an action I'd recommend having an "Accept" (fried requests), or some sort of "Are you sure". Probably a good idea in the event someone accidentally opens the link too.
    • And of course only expire the link after the action is executed

TLDR

Seriously consider sending links that don't require logging in, when it makes sense, it'll make everyone's life easier.

9.24.2013

Map Then Collect

Iterating through a collection of data and mapping to a new type is a rather routine development task. Here are various ways to do this. At the bottom I have a list of things to consider. What conclusions do you come to?

Note: in LINQ the map operator is named Select

Mapping

for Loop

public List<Output> ForLoop()
{
    var outputs = new List<Output>();
    var inputs = GetInputs();
    for (var i = 0; i < inputs.Count(); i++)
    {
        var input = inputs[i];
        var output = new Output();
        output.Id = Convert.ToInt32(input.Id);
        outputs.Add(output);
    }
    return outputs;
}

foreach Loop

public List<Output> ForEachLoop()
{
    var outputs = new List<Output>();
    foreach (var input in GetInputs())
    {
        var output = new Output();
        output.Id = Convert.ToInt32(input.Id);
        outputs.Add(output);
    }
    return outputs;
}

Functional ForEach

public List<Output> FunctionalForEachLoop()
{
    var outputs = new List<Output>();
    GetInputs()
        .ForEach(input => MapAndAdd(input, outputs));
    return outputs;
}

private void MapAndAdd(Input input, List<Output> outputs)
{
    var output = new Output();
    output.Id = Convert.ToInt32(input.Id);
    outputs.Add(output);
}

Functional Map Then Collect

public List<Output> FunctionalMapThenCollect()
{
    var outputs = GetInputs()
        .Select(input =>
        {
            var output = new Output();
            output.Id = Convert.ToInt32(input.Id);
            return output;
        })
        .ToList();
    return outputs;
}

Functional Constructor Map Then Collect

public List<Output> FunctionalConstructorMapThenCollect()
{
    var outputs = GetInputs()
        .Select(input => new Output(input))
        .ToList();
    return outputs;
}

Adding Filtering

foreach With Filter

public List<Output> ForEachWithFilter()
{
    var outputs = new List<Output>();
    foreach (var input in GetInputs())
    {
        int id;
        if (!Int32.TryParse(input.Id, out id))
        {
            continue;
        }

        var output = new Output();
        output.Id = id;
        outputs.Add(output);
    }
    return outputs;
}

Functional Map Then Filter Then Collect

public List<Output> FunctionalMapThenFilterThenCollect()
{
    var outputs = GetInputs()
        .Where(InputHasValidId)
        .Select(input => new Output(input))
        .ToList();
    return outputs;
}

private bool InputHasValidId(Input input)
{
    int id;
    return Int32.TryParse(input.Id, out id);
}

Considerations

  • Readable
  • Understanding / Confusing
  • Composition
  • Extensible
  • Intent
  • What is explicit?
  • What is implicit?

For reference

public class Input
{
    public string Id { get; set; }
}

public class Output
{
    public Output()
    {
    }

    public Output(Input input)
    {
        Id = Convert.ToInt32(input.Id);
    }

    public int Id { get; set; }
}

9.13.2013

Encapsulated Request Pattern

Many times we need to make requests to external systems when integrating applications. I've noticed a pattern I like when making these requests that simplifies understanding what all is involved.

Procedural submission

It's easy to end up with procedural code to execute requests, something like:

// detect condition to send remote request
    request = BuildRequest()
    client = CreateClient()
    response = client.Submit(request)
    if(response.Error) throw new Exception(...)
// continue with our code

Right in the middle of our application code, we conditionally decide if we need to submit a request, then we build, send and validate it all inline in our application code. Sometimes we make this one step better by extracting functions to deal with the request in some static class or injected service. This is compounded when we have multiple request types and we start to try to re-use parts of the process and end up with conditionals bleeding into the consumer code:

// detect condition to send remote request
    request = BuildRequest()
    client = CreateClient()
    response = SubmitRequest(client, request)
    if(response.Error) throw new Exception(...)
// continue with our code

// SubmitRequest(client, request)
    if(request is ThisTypeOfRequest)
        return SubmitThisTypeOfRequest(client, request);
    if(request is ThatTypeOfRequest)
        return SubmitThatTypeOfRequest(client, request);

// SubmitThisTypeOfRequest(client, request)
    // special code for This Type
    return client.Submit(request);

// SubmitThatTypeOfRequest(client, request)
    // special code for That Type
    return client.Submit(request);

This can get pretty hard to manage, and in some cases validating the response becomes conditional too and often this happens:

// detect condition to send remote request
    request = BuildRequest()
    client = CreateClient()
    response = SubmitRequest(client, request)
    if(response is ThisTypeOfResponse && response.Error) throw new Exception(...)
    if(response is ThatTypeOfResponse && response.InvalidWhatever) throw new InvalidException(...)
// continue with our code

Sometimes that response handling code at least ends up in the Submit methods that are extracted, either way it's pretty hard to follow as the parts of each request (building, submitting, validating) are scattered throughout some highly procedural code. It becomes hard to follow and prone to duplication and mistakes :(.

Encapsulated requests

One way I've found to help make things more apparent is to create a type per request. Like an anti-corruption layer around the request. In here I'll build, submit and validate each request:

// detect condition to send remote request
    request = new ThisTypeOfRequest()
    request.Submit()
// continue with our code

or

// detect condition to send remote request
    request = new ThatTypeOfRequest()
    request.Submit()
// continue with our code

class Request
    function Submit()
        request = Build()
        client = CreateClient()
        response = client.Submit(request)
        Validate(response)

class ThisTypeOfRequest extends Request
    function Build()
        // special code for This Type
    function Validate(response)
        if(response.Error) throw new Exception(...)

class ThatTypeOfRequest extends Request
    function Build()
        // special code for That Type
    function Validate(response)
        if(response.InvalidWhatever) throw new InvalidException(...)

Now, everything involved with a single request is in one class, in one file, one place to see what is going on! And in some cases, things like Submit can be shared across request types, and if it varies, it can be overridden. This pattern brings readability and re-use to the solution. Now consumers don't have to manually compose building, submitting and validating requests, they can focus simply on which requests to execute.

Steps to refactor to Encapsulated requests

If you have procedural code like this, try these steps to gradually refactor to this pattern:

  • Extract conditional building code into a single Build method that all consumers use
    • Then, in time, remove the conditionals and move the Building code for each request type into it's own class
  • Do the same for conditional submission code
  • Do the same for conditional validation code
  • Have patience to refactor in this direction over time, don't worry about doing this all at once.

Composing requests

Sometimes an event in our system triggers a need for multiple requests, almost as if the composite request doesn't exist in the external system. It becomes trivial to compose requests with this pattern:

class CompositeRequest extends Request
    function Build()
        _ThisRequest = new ThisTypeOfRequest()
        _ThatRequest = new ThatTypeOfRequest()
    override Submit()
        _ThisRequest.Submit()
        _ThatRequest.Submit()
    function Validate(response)
        // maybe nothing to do here

Now we can easily compose, with conditionals, multiple requests! Imagine if consumers had to compose this every time they needed this series of requests!

Analysis of pattern

  • Pros
    • Readability, one stop spot to see what all is involved with a request
    • Re-use
    • Avoids mistakes when consumers don't ensure all steps are executed
    • Composable
  • Cons
    • Time to refactor in this direction
    • Getting crazy with inheritance re-use. I'd recommend using a common interface (Build/Submit/Validate) but beyond that use composition.
8.26.2013

Automated testing as a tool, not an obligation

Yesterday I stumbled upon a discussion about unit testing private functions. Many of the responses were very prescriptive (never do this, just say no). In other testing discussions I've heard many advocate 100% coverage via automated testing, an attempt to test everything. In general I find a lot of prescriptive guidance around testing.

Why do we test?

Whenever I experience prescriptive guidance, I can't help but defiantly ask why?

Why do we test?

  • to verify behavior
  • to build confidence
  • to document behavior
  • to tease out design (TDD)
  • and many others.

These reasons are the obligations that drive me to test. Testing to me is a means to these ends.

Automated testing as a tool

When I first got into automated testing, I jumped on the bandwagon of the test everything mentality. I actually recommend trying this if you haven't experienced it, nothing helps you see testing as optional faster than experiencing cases where it truly does just get in the way and adds no value.

Once I realized it can be a burden, I started to think of automated testing as a tool (an option, not an obligation). I started to keep track of which situations I felt it added value and which ones it just got in the way.

I found extreme value in automated testing of complex calculations, component logic, projections, aggregate behavior and interactions with remote systems. Other areas, especially integration layers like a controller (MVC) or service boundaries were often way more work than they were worth. In these cases I found focusing on simplicity and keeping logic out of these layers was a better approach.

The reality is there are other equally valid tools for the job. Reading code is another tool to verify behavior and to build confidence. So is manual testing. Sometimes these are just as effective as automated testing. Sometimes they aren't. Sometimes they are very complementary.

When treated as a tool, I quickly realized that many forms of automated testing gave me a new level of confidence I'd never had before. Some tests were saving me hours of time versus manually verifying behavior, even on the first iterations of development! And some tests were just not worth the hassle. Testing literally became a no brain-er for me in many situations.

Time and intuition have developed an almost innate ability to pick up and put down the "automated testing tool," instinctively knowing when it's adding value and when it's not.

Spreading the good word

Once, I saw the "light", I wanted to spread the good word. Unfortunately, in my haste, I fell prey to being prescriptive. Though I restricted my prescription to areas I felt a lack of confidence or a lack of verification, I failed to communicate it as such. As a result, I often noticed a lack of quality in the resulting tests: missing scenarios, rushed implementations, copy/pasting, readability issues etc. And when testing wasn't explicitly requested, there rarely was any.

In situations where I conveyed my concerns about confidence and verification, the quality of the tests dramatically increased.

Instead of asking for tests of X, Y and Z, if we ask "How do we verify X?" or "Are we confident of Y?" or "In what situations does Z apply?" we can weigh the pros and cons of using automated testing versus other tools to answer these questions.

If we look at automated testing as a tool, a tool we need to study, practice and perfect our usage of, I think people will pick up on the good word faster. If automated testing is optional, but people know the value of it, I bet we'd see more of it as a result, after all, it is a very powerful tool.

7.23.2013

Adding OWIN to an empty ASP.Net MVC app

I've been playing around with the new ASP.Net MVC 5 samples and wanted to share how you can quickly inject OWIN into an empty MVC app and for that matter any ASP.Net app. I'll admit I haven't found a ton of documentation about this yet so this is just me hacking around and wanting to share what I found.

  1. Start out by making an empty MVC project.
  2. Install Microsoft.Owin.Host.SystemWeb
    • Install-Package Microsoft.Owin.Host.SystemWeb -Prerelease
    • This has a type OwinHttpModule that gets loaded dynamically via Microsoft.Web.Infrastructure that "injects" the OWIN infrastructure.
  3. Add a Startup class to configure OWIN
    • This is where you configure your OWIN middleware, this is by convention
          public class Startup
          {        
              public void Configuration(IAppBuilder app)
              {
              }
          }
  4. Do something with OWIN
    • Install-Package Owin.Extensions
      • Nice extension methods to simplify the verbosity of creating middleware
    • I found these ideas in Getting Started With OWIN, Katana, and VS2013
    • Something simple like this can interrupt the process and return a result from OWIN middleware app.UseHandler((request, response) => response.WriteAsync("OWIN Hello World"));
      • This is very similar to the style you'll find in nodejs express apps.
    • This will allow the request to pass through the OWIN infrastructure and be handled by MVC but it will tack on a header to the result.
      app.UseHandler((request, response, next) =>
      {
          response.AddHeader("Hello", "World");
          return next();
      });