Sunday, 6 November 2016

Breaking Not Bad



You'll will often hear developers lament at the fact unit tests are broken and need fixing.
While this can sometimes feel like needless extra overhead in implementing a feature the breaking of these tests is an important part of the ebb and flow of development and has value in its own right.
Many may be scoffing at that sentiment, so what is so great about failure?
Change is Good
We can learn a lot about the changes we have just made to the code by the failure it introduces into our unit tests.
Firstly it demonstrates that we have changed the function of the code we have been working on, I would be much more concerned if no unit tests were broken, that would imply our changes have had no impact on the code or our unit testing is inadequate.
This time the change was intentional next time it might not be and surely we would want the tests to fail in this scenario?
But its not just a case of seeing failing tests, its also a matter of seeing which ones have failed.
Do the tests that are failing make sense within the context of the change that was made or are they actually demonstrating an unintended side effect or problem with the engineering of the code? Ask yourself should these test be broken? 
Don't just blindly fix the tests that are failing also make sure that this all adds up. When it comes to pushing these changes the tests you had to fix will also serve as documentation for the reviewer of your work so they can do the same thing.
Walking on Egg Shells
Whilst extolling the virtues of failure its important that unit tests failing is always in relation to change in the code base and that its scale is in proportion to changes being made.
Unit tests shouldn't fail when no-one touched anything, running the tests over and over again should always produce the same results. Race conditions and brittleness are not qualities we want in our code bases's unit tests.
When measuring the scale of failure we should consider several factors.
Its natural to just look at the number of broken tests but this can be misleading, we also need to consider the amount of time needed to fix the tests even if a relatively small number have been broken.
If we change an interface or a method signature then its natural that a proportionally large number of tests may break, if however only a handful of tests fail but serious thought needs to be put into how the functionality can now be effectively tested then this is indicative of wider problems. 
Taking the Red with the Green
Ultimately we have to ask ourselves why did we write the tests if we didn't expect or even want them to fail occasionally? Are tests that never break actually worthwhile?
Unit tests are a comfort blanket that gives a nice warm feeling that our code is still fit for purpose and still does what it says on the tin. Its difficult to derive this warmth that they truly can be relied upon if we never see them fail, especially if we know the code base is changing.
When we are practicing TDD we take satisfaction from seeing a set of unit tests gradually change from red to green, we do this because it proves the code we have just written does what we wanted it to.
We can take similar satisfaction from seeing the same transition from red to green when a change we make breaks some tests. It provides demonstrable evidence that the code is still doing what we want it to.
We need to realise that the value of unit tests increases over time, they have value when the code is first written to help us engineer interfaces and behaviour and to validate new code works. But they have even more value as time goes by to highlight when code is broken and act as documentation for how code should be used.
Failure is a naturally part of this process and is simply part of the information unit tests convey.
Next time you break some tests don't sigh, instead smile because your unit tests once again have proven their worth.  


Monday, 24 October 2016

The Good Lazy Developer



I've said several times that a good developer is a lazy developer, this is not to suggest that they should be lazy in their attention to detail or their willingness to apply their skill to solving problems.
It is more about proper application of that skill and maximising the benefits that it can bring.
Engineering effort is not a commoditised product, it doesn't simply scale with the number of engineers in a team or with the number of hours each engineer works.
Its a finite resource that needs to be deployed with some calculation and forethought to ensure value is delivered.
Solve the Right Problems
Developers are very often compulsive slightly obsessive people who sometimes focus their effort on the minutiae of a problem or a piece of work.
While this attention to detail is partly what makes them good developers it is a beam that needs to be carefully focused to eradicate the most important problems.
A good example of when this is not done is when an inordinate amount of time is spent perfecting the UI for a customer journey that actually under the hood doesn't work.
Another example would be expending large amounts of effort on an edge case that is unlikely to happen or can be managed in a different non-technical way.
Whilst you always want developers to see the whole picture of a piece of software you do want them to adjust their attitude to when they are happy to say something is done, or at least done for now.
Customer journeys delivering the intended outcome should be such a staging post, a good lazy developer just wants to get to the point where things work and save polish and refinement for another day.
It may be that we don't want to ship until this polish is applied but we still need to approach the problems in the right order and ensure effort is concentrated in the right areas.
Automating the Housework
Developers time needs to be maximised on the furtherment of the product or system they are working on, the implementing of the pipeline to produce this shouldn't be a task that requires continuing application of effort.
When properly implemented the DevOps movement is an answer to this dilemma.
A scrum team contains a technical resource that can be equally adept at using technology to implement an autonomous and continuous pipeline of delivery as it can be at implementing the desired business outcomes.
Whenever a task becomes repetitive or onerous the good lazy developer wants to develop a way to avoid having to undertake that task again and instead concentrate on the production of new features or improvements to the code base.
The nature of these tasks is likely to be different in different teams but the fundamentals of building, testing and deploying code are common to all teams and the slicker these things can be made the more time and effort is conserved for solving the right problems.
Avoiding the Maintenance Headache
The majority of developers prefer to be creating code rather than maintaining it but none the less keeping an existing code base going is an unavoidable task.
The good lazy developer wants to reduce the impact of bugs or requested changes for a pre-existing code base. To do this they anticipate this requirement for change or modification coming and deploy the tools of loose coupling and strong cohesion that they have at their disposal.
This makes the code testable and composable, not only does this make the impact of change easier and more predictable, when combined with an automated pipeline it can prevent problems before they are shipped and reduce the impact even further.
Well structured thought through engineered code helps a team develop lazy habits by allowing them to keep to a minimum the amount of effort involved on change activities and avoid the cycle of tearing things down to build them back up again.
The majority of the time when we are referring to good lazy developers we are referring to an active dislike of repetition of the mundane and a preference to expel effort on the new and exciting. 
We are also referring to an understanding that developing software is a long term aspiration more than it is a short term activity. You'll never solve all the problems so make sure your plan of work address the most important ones first rather then being side tracked on the areas that potentially technically fascinating but ultimately of secondary or tertiary importance.

  

Monday, 17 October 2016

What Do Points Make?


When working in or with a scrum team talking about, debating about and on occasion arguing about points is common place.

Ultimately the ability to deliver points is a strong indictor for a team in terms of a velocity but its important to appreciate what this measure should represent and also importantly what it doesn't represent it.

Effort or Complexity?

An often debated aspect of pointing is whether they should represent complexity or effort.

I believe ultimately its difficult for team members to remain focused on one particular criteria when giving a points estimate, they are likely to consciously or sub-consciously be taking many factors into account complexity, effort and time to name a few.

For this reason we should see points as simply representing the currency of the work a team can get through in a sprint, each point representing a unit of work to be achieved.

Relativity and consistency are the most important aspects of pointing, points are unit-less, providing a 13 point story is more work for the team then an 8 or 5 point story and providing two 13 point stories represent roughly equivalent pieces of work then pointing is serving its purpose.

The exact reasons the team are choosing a points value is not necessarily relevant providing they are consistent in the application of those reasons.

Everything is Work

If we are going to have an accurate measure of the work a team can achieve we need to ensure all tasks that require more than a trivial amount of work carry a points value.

Sometimes we are tempted into indulging in creative accounting because we feel we want to ensure some piece of work is put into a sprint whether this be a bug fix, sorting out some technical debt or doing some refactoring.

But we can't achieve work with zero effort and ultimately in our attempt to fix or improve our code base we may very well have the opposite effect when more stories are added to an apparently under filled sprint even though we already have a lot of work on our plate.

If we generate a lot of technical debt or bugs the points value this work carries is a direct measure of the price we must pay to fix these things and should act as encouragement to not incur these charges.

Points Aren't Prizes

The purpose of a scrum team isn't simply to score points, it is to achieve business outcomes. At the start of every sprint the teams velocity represents a budget that can be spent to achieve these outcomes.

All members of the team can and should play a role in deciding how best to spend that budget in order to achieve value for money, in the form of a well defined MVP, and to create some investment opportunities for future sprint delivery.

It is all too easy to construct a sprint that achieves a lot of points but has very little tangible benefit, its not the case that at the end of every sprint we have to have a new feature or widget but we do need to understand how we have moved forward and how this will flow into the next sprint.

Points are a mechanism to use in planning to provide estimates and judge how much work to commit to in an iteration, they are not the only measure by which a team should be judged.
   

Sunday, 25 September 2016

Agile Quality



Being an agile team is not achieved by flipping a switch, becoming agile is a journey where the validity of qualifying yourselves as being agile is a sliding scale.

Along with an adherence to the structure and ceremonies of your chosen agile approach there is also a required mindset that needs to be adopted in order for the benefits of agile to be realised.

So if being agile is not a binary metric how do we know in our day to day working lives if were moving in the right direction towards our agile nirvana.

Story Writing

An agile story is the communication device by which stakeholders can communicate to the team the outcomes that need to be achieved to implement some desired functionality.

As with any form of communication its possible to do this badly, to generate misunderstanding and confusion that ultimately lead to a failure to deliver or a delivery that provides the wrong outcomes.

Story writing should not be an arduous process, it should promote discussion but it shouldn't cause confusion.

A key to this is realising that story writing needs to start only when a broad understanding of outcomes is already in our grasp.

The process of story writing should be for the team to create an understanding of what needs to be done and the approach that will be taken, it shouldn't be a painful process of trying to tease out of stakeholders what the point of doing this work is.

You can learn a lot about agile quality by watching a team in a story writing session, are you watching a well oiled team who understand the product they work on and where its going? Or are you watching a group of individuals churning out software without an understanding of why?

Backlog

Once a certain number of stories have been written then you have created a backlog.

Again a backlog can be seen as a form of communication, it describes the journey a product is going on and identifies the signposts and milestones that need to be hit along the way.

A good agile backlog is fluid, the next priority can be changed, stories can be added, removed and re-ordered.

What shouldn't be fluid is the over arching themes of what is trying to be achieved, the product that is being built and the path of its evolution.

A low quality backlog will not demonstrate this cohesion, it will present itself as just a collection of work items thrown together in order to give a team something to do. It will not have obvious goals or points of delivery.

The quality of a backlog can often been seen by asking a member of the team to talk you through the stories, what they achieve, why they are in the order they are and where a deliverable exists.

Delivery

The point of all this is to deliver software and almost regardless of what development philosophy you apply the effectiveness of a team should be measured in their ability to deliver working software.

However we need to understand what is realistic to expect.

No matter the quality of a team the ability to deliver any amount of scope in any amount of time is a fallacy.

What should be valued is the predictable nature of a teams delivery, this predictability will come from an accurate and stable velocity.

When this is combined with a quality backlog made up of quality stories this enables accurate estimation.

A stable velocity can only be achieved when a team, whose members don't change, is working its way through a well crafted backlog towards a well understood goal.

Velocity should be the third measure of the agile quality of a team, as the team improves its practices it should demonstrate an upward trend but not have large variation between every sprint, within the short term past performance should predict future delivery.

Ultimately all these aspects of agile combine and interact, the important aspect is to embrace the agile mindset and realise it is not a project management process.

It is a living organic approach that embraces change and wants to deliver what is required on regular and improving cadence. But as with any system, garbage in will lead to garbage out.

Sunday, 18 September 2016

Extend Don't Modify


One of the five pillars of SOLID software engineering is the open/closed principle:

    A software entity should be open for extension but closed for modification. 
 
With the advent of distributed source control systems, such as Git, many claim that the open/closed principle (OCP) has lost its relevance. We don't need to fear modification since we can accurately track change, roll it back if required and visualise the history of a piece of code.

I argue that this is looking at OCP in a limited sense, software has an inherent ability to be fragile and therefore any architecture or implementation that promotes modification is on a path to increase this fragility and ultimately lead to defects and instability.

Concentration of Knowledge

Regardless of whether or not we can track modification we should still ask ourselves why we are required to modify and not extend a class, often this is because we have created a concentration of knowledge and therefore a concentration of change.

If we have a class responsible for drawing shapes we will be forced to change this class every time the number of types of shape in our universe expands, if we instead delegate responsibility for graphics to each individual shape then we can naturally extend this universe just by adding new shape classes.

The above example is generated by the fact that knowledge of how to draw shapes was concentrated in one place when the number of shapes we have to work with was going to be on an upward trajectory.

Sometimes its a fine line between obeying OCP while also adhering to other SOLID principles such as Single Responsibility Principle (SRP), however both principles are trying to limit the need for change, if we concentrate knowledge in a particular class we need to keep in mind how much that knowledge may need to expand.

Too Many Cooks

Another important aspect of OCP is a much more practical one.

Source control systems may be good at tracking change but they cannot smooth the problems we encounter when many engineers have rolled up their sleeves to go under the hood of a piece of code.

Creating a code base where many developers may be working in the same area will have an impact on velocity both in terms of developers struggling to get their code merged in, struggling to understand an area of code under modification and with the defects that will arise as a result.

Sometime we concentrate solely on the properties of code that can be slightly abstract in nature but the ease at which a code base can be worked on by a team is something that should not be forgotten or ignored.

OCP helps create a code base where many developers can work together in harmony without tripping over each other and without creating confusion.

This Used to Work

Software has the potential to be inherently fragile, it is written by developers who are only human and will make mistakes.

We put certain automation in place to try and catch these errors but they still on occasion make it through.

Promoting change in already working software should be left for refactoring activities to improve the overall quality of the code, it shouldn't be a daily occurrence because the software has been built in such way that it must be deconstructed before being re-built with new functionality on every iteration.

The ideal situation to be in is that whenever new functionality is added the risk of defects only exists within that new functionality. It shouldn't be the case that all bets are off on the working state of previous functionality because its implementation has been modified or changed to accommodate the additions.

The SOLID principles are not always universal truths, there are occasions where strict appliance would not improve a code base, but that needs to be viewed in the round sometimes the benefits they bring can be both broad and subtle.

Although the invention of many of those principles pre-dates the world in which we are developing software the truth within them still holds, how to engineer good software hasn't changed that much and its unlikely any of those five principles will ever be declared defunct.

Monday, 12 September 2016

Feature Quest



When working on a software project it can sometime feel like your part of a never ending convey belt of feature delivery.

Its easy to fall into a trap of becoming obsessed with the delivery of more and more features for users and to value this above all other aspects of the product.

Actually there is more to developing a product then just bombarding users with a constant stream of shiny new features.

When you come to think about it, how often do the major platforms such as Google, Facebook, Apple or Amazon release new features that are visible to users? Its not as often as you think.

Working is a Feature

Sometimes we assume that users are judging us by the cadence at which we are giving them new toys to play.

Generally if you ask a user "would you like it to do this..." you will get some form of positive reaction, however if you ask them what bugs or annoys them about using your product they will talk about problems they have using the current feature set.

Performance and stability need to be viewed as features that are just as valuable as the next bright idea, users have very little tolerance for a decline in either of those two aspects of your product.

You are much more likely to lose users because your product is not functional or doesn't do what it says on the tin then you are to boredom of a perceived slow down in new features.

Quality in your code base is not a nice to have, ultimately its what users value and no amount of bells and whistles will distract them from it.

Internally Facing Features

We don't necessarily have to view the features we deliver as being always focused on the user.

In our own way the organisations we work in are consumers of our product, we have to work with it, deploy it and maintain it.

Features can address those key areas as much as they might have an impact on things the user is aware of.

Although working on these areas might be seen as making our lives easier they also have an indirect knock on affect on our users.

Anything that makes our life easier makes delivering software easier and easier delivery means we can make more frequent updates and in turn deliver to the user at a higher rate.

When evaluating potential new features we need to look at the whole delivery chain not just the relative tip of the iceberg represented by what is visible to the user.

Feature Overload

Pick any popular piece of software and ask people what they use it for and in the vast majority of cases that list will be relatively small and not include everything that software is capable of.

It is also equally likely that if you compare how the features on the list work now to how they worked in the original version you will see a large progression.

If we take an agile iterative approach to development we should develop a mindset of "better and better" not "more and more".

We should concentrate on the core set of features that we feel our the prime value drivers in our product and work on ways to deliver that functionality in an ever increasingly better way.

These improvements may be marginal but by continually delivering them in a relatively short amount of time they can add up.

A performance tweak here and a bug fix there, some polish to the UI here and some smoother UX there can all make users feel like your product is more useful in their lives.

Sometimes we develop a features at all costs attitude that does more harm then good and is not really want users want.

Users want the functionality that originally brought them to your product to work and work well.

In time they come to expect you to offer them more but they don't expect this at any where near the pace that we sometimes think they do.

When the time for new features does come it should be an organic extension to what you already offer without the need to re-invent the wheel or find the silver bullet.

Sunday, 4 September 2016

Flipping Dependencies



Sometimes we can be guilty of following a principle or a pattern without fully understanding or appreciating why this is a good thing.

Some could argue what difference does it make if your writing good code? But without understanding what makes the code good you invite the risk of unintentionally degrading it.

One of these patterns is dependency injection, sometimes developers will implement this pattern without appreciating that the reason for doing it is to apply the principle of Inversion of Control (IoC).

Static vs Dynamic

A class that does not apply IoC is statically bound to its dependencies, they are defined when the class is compiled and will never change without the code being changed.

When a class is written to apply the IoC principle it is dynamically bound to its dependencies they are not necessarily defined at compile time, instead they are loosely coupled by a shared contract in the form of an interface between the dependency and the dependent.

The major point here is that we have inverted who is in control of defining which implementation will fulfil the dependency for the class we have written. Rather than the class itself controlling this the framework in which the class operates is in control.

So why is this inversion a good thing?

Hang Loose

The primary benefit of IoC is to create loose coupling between classes.

The benefits of this to the dependent class should be clear, it makes the class eminently testable and increases the opportunities for re-use.

It is almost by definition not possible to test a class that is statically bound to its dependencies.

A unit test should only have one reason to fail, namely that the class being tested is not supplying its required functionality. It should not be the case that the failure is caused by one of its dependencies, this would mark this test as an integration test, this doesn't mean the test has no value but it does make it harder to interpret the results.

If its impossible to break a class away from its dependencies then its impossible to write a unit test.

Quite often despite the fact that a class has the control to define the implementation of its dependency it actually has no reason to have this control, it has not got a dependency on the implementation only on the functionality.

By applying IoC we properly model this situation and allow the class to function with any implementation willing to provide the desired functionality, we have made the class more flexible, re-usable and ensured we do not have to needlessly write more code or copy code we've already written.

Loose coupling also has a benefit to the class supplying the dependency, by being statically bound to an implementation we don't allow for any change in that implementation without the requirement to transmit that change to the dependent classes.

By dynamically binding to the functionality we allow for change in implementation to have no impact on the dependent class allowing it to carry on working in the way it did before. 

Giving Up Control

Once a class is no longer responsible for creating its dependencies it can also be absolved of any responsibility for implementing logic relating to that creation.

The IoC principle allows our use of constructs such as singletons, object pools or prototypes to be both hidden from the class that needs the functionality and centralised within our implementation of a container to realise the IoC principle.

This is another example of how application of IoC is all about leaving the class that requires dependencies to be written with only concern for the functionality it needs to offer and not also be responsible for playing a role in implementing the framework we need our code to run in.

In this way IoC can be seen as playing a role in ensuring we follow multiple elements of the SOLID principles, not only dependency inversion but also single responsibility and the open close principle. 

Too often we can simple show developers a piece of code and simply tell them this is good code.

But this encouragement to simply repeat what you've been shown without appreciation for why the code is good will inevitability lead to the subtitles of the code being missed.

It is never the case in software engineering that any particular pattern can be endlessly applied, there are always other factors to consider and different situations to recognise.

The way to enable developers to appreciate this is to teach them the principles that are used to define good code, which patterns to use are a natural consequence of understanding these principles. 

Sunday, 21 August 2016

Integrating with Users



Somewhere along the line, to a greater or lesser extent, all software is integrated into some kind of front end to allow users to interact with it and benefit from the value it can provide.
Too often this value is masked under a shroud of a confusing UI, causing users to fail to see this value because of what they perceive as a bad experience using the software.
It isn't enough to create a well crafted, well engineered piece of software without also putting as much effort into how the final piece of integration will be achieved, integration with your users.
Don't Astonish
They're certain noises that you don't want users to make when they are using your software. Some of these are obvious, you don't want shouting, screaming or swearing to be heard, but we also don't want any kind of puzzlement or astonishment.
Users do have to go on a journey of discovery when using any new piece of software, they need to learn what its capabilities are and what value they can bring. But users should never need to be trained to use a piece of software, this process of discovery should be one of self discovery.
If you find yourself having to construct tutorials, FAQs and help sections to explain to users how to operate your software then your preventing them from going on this journey.
The majority of your users will not be prepared to put this level of effort into learning how to utilise what you've built, your hard work in developing features will simply never be discovered.
Instead we should simplify wherever we can and let users stumble across the value we can deliver without expending much effort of grey matter.  
Don't Reveal Detail
Writing software can be a difficult and complicated matter, sometimes we are faced with solving challenges related to systems integration, legacy code bases or sub optimal implementations.
All of these problems must exist in the shadows, users should never be expected to be part of the solution.
These complications of implementation shouldn't be allowed to affect user experience, if a feature cannot be implemented to provide an acceptable user journey then we should question whether it represents any value to the user.
Users can be very fickle and don't forgive valiant attempts by developers to implement a feature despite the technical challenges if it doesn't sit well with how they want to use the software.  
Don't Find a 3rd Way
Sometime there is what is correct and there is what people actually want or understand.
Users like familiarity with what they have seen and used before, it may be that what they are familiar with is in some way flawed.
Just about every platform that you will use to deliver your software to users will have these conventions and perceived wisdoms.
I would never want to discourage anyone from trying to innovate but to go against these conventions of how people expect to use software on a platform can be fraught with danger.
Even if you think your new way is an improvement in order for users to not be put off by the unfamiliarity of what your presenting to them it needs to be a significant improvement.
Be cautious when innovating with new ideas for user experience, users can all too quickly dismiss something new it it doesn't match their expectations based on what has gone before.
Users are often difficult things to predict and we can be left frustrated when something that we've put a lot of time into and believe is dismissed or misunderstood.
But ultimately the user is always right even if for no other reason then you can't force people to use your software.
As with most aspects of engineering simplicity should always be something to strive for.
We may inevitably have a certain amount of complication happening under the hood but our user experience should be an effective shield from the user ever being aware of any of this, and instead be impressed by the apparent magic we are able to produce. 

Sunday, 7 August 2016

Don't Write More Code



As strange as it may seem we aren't in the software production business, we are in the solution delivery business.
What I mean by this is we shouldn't measure our effectiveness by the amount of code we produce but by the number of solutions we deliver.
We should actually consider code a necessary evil in delivering these solutions with it counting more as a liability than an asset.
Costs of Production
If viewed as a commodity code is pretty costly to produce, developers are highly skilled well paid people and good code can take time to engineer.
If we define an implementation that requires a lot of code to be written we are increasing our costs and putting our deadlines at risk.
We need to make sure that developers time is spent on writing the code that provides the features we really need, not re-inventing the wheel or falling into the not invented here trap.
The essence of this approach is re-use, whether this be utilising 3rd party code that does what you need or by recognising when you write code of your own that what you're writing will be the answer to a similar problem in the future, effectively reducing the time to provide the solution the next time round.
Whenever you find one of these re-use potentials your reducing your costs and making it more likely that you'll hit your deadline. 
Production Defects
Whenever we write software we are usually writing defects at the same time.
While I wouldn't suggest that its impossible to produce a small piece of code riddled with bugs or a large piece of perfectly bug free code, there is undoubtedly a relationship between the amount of code we write and the number of defects we create.
This is not only a problem because we don't want to ship bugs but also we create a vicious circle of even more developer time, which we've already established as expensive, being spent on fixing the issues. 
Re-use once again is our friend, by re-using code, especially well tested code, we can ensure that we build our software on strong well understood and proven foundations, reducing the amount of new code that is likely to cause defects.
Maintenance Not Guaranteed
Code can rot if not maintained, this can be because of constant change to deliver new features, hacks or patches being applied or not being kept updated with changes elsewhere.
The more code you have the more rot your going to see, and once again this brings us back to the time and cost of having to maintain and fix that code.
Yet again re-use can help us, by ensuring we are using the same solution whenever we encounter the same problem we reduce the amount of code that needs to be maintained.
If we discover a problem in a library or package we can fix it once and feel the benefit in every other code base without expending any more effort or cost.
Its very easy to fall into a trap of engaging in engineering software for purely technical reasons.
We are enthusiastic about what we do and gain pleasure from doing it, but our industry is not about production lines. We aren't employed because of our ability to produce code, we are employed because of our skill in utilising software to achieve business outcomes.
There doesn't have to be a relationship between the amount of code we produce and the number of outcomes we achieve.
Think of software engineering as a constant process of refinement rather than as a means to bring more code into the world. 

Sunday, 24 July 2016

Battling Against Time




When developing software there are many pressures that play a role in the final outcome.
The biggest of these pressures by far is time, anyone who has ever been involved in a software project will recognise that initial inward drawing of breath when the release date is first vocalised.
I'm not about to attempt to argue that these deadlines shouldn't exist, that simply isn't the real world. Product needs to be delivered to end users and this cannot be after their need has passed or after someone else has already provided value.
What I am going to argue is that these deadlines need to be based on input from the whole team and be based on not just delivering software on time but delivering value.
Viable Product
A fundamental part of an Agile approach is Minimum Viable Product (MVP), unfortunately it is also greatly misunderstood.
MVP is not simply a measurement of scope for a release, it is instead a measure of value that will delivered to users.
Their are many factors that go into deciding what constitutes an MVP, time to implement is not one of these factors.
Viability is not a sliding scale, software can not be somewhat viable it either can deliver a use case or it can't, and that use case is either valuable to users or it isn't.
Of course we can iterate, we can improve and we can deliver more, but this brings us to the minimalist approach that should be taken to MVP.
Some think that MVP only ever serves to push out deadlines, the goal of MVP is actually to deliver earlier by not concentrating on polish but identifying how a core need of users can be addressed with the minimum amount of implementation. Refinement and improvement come at an equally optimised pace by defining the next MVP and the next.
Making Effort
Discussions about deadlines often take place from a very entrenched position, I need this and I need it by then.
As we have discussed proper application of MVP can often lead to a realisation that maybe you don't need all those things, but what if you can't reduce scope any further?
Fundamentally a project only has two variables, scope and time, to fix both means the only other levers to be pulled are effort and quality.
A lesson that continues to be a difficult pill to swallow is that its very difficult to create effort and that the majority of the effective ways that this can be achieved are related to a teams structure and not just to the number of members.
Software is a creative process not just a manufacturing process, would a novel be written faster by more authors and maintain its narrative? Would a symphony be composed faster with more maestros and hold its tune?
So we are left with varying quality, the sad thing about this approach is that it often does work in the short term by bank rolling the release on technical debt. But with equal certainty it will also be the downfall of future releases when the interest on that debt has to be paid.
Release Early, Release Often
So I said I wasn't going to argue against deadlines, some reading this may think thats exactly what I've done but actually what I'm proposing is that we introduce more deadlines.
Rather than viewing the Agile process as a brake on driving towards deadlines we should see it as providing the acceleration that means we knock them off earlier then we thought possible.
An Agile approach means we can chip away at a mountain of scope, we may not be able to see the summit but we can establish the base camps that will be the factor in a successful ascent.
Rather than concentrating on the final release that will be the fruition of our grand plan identify the layers of value that means we can deliver something to our users to get them on board and help them keep the faith.
This means breaking away from waterfall thinking and embracing the iterative nature of Agile. 
Letting go of the illusion of control that anything can be made to happen in any timeframe, instead making the most of what the teams is capable of by identifying whats the next best thing we could deliver to incrementally deliver value.