Too often in software engineering people are too quick to focus on the latest technology and reticent to develop their knowledge of the fundamentals. I suppose the reason for this is to build marketable skills. Recruiters and employers tend to focus on the technology their hiring managers (often other engineers) ask them for, which is usually the latest shiny thing and so the cycle continues.
Let’s start with describing what I mean by the fundamentals with some examples. The first set are typically the things you’d learn in a good Computer Science undergraduate programme. Examples are:
- Data structures
- Algorithms
- Operating system design
The next set are generally good things to know for any software engineer but aren’t always covered in mandatory modules in CS degrees. Things like:
- Design patterns
- Networking
- Low level computing
- Cryptographic primitives
- Bit twiddling
I could go on but you get the idea, you won’t regret learning these things, whatever you go on to do in software engineering you’ll find them useful, possibly essential. They will help you learn the latest shiny technology more quickly because you’ll know the building blocks of such things.
There’s more too, if you skip learning one to two cycles of shiny things you won’t notice it in a few months or years. Does anyone regret not learning grunt, then gulp, then webpack, not really, you just need one that works and nothing too bad happens if you skip one. Have little to no knowledge of networking or algorithms you’re severly going to limit what you are capable of.
So, should you avoid learning shiny new technology altogether? Absolutely not! Whilst learning those technologies you’ll pick up reusable skills for other tech, but guess what, those reusable things are the fundamentals. Thus if you want to accelerate your speed or learning, reduce those difficult learning curves, make sure you’re spending enough time looking at the basic underpinnings of computer science, they’re so important.
—Andy Hedges
This topics comes up a lot: “how do I do authorization for my service architecture?” or if they are hip with the kids “how do I do authorization for my microservices”. The answer to both is the same…
Firstly some definitions:
- Authentication
- the process of confirming, to a level of certainty, a user is who they say they are. Often this is done with a username and password pair, but could be done with a certificate, PIN, token, fingerprint or anything else.
- Authorization
- the process of making sure that people can only do the things they should be allowed to and see the data they should be allowed to.
The Authorization-as-a-Service Anti-Pattern
Now at first guess it might make sense to have a service that does authorization. Why not, you can put all that complexity in one place and not worry about it anymore, safe in the knowledge that all that difficult authorization logic is encapsulated.
Trouble is when you add a new feature in an other service you need to make a change to your authorization service, to enforce the correct access to that service. It turns out everytime you make a change to any other service 9 times out of 10 you are then making a modification to the authorization service. This quickly gets tedious - it smells wrong.
Say you decided to live with the inconvience of the above double modification problem, who do you get to maintain and run the authorization service. You could have one team do it. However fairly rapidly they are going to be inundated with change requests, because every change to any other services needs a change to their service (most of the time at least).
The other option is to allow the teams who require the change to make the changes to the authorization service themselves. Trouble is then you have many teams churning a service’s code base that they don’t own then they don’t feel, indeed literally they don’t have, ownership and that’s a recipe to declining quality.
On top of all this, the releases of the authorization service needs to be sychnorized with all the other services that have been modified recently. Pretty soon you are in a stop-the-world type release process where every service in your estate needs releasing at the same time. The logistics are a nightmare.
The Solution
The simplest solution to the problem is to have authentication as a service; that is proving I am who I say I am.
Once you have the ability for a service to determin within a level of certainty that a user is who they say they are, then you can do authorization in each service. What better place to have the complex logic of who can do what than in the code that does the what.
For example consider a service that is responsible for providing access to a financial trading platform. It allows brokers to buy and sell a stock. Now the service might be aware that certain brokers can only buy €100k of the stock each day, it keeps track of this, because that’s what it does, rather than reaching out to an external service to ask, it has the information right there, it knows who you are, what you’ve bought and the rules for how much you can buy - it’s cohesive. Now say you want to change it so that brokers can only buy stock Monday through Friday, again all the information is there. There is no need to go anywhere else.
Perhaps you might write a library, a shared object, dll, jar or npm for it that others can reuse. JaaS and implementations thereof are a good example of something approximating a good design here, but don’t create a service, you’ll regret it.
—Andy Hedges