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.

Sunday, 17 July 2016

Arguments Against Agile



Whenever any philosophy or school of thought gains traction and reaches a critical mass of adopters a dissenting voice will start to develop against the new perceived wisdom.
This voice should never be ignored as while sometimes this can be simply a need to differentiate sometimes the points being made are genuine problems that need to be addressed.
Agile also has this opposition where some question its effectiveness.
I would never presume to say that Agile has all the answers but I do believe its as good a theory as we have yet devised. 
I also believe that most of the arguments put forward against are related to the flawed implementation of Scrum as opposed to criticism of an Agile mind set.
Too Many Meetings
A core principle of agile is face to face communication, this communication does not have to be regimented with an agenda, a duration or a fixed meeting place.
Simply put, the point Agile is making is that you'd be surprised how many problems get solved when those involved just talk to each other whether that be at their desks, at the coffee machine or over lunch.
A daily catch up with the team to ensure people are progressing and fortnightly opportunities to review progress and plan the next iteration do not seem onerous.
If you find yourself in an unending cycle of meetings, often about the same subjects, then you should question why there is so much uncertainty in the work your team are trying to get through or why there is so much disagreement on the way forward.
These problems are unlikely to be related to Agile, instead they are likely to indicate a lack of preparation, direction and vision.
No Commitment to Deadlines
A common frustration with Agile is an apparent inability to commit to a deadline.
Actually Agile teams commit to deadlines on a regular basis, every other week the team will commit to a certain amount of work being achieved in the next two weeks.
The team will also regularly discuss how they can improve there operating process so that they can commit to even more work in the next iteration.
Agile teams have a certain budget represented by their velocity, and this allows a certain scope of work to be completed in a certain time frame.
Agile is simply re-iterating the maths of this situation, that you cant fix time and scope because that involves you creating more effort. If you base your plan on the team creating more and more effort you will miss your deadline because thats not how teams or people can work sustainably.
Instead a deadline needs to be a compromise between timescale, scope and what the team think they can achieve, its possible for everyone to win.
Rigid Process
Some will say that they don't feel they can achieve as much with all the red tape and bureaucracy that Agile places on them.
Its critical in this situation to draw a distinction between Agile and the system we use to try and achieve.
Agile is not a system, a framework or a structure. Agile is a mind set and a philosophy.
Agile is nothing more than the principles laid out in the manifesto listing certain aspects of software development and team interaction that should be encouraged.
Scrum, and others like it, are attempts to organise teams to promote these principles. What they shouldn't become are rules and procedure that hang around the teams neck.
There is no one Agile to rule them all, each team needs to find their own way the only things they need to believe in and follow are listed in the manifesto the rest is implementation detail that while important is not the aim of the game.
Feel free to find your own way, adopting an Agile mindset will ensure you take the right path, even if your path is different from others you'll still be on track to reach your destination. 

Sunday, 10 July 2016

I've Got Something For That



Much like when someone disappears into a shed and emerges with the perfect tool for a particular job developers can often be heard saying "I've written something a bit like that before".
As I've said many times a good developer is a lazy developer, re-using what you've previously written should bring a smile to every developers face.
But how can we increase the chances that these opportunities will present themselves, what is it that makes code re-usable?
Simplicity Over Configuration
An easy trap to fall into is to take a piece of code thats fairly close to what you want and makes the bits that don't quite fit configurable.
While in a lot of cases this will yield a nice solution care must be taken to ensure that this won't run out of control. An object with a vast number of possible configurations can be difficult to get to grips with, what you need it to do might be in there somewhere but your eye isn't drawn to it.
This is more likely to happen when your trying to re-use code in a large block where the desired functionality is always going to be custom based on the context its being used in.
The answer to this is composition, by breaking this large code block down into small, simple, easy to understand building blocks you allow for different configurations of the functionality by allowing the developer to build the functionality that makes sense for them while taking advantage of the effort you've put in to taking care of the lower level details.
Layering the Pie
In a similar vain composition is easier to achieve when your code has a clear hierarchy taking us from low level detail all the way up to chunks of functionality that a user would recognise.
These functional blocks will very often be able to traced back to the same lower level detail.
By working out at what level certain pieces of code should exist you can avoid duplication and move towards a toolbox of code.
Obvious examples of this would be a data access layer or a networking layer, but even here recognising that there is a common pattern to how network requests are built, queries are constructed or results are interpreted can help the extract, abstract and re-use cycle that we are aiming for. 
Guarantee Included
Identifying that a piece of code might suit your needs is only the first step, it would be nice to also have some evidence that it does do what it claims.
This could come by reviewing the source code but it wouldn't it be better to have the code come with a guarantee of its effectiveness.
This evidence should come in the form of unit testing, those test results should not only demonstrate that the code works but also act as documentation for how the code is expected to be used.
This testing as documentation approach will help re-enforce that this is the piece of code that you've been looking for, this will solve your problem and enable you to move forward.
All this means that testability should be seen as synonymous with reusability, along with the guarantee and documentation elements the qualities of code that make it testability such as loose coupling will also make the possibility of reuse much higher.
While in many aspects of engineering becoming obsessed with a single element of the design may not be optimal striving to make something reusable will naturally lead to many other qualities.
Sometime code will be custom to a particular situation but a divide and conquer approach and thinking about how code will interact can help minimise these situations and help a developer be a a lazy developer. 

Sunday, 3 July 2016

Tech Debt Accounting



Technical debt is incurred whenever a sub-optimal solution to a problem is chosen because of some other pressure aside from technical merit.
Technical debt is only technical debt if you knowingly choose that sub-optimal solution, anything else should come under the heading of mistake, poor judgement or idiocy.
So if we knowingly incur this debt why don't we just always do the right thing, I would love to tell you that its possible to do that but the reality of working in commercial software development makes it difficult to truly put technical concerns before all others.
We Need to Ship
The reason we write software is to ship it and there are many more inputs into the decision on when or if to do that aside from the purely technical.
I would like to be able to give you advice to never allow your code base to be affected by these outside pressures but it just wanted be realistic.
Shipping software is important, it reenforces our link with our users and reassures them that we are working on ways to improve the product.
Its a fine line between making sure software is properly implemented and meeting a schedule of releases and because of this we will occasionally stray either side of it.
We may occasionally ship late and we may sometimes ship something we aren't 100% happy with it, if we accept this is the reality then we need a strategy for dealing with the consequences. 
Auditing Your Finances
So if we assume that at any time we are carrying a certain amount of debt how can we ensure that it is effectively managed.
The first step is to record it, the chances are all developers working on a code base know the areas that need work or that cause problems when dealing with change.
But this isn't enough, too often when developers talk about this stuff it doesn't register with others and this is mainly because they can't see the impact.
Instead have a central register of tech debt that briefly explains the nature of the debt and the impact it has. The next time in a planning meeting eyebrows are raised as to timescales or complexity being able to point at an entry in the register and explain this is why is invaluable.
Secondly every time a bug or performance issue is encountered that is either directly caused by tech debt or exacerbated by it assigning the developer time taken up in finding a resolution and the users affected will highlight that everyone is suffering from the debt.
Visualising the impact of the technical debt like this helps highlight to non-techies that there is value in this kind of maintenance and continual improvement, stability and performance can be a feature.
Now or Later
The biggest piece of education you can conduct around technical debt is that its currency is time.
Time saved by choosing the sub-optimal solution is always paid back in either longer timescales for new features or more time spent on irritating bugs or failures further down the line.
This doesn't always mean we are doomed to either ship later or spend time fixing our code base, we instead need to understand that tech debt cannot be ignored. That it isn't related to people not doing their jobs properly, instead we can all work together to ensure we instigate a cycle of shipping and optimising and shipping.
Stability and performance are often overlooked features but users do not forgive lapses in either of those two things for sake of a shiny new feature. Its not always easy but it is possible to establish a balance between the technical merit and the need to ship everybody just needs to be aware of the nature of debt.  

Sunday, 19 June 2016

The Scientific Method



Agile is made up of many aspects and means different things to different people.
I believe one of the things it teaches us is that we can't control the environment our software will be used in, our predictions are educated guesses and we must have an acceptance that we may be wrong in part or entirely.
In this aspect Agile development shares much with the scientific method, as developers we are conducting experiments with the goal of discovering what it is our users really want.
Constructing an Hypothesis
Whether were planning the release of an entirely new piece of software or adding a new feature to something already existing.
The need we are trying to fulfil might seem obvious, it may be based on feedback from our users or it may be an idea of our own invention. Either way whether or not users end up thanking us for its addition is not just about the idea but also the execution.
We should prepare to make changes after we ship, these changes may be big or small, we may be close to the mark of whats reuired or a distance away.
The important aspect is that we anticipate the need for refinement and give ourselves somewhere to go in the code.
Conducting the Experiment
The only people that can conduct our experiment are our users, they are the ones we are trying to provide value to and it is they who will judge if this value is being derived.
However feedback directly from users is often difficult to extract and interpret.
We therefore need a way to monitor their behaviour, a way in which we can measure the interactions and reactions people are having with and to our software.
For this reason analytics and instrumentation need to be a core part of what we ship.
Analytics to observe what users are doing, or not doing, with what we have given them and instrumentation to gauge the performance of our implementation.
Thought is required in what these key measures should be to avoid ambiguity but the data we collect represents the results of our experiment.
Interpreting the Result
We started with an hypothesis of how we thought we could please our users and add some value.
We put software in their hands and ensured we were collecting data on how it was being used.
Now we need to analyse the results of our endeavours and here we must not be afraid of a negative frame of mind.
It is all too easy in these situations to have a bias towards proving we were right. We knowingly or unknowingly construct our analytics platform to provide measures that will cast us in a positive light.
We should instead always be fearful that we may have missed something or not quite nailed it.
If we approach our analysis in this frame of mind and yet still the results prove that what we delivered was a hit with users we will truly know we got it right.
The flip side to this must be that we are accepting when the data proves we were wrong in part or wholly. This doesn't have to be seen as a negative, we've gained understanding of what doesn't work and this can feed a better approach.
Agile should all be about continual iteration and regular deployment of something new to users, if we get it wrong this time the next release is just round the corner and we will be better next time. 

Sunday, 5 June 2016

Abstract Defence



The proper application of abstraction is potentially the most important skill an engineer can develop.
When correctly applied abstraction leads to loose coupling which in turns increases the possibilities for you code base.
However abstraction sometimes gets a bad name and is blamed for adding complexity, while this can be true when its badly applied we shouldn't let this blind us to the immense benefits it can bring.
Bad Code is Bad Code
The main criticisms of abstraction are related to it taking more time to implement and it adding more complexity.
No matter how your approach the problem you have to write code to solve it, by introducing abstraction all you are doing is taking time to think about the interface to that solution.
Thinking about how your code is used should not be considered an onerous task, time saved by not thinking about things is paid back in full when unintended consequences are encountered further down the line.
When the use of abstraction adds complication this is usually either because the architecture and implementation of the code is already complex or because abstraction is being badly applied.
Quite often this is because the abstraction won't hold up over time, the most common cause of this being the abstraction leaks implementation detail. Rather than being constructed from the point of view of the caller it screams details about what is happening under the hood.
When these details change the abstraction breaks and people get confused.
Why Abstract?
So how do we make sure we do apply abstraction properly, firstly why are we applying abstraction:
  • To reduce the surface area of change.
  • To control the interface to functionality.
  • Testability.
All three could be summed up by saying we want to remove dependency on detail.
Details change and we therefore want to reduce the code that gets re-written when the change occurs.
When we interact with a piece of code we don't want to interact with the detail we want to interact with the functionality.
When I'm testing my code I don't want to be testing the detail of a dependency.
If there is no detail we don't need abstraction, a class modelling a customer contains no implementation detail, its purely data driven with no secrets to hide. 
Where ever you see detail think about the functionality being offered that could be represented by an abstraction.
What to Abstract?
If we are to achieve this de-coupling of detail what are the kinds of things that we should be abstracting:
  • Technology.
  • Code we didn't write.
  • Code we might lift and shift.
The technology being used to save data, send data or work with data is detail with a high propensity for change and also has very little to do with the functionality being offered.
Its bad enough when change in code you wrote causes widespread change in your code base, the impact is felt even more when change in code written by a 3rd party causes the same disruption. In this instance you not only don't control the change you don't control its impact either.
Obviously a dose of realism is required here, I'm not suggesting you try and abstract yourself from the OS your code is running on. Instead you need to make a call, can I realistically protect myself from these guys making changes, sometime the answer will be yes sometimes no.
Finally as I've said many times, a good developer is a lazy developer who is always looking for opportunities to not write more code.
Code re-use is a much easier prospect when the wiring and plumbing aren't exposed. When you have a clearly defined junction between code requiring functionality and code providing it you will find all sorts of new ways to write once and run everywhere.
As with many techniques in development over using abstraction will degrade a code base, however the opportunities for abstraction to improve your code base are numerous and plentiful you just need to develop a keen eye for spotting them.

Monday, 30 May 2016

More Than Coding



When your starting out in a career in software development its only right that you concentrate on developing your core engineering skills as a coder.
Your primary role is to engineer software and you need to be able to recognise good from bad and have a toolbox of skills you can draw on to build the systems required.
But as you grow into your career certain softer skills start to develop that are important for your growth as an engineer both on a personal level and within the organisation that you are a part of.
These softer skills can easily be overlooked if we assume our only role is to be a techie when actually we need to be more well rounded than that.
Know What You Don't Know
There is a phase in the development of an engineer when their skill is starting to develop that they feel they can conquer any challenge, they are an engineering super hero that will use software to combat all enemies.
Actually no engineer is an expert on everything, no-one has the answer to all questions.
Being a good engineer means having the ability to effectively and efficiently learn how to do something new. Your knowledge and experience makes you able to asses what good and bad looks like, even if you've never seen a technique or approach before you can spot well engineered thought through from the smell of something thats not right.
What is critical is to realise when your knowledge doesn't extend into the area your being asked about, to realise how your going to build that new knowledge and to realise that knowing what you don't know is a skill in itself.
Being a Pragmatist
Another aspect to our developing engineer is to accept no compromise in the application of their engineering skill.
While I would never for one second tell developers that should readily accept incurring technical debt there does also need to be a realisation that software that isn't shipped does nobody any good.
Another skill our developing engineer needs to acquire is a level of pragmatism to know when a compromise needs to be reached between engineering excellence and getting something to users.
The key second aspect to that skill of pragmatism is knowing how to structure the compromise so that it isn't a weight around everyones neck when developing the product further in the future.
Coding something badly is simply bad, knowing when to stop finessing and leaving room for future growth is being an effective engineer.
When Talking to Farmers Talk About Farms
A final awakening for our developer needs to be that they are part of something wider than just developing software.
They have a role to play that is wider than just being a techie they also need to be a communicator whose able to get non-technical people within there organisation to appreciate technical problems and have an appreciation for how the sausage is made.
There is a key difference here between understanding and appreciation, you don't need to teach everyone in the business to code, you instead need to build an appreciation for when a requirement is hard or easy and consequently why a suggestion of a different approach is being made.
You also need to build an understanding of what matters to others in your organisation, understanding there viewpoint while developing the language you need to use to explain how what your doing affects what they want. 
Your role here is to be a technology evangelist building a recognition in those around you of the engineering process whilst not losing sight of the fact that you all need to come together to produce products not just code.
First and foremost you need to become a good engineer capable of producing quality software but always have an eye on the fact that you also need to grow into a well rounded individual who understands all aspects of the business you are in.    

Sunday, 22 May 2016

Cogs Not Machines



What does it really mean to construct or devise a software architecture? If we can't answer that question are we just in the code production business or are we following a plan to build something that is greater than the sum of its parts.
We build software to solve a problem but are we also trying to lay the foundations for the solution to the next problem or are we only working in the here and now where we don't worry about tomorrow until it comes. 
With agile practices we've tried to put less emphasis on up-front architecture and bring people down from the ivory tower, so what do we now mean by developing an architecture.
Integrate to Implement
As a software development team we are ultimately tasked with producing something that meets the needs of the user and improves some aspect of their work or play.
However if that is the driver for our architecture then progress from that initial success will require as much effort as the first step we took.
If we construct a monolith of code aimed at solving the problem put in front of us then each subsequent problem will be just as hard to answer.
Implementation should be limited to the cogs that will, via integration, be used to form a problem solving machine. If we achieve this the solution to the next problem may very well require no implementation we instead repeat the integration phase with minor tweaks to the blueprint of the machine.
Re-Use without Re-Compilation
In essence what we are describing is code re-use, but critically this must be achieved without the need for re-compilation.
Some are happy that re-use can be achieved by copy and paste.
What is actually being achieved by this operation is re-use of thought, not re-use of code.
Whoever is copying and pasting the code is simply not having to expend any grey cells on working out a solution to whatever problem they have, the code itself is being duplicated and re-compiled.
If we construct our code into re-useable units, whether we call them libraries, packages or frameworks, we achieve re-use of both thought and code without the need for re-compilation.
We have created a situation where we can build many machines from the same cogs.
Re-Configuration without Re-Compilation
We may construct a piece of code that successfully consumes an API or integrates with a sub-system and this leads us to conclude that we can know integrate with any such system by simply re-configuring the code to a different end-point or URL.
But its important that if this re-configuration is achieved by changing the code then actually what we are producing is slightly modified software not re-using what we already had, this process would have to be repeated multiple times.
Once again re-compilation is not what we want to be doing, all good developers have a healthy laziness that means they'd rather be able to ship exactly what they shipped last time then go to the effort of producing more, slightly modified, software. 
So to go back to our original question, constructing a software architecture is to increase the opportunity for the re-use of effort, thought and code without modification or change.
It should be based on a lethargy that makes us reluctant to want to hit the build button and instead want to point you at the package we've already produced that fits the bill.  

Sunday, 15 May 2016

Mobile DevOps



The DevOps movement is a natural extension to the application of agile principles.
If we are good at writing software and utilising IT why would we not complete the circle and use these skills to help us deliver our products.
If you work in mobile development sometimes this can seem like a foreign land, the way we build and deploy software can on first inspection not seem to fit with these ideas but its simple a matter of degrees, we can achieve the same results.
Always Ready to Ship
One principle of DevOps is to have a continuous pipeline to enable the delivery of features into production.
Anyone who has ever submitted an app to the app stores would say this isn't a realistic dream, we cannot submit multiple updates to an app on a daily basis whenever a new piece of code is finished.
But the key here is to realise that the ability to deploy at a moments notice is actually a side-effect of the real benefit we gain from automating our delivery pipeline, and that is certainty about the state of our code.
By consistently and automatically building, testing and analysing our code on every change we always know the health of our application.
If the change makes it through the pipeline we still have an app that is ready to ship but now with added functionality. However, if the change doesn't make it through we still have work to do to deliver that feature and we fall back to the last known good version of the product, which may only be hours old.
We never again will have panic setting in when we're told we need to get a new version out.
Always Ready To Code
So now we can ship whenever we chose what features and improvements do we want in our next release?
Users interaction with software can be unpredictable and not necessarily logically, this is no less true for mobile development.
As agile practitioners we don't try to out think our users, we make a reasonable guess about what we think they want and ship the minimum implementation of that idea, we also expect that guess to be at least partly incorrect.
We detect our mistake by observing our users interacting with what we have built, not by standing over their shoulder but by having our app call home.
Asking one user what they think of what has been produced will not be informative, asking many of them might give a clearer picture but asking every single user all the time gives us a total and thorough view of where we are.
Implementing instrumentation and analytics can provides us with the data to drive our continuous pipeline to deliver a slightly improved experience, when we iterate through many cycles of this feedback we will have moved a long distance from where we were towards satisfying our users.
Always Ready To Work
Its important to realise that DevOps is not actually concerned purely with making our users lives better.
Its actually about realising that within our team we have the people with the skills who can make our users lives better and therefore we should remove all obstacles to allowing that talented team to deliver.
If we make the lives of our developers and testers easier we will maximise their output in the form of new features being delivered to users.
This is as true for mobile development as for any other form of software engineering.
Identify what is causing you pain in the process of trying to deliver your product, then confront it head on.
In many instances technology and software will be the key to reliving you from this pain and fortunately you have a team of people that excel at using and creating technology, you just need to remove what is in their way.  

Sunday, 8 May 2016

Minimum Viable Engineering



Implementing a Continuous Delivery (CD) pipeline means automating to a large extend the decision on when to ship.
Not everyone will be brave enough to completely remove a person from the process but if we are to achieve anything like a continuous deployment of functionality that person will be basing the decision on the red or green lights of our automated testing.
So how do we build this framework of automated testing how do we know when our code is good enough to ship.
Minimum Viable Code
Code is the building block on which we build our product, the first tranche of testing needs to ensure that each of these blocks does what it claims to do, we determine this via unit testing.
If we have adequate coverage of our code from unit testing then we know that we can safely compose our system with confidence that when tested in isolation each of our building blocks is fit for purpose.
If we've followed TDD we also know that this isn't by fluke, we have seen the tests fail and now were seeing the tests pass.
By integrating unit testing into our CD pipeline we can be confident that problems at this level will be detected early, the higher the frequency of change in your code base the higher the need for this testing to be automated. 
Minimum Viable System
Just because we have developed trust in our individual building blocks doesn't necessarily mean we can build our jigsaw and just assume everything will be ok.
Part of our engineering skill is in being able to orchestrate these building blocks into a system that achieves a goal, this might be to manage a database, consume an API or process some data.
We now need to move from testing the building blocks in isolation to testing them when they are chained together.
During unit testing the interaction of code with its dependencies takes place in a controlled but simulated fashion, now we need to ensure that end to end processes give the desired result.
We have now moved from building blocks to sub-systems and verified that under the hood our code works.
Minimum Viable Product
The majority of us will be constructing software that people interact with, we provide a user experience where inputs from our users trigger behaviour within our code base resulting in output to be consumed.
Our final level of testing needs to assume the place of our users and ensure that given a certain circumstance, when a certain action is taken, then a certain result is observed.
This behaviour driven testing is the final step that determines whether or not we have something viable to ship.
A green light from those tests needs to be interpreted that we have something delivering the minimum our users expect, a red light should mean everyone stops until the problem is discovered and fixed.
We have now tested our product end to end, if we've done this on a regular automated basis then we have established several points at which we could ship.
Software is complicated, manually testing an entire product is a lengthy error prone process.
The only way to be able to deliver regularly and often is to automate as much as possible, freeing up your human resource to concentrate on more abstract elements such as edge cases and unusual activity.
Software is very good at dealing with the repetitious and mudane we should use that to ensure our code, at all levels, is continually being tested whenever change takes place.