It's pretty common to get emails with links like the following:
I'm usually annoyed when I click the link and have to login, especially on mobile devices.
It's beyond me why LinkedIn requires me to login to accept a connection.
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.
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...)
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).
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.
Seriously consider sending links that don't require logging in, when it makes sense, it'll make everyone's life easier.
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
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;
}
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;
}
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);
}
public List<Output> FunctionalMapThenCollect()
{
var outputs = GetInputs()
.Select(input =>
{
var output = new Output();
output.Id = Convert.ToInt32(input.Id);
return output;
})
.ToList();
return outputs;
}
public List<Output> FunctionalConstructorMapThenCollect()
{
var outputs = GetInputs()
.Select(input => new Output(input))
.ToList();
return outputs;
}
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;
}
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);
}
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; }
}
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.
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 :(.
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.
If you have procedural code like this, try these steps to gradually refactor to this pattern:
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!
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.
Whenever I experience prescriptive guidance, I can't help but defiantly ask why?
Why do we test?
These reasons are the obligations that drive me to test. Testing to me is a means to these ends.
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.
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.
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.
Install-Package Microsoft.Owin.Host.SystemWeb -Prerelease
public class Startup
{
public void Configuration(IAppBuilder app)
{
}
}
Install-Package Owin.Extensions
app.UseHandler((request, response) => response.WriteAsync("OWIN Hello World"));
app.UseHandler((request, response, next) =>
{
response.AddHeader("Hello", "World");
return next();
});