Sunday, 25 February 2024

Resting in Style

 


The majority of software engineers who have had any exposure to server side applications, either by building them or consuming their functionality, will be familiar with the idea of a RESTful API.

Sometime the concept of an API being RESTful is framed just in terms of its interface, its use of URIs, HTTP verbs etc.

However Representational State Transfer (REST) actually goes beyond just a definition of an interface and describes an architectural style for how server side software can be built and consumed by clients.

Early Days of the Web

By the early 90s the web was starting to become prevalent in peoples lives with websites becoming available beyond the academic institutions that had pioneered the web's invention.

As it became clear that the web's adoption was growing at pace, pressure started to grow to formalise its as yet relatively loose architecture. This flexibility was one of the web's strengths but without some formal standards to govern how its functionality could be consumed there was a risk it would become fractured.

To address these concerns organisations such as the World Web Consortium (W3C) and the Internet Engineering Task Force (IETF) put together a series of working groups to document a more formal approaches to some of the key web technologies such as HTTP an HTML.

One of the people involved in these working groups was a computer scientist called Roy Fielding. As part of this work Fielding developed the concept of a REST architecture that cumulated in his 2000 PhD thesis "Architectural Styles and the Design of Network-based Software Architectures".

This thesis defined a series of constraints that when followed would create a system with a RESTful architecture.

REST Constraints

The first REST constraint is the one we are maybe most familiar with, that of a Uniform Interface. The constraint dictates that your system should have a uniform API interface where data within your system is represented by a collection of resources.

Resources might be customers, products, user reviews or any other data your system provides access to. Request URIs identify the resources they want to work with. The data returned in API responses are a representation of a resource rather than necessarily being tied to how the resource might be stored in the backend.

Resource representations are self describing to give the client all the required metadata in order to process the data, an example of this would be the Content-Type header that includes metadata about the data representation. Resources should also demonstrate Hypermedia as an Agent of Application State (HATEOAS) where it provides links that can be used to obtain related resources, such as customer linking to their previous orders.

The next constraint is that of Client/Server, this states that clients and servers should be able to evolve independently without a dependency on each other. A client should know only about the API interface being offered by a system and have no knowledge or dependency on how that interface is being implemented.

A constraint which follows from the client/server approach is that of a Layered System. Building a system as a series of layers allows for a loosely coupled architecture where multiple systems maybe involved in data processing and storage whilst a uniform interface is presented to clients.

The next constraint says that all interactions between a client and server should be Stateless. A server should not store state related to previous requests from a client. If a client applications state is relevant in the processing of a request then this request should contain all the necessary information the server needs in order to process it. An example of this would be the fact that all requests should contain authentication and authorisation information to prove a user of the client has previously logged in.

Resources will often not change on a frequent basis, in order to address this and make sure interactions are efficient, then each resources should indicate whether or not it is Cacheable. This involves both the resource representation indicating if its cacheable and for how long, as well as clients being able to query if the resource representation they currently have is still accurate.

The final constraint was deemed optional and is not one that you will see frequently applied. Mostly when consuming APIs they will be data driven and provide static representations of data in formats such as JSON, HTML or XML. However a situation was envisioned where it might be necessary for an API to return functionality to deal with data as part of the response. The Code on Demand constraint described how an API could return executable code alongside data to increase the functionality that could be offered via APIs.

Modern Relevance

The use of the web in the modern world is probably far beyond even that which was envisioned in the early 90s when the need for engineering standards was first being identified. 

It is testament to the work done by the working groups involved that the REST constraints are as relevant today as they were then.

You will not see many server applications that completely follow all these constraints, some pragmatism is often required to adapt them to your particular application and its nuances. 

What is more important is to value the architectural properties they promote. Scaleability, modifiability, portability and reliability are examples of these properties that are never going to fall in or out of fashion even if the technologies being employed are subject to these changes in favourability.

Good engineering and an understanding of what good looks like for an application will always remain relevant even if the world the applications exists in does.

Sunday, 4 February 2024

Leading in Software Engineering

 


Aspiring software engineers are often keen to understand how they can progress in their career to a leadership position within their team or their organisation.

Clearly a certain level of technical competence is going to be a requirement but there is also a number of soft skills that are often the make or break factor. 

If you have the correct aptitude then correcting any omissions in technical knowledge can be easily addressed, but developing the softer skills can often require a more conscious effort.

Software within Context

The majority of the companies you will work for aren't in the software engineering business. Software is instead a tool being employed to achieve other business goals.

Understanding the business context within which you are creating software is important, the software itself isn't the end goal, the things it can achieve are. Allowing this context to influence the engineering decisions you make will increase the effectiveness of your engineering output.

You don't necessarily have to become an expert in how your company operates. But an understanding of its source of profitability, its customer base and its goals and motivations will enable you to become a more rounded operator.

Don't just see yourself as an engineer, see yourself as someone with engineering skills working towards a common goal.

The Reality of Technical Debt

Many engineers will frequently become frustrated at business decisions that they feel are impinging on the quality of their software.

This passion to be involved in quality engineering is an asset and is much better than a "that'll do" attitude. But a pragmatic outlook is going to be required to avoid becoming too disheartened.

It is unlikely to be the goal of your company to produce quality software, that will probably never be stated, but going back to the idea of business context, the business will have goals that are wider than pure engineering excellence.

This means decisions will be made, for legitimate business reasons, that are counter to what you might like to see within an engineering context. This means technical debt is just a reality of life, but there are good and bad ways to deal with and manage technical debt.

Technical debt is only technical debt if you understand you are incurring it, if you are oblivious to it then you're just writing bad software. Often the skill as a leader is to identify where technical debt is unavoidable, trying to limit its scope, making sure a plan exists for paying the debt back in the future and ensuring the fact it is being incurred and its impacts are properly communicated.

Being a zealot and refusing to compromise or co-operate with the business is going to make you less effective. 

Helping People Help Themselves

When you move into a leadership position its often tempting to think you have to do everything yourself, this lack of delegation can lead to a tendency to do rather than teach.

As a leader others will often come to you with problems they are struggling to solve. It may be tempting to simply solve the problem for them, but in doing this you are restricting their ability to learn and grow.

Sometimes a problem might be urgent or have severe implications meaning you need to take ownership of the situation. But on other occasions rather than solve the problem for somebody you can instead guide them to the right solution and give them the skills to repeat the process in the future.

This will also extend to letting other know it's ok to not know the answer. Others will often assume that you know the answer to all problems, making them understand that you don't and in fact you just have developed a set of skills to help you find the answer will help those individuals acquire the same skills.

It's tempting to think that a leader in a software engineering team is equivalent to the chief geek and the best engineer. While it's likely that someone with the aspiration to lead will also have strong technical skills that is not the only qualifying factor in being an effective in a leadership role.

There are other softer factors that can require us to re-think the way we view our role but will ultimately make you a more well rounded engineer and successful leader.