Continuous Integration

Continuous Integration

What?

Continuous Integration (CI) is a process that allows developers to integrate, in a repository share by the entire team, code developed by himself, at least once a day. At an Utopian Universe, those integrations should happen several times each day, basically every time some code is “pushed” into the repository. This action will trigger the automated process.

Why?

Agile methodologies demands code to be always “ready” to be delivered. This process of continuous integration of the entire team’s code, in the product/project code base, allows an early error detection.

In a Waterfall process, each code delivery might took several months to happen. As you can imagine, in that time, it was usual to set a “War Room”, where the entire development team would be, in the company of the entire operations team, QA team, product team, and management team. The delivery process were a terrible chaos, a real nightmare, and it could take hours to deliver (don’t bother asking about any issue that might occur, the responsible team had to fix it “pronto”).

In fact, back in those days, imagining that each code push might trigger a battery of tests (unit, integration, acceptance, …) and have immediate feedback about the possibility of the new code breaks any existing functionality, it was unthinkable. A true adventure !!

How?

There are several available options for those that wish to start using a development pipeline with continuous integration. Probably the most notorious is Jenkins. An open-source tool written in JAVA. To those that do not want to add another tool to their setlist of tools to administer/manage, there are some SaaS solutions. Nowadays, at log, we use the CloudBees’ SaaS Codeship.

Once configured, every time a new push to a Git repository happens, it will trigger an automated process where a virtual environment, with characteristics specified by ourselves, is set and where the build process will happen, followed by the entire tests battery – unit, integration, acceptance, mutation, …

In any scenario, if a problem occurs, the entire continuous integration process fails and we will have a complete report. It is important to state that when the process fails, there are no possibilities for a deployment – automatic or manual – to whichever environment.

There will be no eXtreme Programming without this important process !!

Test-Driven Development

TDD

Test-Driven Development

The “eXtreme Programming” methodology promotes the test-driven development approach (TDD). What that means?

It is common to see a developer jump headfirst into a functionality. However, TDD advises otherwise.

Short blanket syndrome

You might be wondering “I don’t see what is wrong with that approach”. Let me ask you this question – have you ever implemented/updated/fixed a functionality and by some black-magic, other “way off” functionality broke? I call this the short blanket syndrome. When trying to cover one spot, another is uncovered.

test-driven development diagramXP advises to develop in repetitive short cycles. The developer should write a test and execute the program. The test will fail, we don’t even have any real code to run. Time to write some code, but just enough for the test to pass. If green light occurs, the developer should revisit the running code and refactor if needed.

Write a test, fail. Write code, pass. Refactor.This cycle will continue on and on.

There are many possible tests – unit, integration, functional, acceptance. All of them, as we will find out, are extremely important in the software life cycle.

Unit Tests

This type of testing, as the name implies, should evaluate the smallest unit of code. It should test, typically, every public method and with no interaction with the rest of the system. Basically we will be evaluating the input and output of data to every method. If, in a future update, a developer write some code that will change the necessary input data or the type of output, the test should fail and let the developer know that it may break the entire logic.

It is quite common to find developers using the, so called, “code-driven tests”. That is the same to say that a developer will write the running code and afterwards will write the adapted test.  This inverse process will make your code base really difficult to test, and it is wrong.

When these tests are well written, they may be used as documentation. And this is really interesting.

How many unit tests should a code base have? Well, Robert “Uncle Bob” Martin use to say that 100% of the code base should be covered by tests !!!

Integration Tests

After unit testing, where the small units of code were tested, is time to integrate all the pieces. There are several approaches to this sort of testing – “big-bang”, “top-down”, “bottom-up”, “mixed” and “risky-hardest”. I will let the explanation for those for future posts. However, and if with unit tests one should cover 100% of the code base, integration tests deserves a more concise reflexion. J.B.Rainsberger explains in this talk that we may be creating a small monster. I advise you to watch that presentation (or at least read the article).

Functional Tests

Functional testing belongs to the Quality Assurance (QA) process. Like the name implies, in a functional test we will test a functionality against some specific requirements. The internal process isn’t important, that is why this sort of testing is called a “black-box” test.

Acceptance Tests

We might consider acceptance tests as the last stop before the release. We will write user stories, with the client help, and the test should mimic that story. Let me show you an example:

  • user will access the login screen
  • user will input authentication data (user: admin, pass: password)
  • user will be redirected to screen X

Basically, we will test several possible scenarios, emulating real users. Like I say previously, this is the last phase before the release, therefore QA team and client should be working really close.

Mutation Tests

This sort of testing takes the approach of modifying small pieces (mutations) of your code base. Those mutations should be detected and resolved by your testing suite that would be running in each commit. As you may think, this testing typology is primarily to test your test suite and to help design new tests.

The example provided by Wikipedia, transpilled to PHP:

The mutation might be just transforming the logical condition && to the condition ||.

For PHP we can refer to the Infection framework, and for JavaScript we might choose the Stryker framework.
Following another XP best practice, the entire code base should be continuous integrated, so all these tests must be automated. Worry not, I’m writing another post about this subject.

Have I convinced you that writing code with tests are really beneficial ? Let me know your opinion.