Sunday, January 30, 2011

Returning to current page after login

This is one of the must have conveniences of a modern web-site: if a logged out user encounters a page that requires a login then - after logging in the user goes directly to that original page (instead of staying on the login page or going to some other predefined page). Here is a quick list of possible high-level solutions - anything missing? What is your choice?

1. No redirect

Either you have the login form on every page (a small one) - or you can display the login form instead of the page text if the login is required. You need more then a small box to fit in all the currently broadly used options like OpenId or logging in via Facebook - so for a universal solution you need a full page. Let's focus on displaying the login form on a page requiring authentication instead of that page content. This is a very simple solution - would it break any of the HTTP protocol rules? But then wouldn't displaying the error message saying 'Login required' break the same rule?

2. Passing the current url in the link to the login form

The minus of this solution is the ugly url of the login page. I also read somewhere that in some implementations there is a security problem - but I cannot find now any reference about it (it was something about crafting the uri param in a way that resulted in two http requests when the redirection was done).

3. Saving the current url in the session

Additionally to all the problems with sessions (and for example multiple tabs open to the site), there is a slight efficiency disadvantage if we do that for each link to the login page, because the session then needs to be saved every time. If the session is save to the database I imagine that this could have a slight impact.

4. Using the Referer HTTP header

This would also be quite simple - but can we rely on it? Additionally it would also require passing that url from that header back to the form for the case when the first login attempt fails. This can be done with hidden field - and since everyone uses POST for the login form method this would not spoil the login page url (or it can also be done with a session - but this time the session would be saved only in the case of a failed login).

This would only work if the user followed a link from the current page to the login page (presumably displayed together with the authentication required error message). But actually it is better to automate that step and:

5. Redirecting both to the login page and from it

This still requires saving the current page in the url (as in 2) or in the session (as in 3) - but without saving current url in the session at every page containing a link to the login page. It can also be combined with 4 if additionally to this mechanism we want to have have links to the login page that would lead the user back to the original page. From the user perspective this is as convenient as 1 but might be a bit more clean from the technology perspective (see Dave's comment below - although is 303 more correct here?). Anyway - this is the solution used by CatalystX::SimpleLogin (and Catalyst::ActionRole::NeedsLogin).

Updates: Added 5.

Monday, January 10, 2011

Is $ responsible for the 'ugliness' of Perl code?

We cannot hide it that Perl code is littered with the $ characters and, compared to the original well rounded Latin letters, that went through the thousands of years of tweaking to please the human eye, compared to them, $ is just an ugly hack. Unfortunately this is what people see when they first look at Perl code - lots of $ signs (by the way @ looks a bit better - maybe we should use more arrays?) - and this is how unconsciously they form the first impression about our language. This is not fair, this is so superficial - but the way the human mind works dictates that this first impression colours every information about Perl that comes later. People don't like to change their minds, and they always will find something to support what they thought initially, even if, or maybe the more so when, that initial thought was just an unconscious impression.

What can we do then? Changing the typeface of $ in the most popular web and editor fonts does not seem like a practical solution, but maybe if we show the sheer shallowness of judging the language by the shape of the typeface of some used character - maybe this would have some impact?

Update: Bear in mind that I don't advocate to get rid of $ in Perl - I find it very useful. The point is that the type face ugliness of $ can project a shadow on the whole language completely independently from it's usefulness as language construct.

Thursday, January 06, 2011

Dependency Injection - some updates

I finally found a succinct and clear definition of Dependency Injection:

Dependency injection means giving an object its instance variables instead of letting it create them.

based on answers to What is dependency injection? on Stackoverflow. There are some variations on how you do that - you can pass the instance variables in the call to the object creator (the new method) or you can use a setter to pass it to the object after it is created. This is exactly what I was thinking. Inversion of Control here happens only if you use a framework that takes over the object creation - but this is not required for the practice of DI. The name does not fit too well to its definition - but it is probably too late to change it.

Reasons to do DI:

  1. The most immediate reason is that it makes it easy to use mockups (or even undef's or Nulls) for the dependencies in tests. But this is is just a concrete example of the more general reasons that follow.
  2. To change the coupling between the main class and the dependency from control coupling to data-structured coupling (Types of coupling in wikipedia). Intuitively this also means increasing the encapsulation of the main module.
  3. To remove more frequently changing code from inside of less frequently changing code. There is an analogy between hardcoded literal constants and hardcoded objects - this is the main subject of my previous post.

It is worth noting that Moose by taking over the new method encourages DI, but of course people will always find ways to sidestep this by creating an init or setup method or using BUILD or BUILDARGS from the Moose API.

Tuesday, January 04, 2011

Dependency Injection or Removing Hardcoded Values?

Ever since I've heard about Dependency Injection (DI) a few years ago, I read and reread all the available documents and I kept having this feeling that I still miss something. Yesterday after some googling - I found that even those whom I always expected to explain things, have similar problems with it (see also this interesting reply to that rant). I am not sure if I now really understand DI, maybe I am still missing something important, but here is my tentative theory about it.

Let us say that somewhere deep in your web app code you have these lines:

Every minimally experienced programmer will notice immediately that for any re-usability the database name, user and his password should be extracted into a place where they can be changed easily, like the first lines of the program or better a config file. This would come very natural - but the reasoning behind it does not come from any theory - it is our experience that tells us that these pieces of data will change more frequently then the surrounding code.

I don't know if anyone would call this Dependency Injection, I think he would rather say that he is removing hardcoded constants.

Now let's take this snippet:

This is better - but the name of the DBI class and the way you construct the $dbh object is still hardcoded here - the point about DI is that this is still wrong because these parts also will change more often then the rest of the MyClass. The most important case for this is tests. In Perl it is possible to change the definition of the whole DBI package (mock it up) for the tests - but a more elegant solution is to move the database connection creation out of the MyClass code:

then, to test the MyClass methods that don't use the dbh field, you could pass an undef there and not bother with setting the database at all. But it is not only tests that require changes to that code - if for example at some point you decide that you want to log all the DBI warnings and add { PrintWarn => 1 } to the DBI->connect call - this would also be easier with this design. Again, just like with the initial example, I haven't seen any theory explaining this, but from my programming practice I am assured that this kind of change happens much more often, and at different phases of development, then changes to the rest of the MyClass code. Maybe the distinction is about what i.e. values (literals or objects) and how i.e. methods and subroutines - what is more expected and easier to change - and to get the advantage of that ease you cannot mix it together with how.

The code removed in the last sample is a bit more complicated then in the initial example - but at the core it has the same nature - it is about computing some values that are later used across a program part (or the whole program). In the initial example these values are literals, here they are objects. Literals can be created independently, objects depend on other objects: we can have a MyUser that depends on MyClass that (as in our example) depends on the database connection. Fortunately solving the dependency graph and finding out what needs to be created to have a MyUser object can be automated - this is what the various DI frameworks (like Bread::Board) do. In more 'strictly' typed languages like Java - this dependency graph is mostly defined by the types used, in Perl the dependency needs to be defined by the programmer explicitly - but the graph solving works in the same way. This is why this object creation code is (or can be made) quite simple and for all objects in the same scope it can fit into one package where you could adjust the various cooperating objects just like you do with the values of the configuration variables.

This is my understanding of Dependency Injection - maybe I am still missing something - but I don't see where, in any non-convoluted way, there is the Injection happening. There are no new dependencies injected into the code. Maybe more appropriate would Dependency Passing - as the dependencies are passed as parameters - but most of the work done when performing this refactorisation is removing parts of code, parameter passing is the trivial part. Additionally Inversion of Control, which is used to explain DI in many places, is just a minor characteristic of it, not very visible one and very different from other more common Inversion of Control occurrences. Mark Fawler coined the term Dependency Injection specifically to differ it from Inversion of Control in general - but I think that even presenting it as an example of IoC is misleading, because it is not very important to understand what is going on and it is so different from the Hollywood Principle that everyone thinks about when reading Inversion of Control. Finally what is frequently blurring explanations of DI is the details of the DI frameworks used and dwelling over constructor injections or setter injections - i.e. going into the how before the why is well explained.

I believe that removing hardcoded values is what Dependency Injection is really about. Most programmers already have good intuitions on why this is needed.