Stefano Alletti

12 factor App – Comment scaler vos applications ?

QU’EST-CE QUE LE « 12 FACTOR APP »

Le « 12 Factor app » est un manifeste qui propose 12 bonnes pratiques concernant le développement d’applications web. Ce manifeste, écrit par Adam Wiggins (co-fondateur d’Heroku), est né de ses observations et de son expérience dans le développement et le déploiement d’applications web.

Ce manifeste s’applique à tous les langages et toutes les plateformes, c’est pourquoi il se contente de décrire les décisions de conception de haut niveau sans donner de détail sur l’implémentation.

Dans ce post, nous allons parcourir ensemble ces 12 facteurs, en extraire le concept et tenter de l’appliquer au monde PHP.

Lire tout l’article a la source original: Eleven Labs.

 

À l’époque actuelle, les logiciels sont régulièrement délivrés en tant que services : on les appelle des applications web (web apps), ou logiciels en tant que service (software-as-a-service). L’application 12 facteurs est une méthodologie pour concevoir des logiciels en tant que service qui :

  • Utilisent des formats déclaratifs pour mettre en oeuvre l’automatisation, pour minimiser le temps et les coûts pour que de nouveaux développeurs rejoignent le projet;
  • Ont un contrat propre avec le système d’exploitation sous-jacent, offrant une portabilité maximum entre les environnements d’exécution;
  • Sont adaptés à des déploiements sur des plateformes cloud modernes, rendant inutile le besoin de serveurs et de l’administration de systèmes;
  • Minimisent la divergence entre le développement et la production, ce qui permet le déploiement continu pour une agilité maximum;
  • et peuvent grossir verticalement sans changement significatif dans les outils, l’architecture ou les pratiques de développement;

La méthodologie 12 facteurs peut être appliquée à des applications écrites dans tout langage de programmation, et qui utilisent tout type de services externes (base de données, file, cache mémoire, etc.)

Les 12 facteurs

I. Base de code

Une base de code suivie avec un système de contrôle de version, plusieurs déploiements

II. Dépendances

Déclarez explicitement et isolez les dépendances

III. Configuration

Stockez la configuration dans l’environnement

IV. Services externes

Traitez les services externes comme des ressources attachées

V. Build, release, run

Séparez strictement les étapes d’assemblage et d’exécution

VI. Processus

Exécutez l’application comme un ou plusieurs processus sans état

VII. Associations de ports

Exportez les services via des associations de ports

VIII. Concurrence

Grossissez à l’aide du modèle de processus

IX. Jetable

Maximisez la robustesse avec des démarrages rapides et des arrêts gracieux

X. Parité dev/prod

Gardez le développement, la validation et la production aussi proches que possible

XI. Logs

Traitez les logs comme des flux d’évènements

XII. Processus d’administration

Lancez les processus d’administration et de maintenance comme des one-off-processes

 

Lire tout l’article a la source original: 12factor.net

 

Yann Klis, co-fondateur et CEO Scalingo revient sur les 12 bonnes pratiques pour créer des applications qui pourront facilement tenir des montées en charge et en faciliter la maintenance. Initialement créée pour les environnements type Heroku, cette liste de bonnes pratiques s’est étendue à toutes les formes de déploiement d’applications web.

Introduction to automated, static code analysis in PHP

Static analysis of a PHP project by a CIP such as Jenkins requires optimization of the rules for excluding directories that are not part of the developed code. In the following article I want to introduce the most common methods and tools addressing static code analysis in PHP.

Static analysis tools

Beside the usual checks like manual code review, training (e.g. using XP programming sessions) and automated unit tests using PHPUnit, there are some metrics that can be measured automatically making my work easier and helping to reduce error rates in the review process.

So, I want indicators that can measure the quality of my code. These indicators are produced by third-party tools (for the most part, it is a port – for the PHP – of analysis tools from the Java world) such as:

 

Read more from original source: Introduction to automated, static code analysis in PHP

References:

Design patterns: Adapter in PHP

Software development is improved every day by new concepts, methodologies, and high quality libraries and frameworks. But even with all these improvements, we cannot prevent change in software development. You may think that your system is designed perfectly to cater to all of its requirements, but there will always be a change request that ruins your perfect design. We have to be prepared for all possible changes as developers.

In the Adapter Design Pattern, a class converts the interface of one class to be what another class expects.

To translate one interface for a class into a compatible interface. An adapter allows classes to work together that normally could not because of incompatible interfaces by providing its interface to clients while using the original interface.

Adapters are one of the easiest patterns to comprehend and at the same time one of the most useful ones.Strangely enough documentation and examples for this particular pattern seems to be somewhat lacking in the PHP world (at least as far as the research for this article took me) so I’ll try to provide examples that are closer to real world usages.

But first, we need to go over some basic concepts about this pattern. As with any pattern, the adapter pattern has multiple participants:

  • Client: The client is a class or object that wants to consume the Adaptee public API.
  • Adapter: The adapter provides a common interface between the adaptee and its clients.
  • Adaptee: The adaptee is an object from a different module or library.

Another advantage of the adapter pattern is that allows us to decouple our client code from the adaptee implementations. Let’s see what that means in the following example.

UML Diagram

Alt Adapter UML Diagram

Code

You can also find these code on GitHub

BookInterface.php

Book.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace DesignPatterns\Structural\Adapter;

class Book implements BookInterface
{
    /**
     * @var int
     */
    private $page;

    public function open()
    {
        $this->page = 1;
    }

    public function turnPage()
    {
        $this->page++;
    }

    public function getPage(): int
    {
        return $this->page;
    }
}

EBookAdapter.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php

namespace DesignPatterns\Structural\Adapter;

/**
 * This is the adapter here. Notice it implements BookInterface,
 * therefore you don't have to change the code of the client which is using a Book
 */
class EBookAdapter implements BookInterface
{
    /**
     * @var EBookInterface
     */
    protected $eBook;

    /**
     * @param EBookInterface $eBook
     */
    public function __construct(EBookInterface $eBook)
    {
        $this->eBook = $eBook;
    }

    /**
     * This class makes the proper translation from one interface to another.
     */
    public function open()
    {
        $this->eBook->unlock();
    }

    public function turnPage()
    {
        $this->eBook->pressNext();
    }

    /**
     * notice the adapted behavior here: EBookInterface::getPage() 
     * will return two integers, but BookInterface
     * supports only a current page getter, so we adapt the behavior here
     *
     * @return int
     */
    public function getPage(): int
    {
        return $this->eBook->getPage()[0];
    }
}

EBookInterface.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php

namespace DesignPatterns\Structural\Adapter;

interface EBookInterface
{
    public function unlock();

    public function pressNext();

    /**
     * returns current page and total number of pages, like [10, 100] is page 10 of 100
     *
     * @return int[]
     */
    public function getPage(): array;
}

Kindle.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

namespace DesignPatterns\Structural\Adapter;

/**
 * this is the adapted class. In production code, 
 * this could be a class from another package, some vendor code.
 */
class Kindle implements EBookInterface
{
    /**
     * @var int
     */
    private $page = 1;

    /**
     * @var int
     */
    private $totalPages = 100;

    public function pressNext()
    {
        $this->page++;
    }

    public function unlock()
    {
    }

    /**
     * returns current page and total number of pages, 
like [10, 100] is page 10 of 100
     *
     * @return int[]
     */
    public function getPage(): array
    {
        return [$this->page, $this->totalPages];
    }
}

Test

Tests/AdapterTest.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

namespace DesignPatterns\Structural\Adapter\Tests;

use DesignPatterns\Structural\Adapter\Book;
use DesignPatterns\Structural\Adapter\EBookAdapter;
use DesignPatterns\Structural\Adapter\Kindle;
use PHPUnit\Framework\TestCase;

class AdapterTest extends TestCase
{
    public function testCanTurnPageOnBook()
    {
        $book = new Book();
        $book->open();
        $book->turnPage();

        $this->assertEquals(2, $book->getPage());
    }

    public function testCanTurnPageOnKindleLikeInANormalBook()
    {
        $kindle = new Kindle();
        $book = new EBookAdapter($kindle);

        $book->open();
        $book->turnPage();

        $this->assertEquals(2, $book->getPage());
    }
}

 

References:

CQRS PATTERN

CQRS, qui signifie Command Query Responsibility Segregation, est issu du CQS (Command Query Separation) introduit par Bertrand Meyer dans son ouvrage Object Oriented Software Construction. Meyer soumet le principe que les classes d’une méthode doivent être soit des queries soit des commands.

La différence entre le CQS et le CQRS résulte dans le fait que chaque object CQRS est divisé en deux objets : un pour la requête et un pour la commande.

Une commande est définie comme une méthode qui change un état, alors qu’une requête (query) ne fait que retourner une valeur.

La figure suivante montre l’implémentation basique du pattern CQRS au sein d’une application. Elle entreprend l’échange de messages sous forme de commandes et d’événements. Voyons cela de plus près.

Screen Shot 2015-03-31 at 19.57.09

Figure 1: Exemple d’implémentation du pattern CQRS

 

On voit clairement la séparation des parties lectures et écritures sur la figure précédente : l’utilisateur fait une modification sur sa page, ce qui engendre l’envoie d’une commande. Une fois cette commande terminée, un event est publié pour signaler qu’une modification a été apportée.

Voyons cela plus en détail.

 

Langue Français:

Langue Anglais:

Image a la une prise par: CQRS Journey

Test double with webservices, Symfony and PHPUnit

Often, applications that i have developed was interfaced with external web services. Sometimes the services that my application would have to consume were themselves under development. Other times did not respond as they should have. What to do in these cases? Wait for the resolution of problems or the conclusion of the development of the API’s could stop the development of our application. But in a scenario of continuous development that is not acceptable.

So, the solution are mocking web services. But how to mock web services?

Case 1) Linking to internal routes instead of real webservice

Suppose we have to replace a web-service defined on config_dev.yml as well:

web_services:
  service1:
    api_info:
      endpoint: 'http://api-services/service1'
      api_user: 'service1'
      api_pass: 'service1'

1 – Replace the real config with:

web_services:
  service1:
    api_info:
      endpoint: 'http://salletti.myapplication.dev/api-services-mocked/service1'
      api_user: ''
      api_pass: ''

2 – Create new route in routing.yml:

service1-mocked:
    path:     /api-services-mocked/service1
    defaults: { _controller: 'MyApplicationMockBundle:Mock:service1' }
    methods: [POST]

3 – Create Action in MockController of MoclBundle:

<?php

namespace MyApplication\MockBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * @codeCoverageIgnore
 * No need to be cover
 */
class MockController extends Controller
{
    public function servive1Action(Request $request)
    {
        //Your logic here
       $response = new Response($this->container->get('mock_service')->getGenericResultWithoutError());
       $response->headers->set('Content-Type', 'application/json');

       return $response;
    }
}

It’s all, with this strategy you can mock every external web service in a easy way. You can as well use the mock for yours unit tests, simply changing in config_test.yml urls pointing to the external serviceswith your internal urls.

 

Case 2) Injecting mocked class instead real classes

Imagine having clients interfacing with external web services. Clients are injected inside others classes. For example:

#MyApplication/MyBundle/Resources/services.yml
services:
  service1_client:
    class: MyApplication\MyBundle\Client\Service1Client
    calls:
      - [ setLogger, ['@my_logger']]
  service1_consumer:
    class: MyApplication\MyBundle\Client\Service1Consumer
    calls:
      - [ setClient, ['@service1_client']]

And the classes:

<?php

namespace MyApplication\MyBundle\Client
class Service1Client {

   public function getFoo(array $params)
   {
      $result = $this->callService('getFoo', $params);
      return isset($result->foo) ? $result->foo : false;
   } 
}
<?php

namespace MyApplication\MyBundle\Service1Consumer
class Service1Consumer {

   public function getFoo()
   {
      $params = ...;
      return $this->client->getFoo($params);
   }

   public function setClient($client)
   {
      $this->client = $client; 
   } 
}

 

The idea is to change service to inject:

1 – Create a Mock class

<?php

namespace MyApplication\MockBundle\Client
class Service1Client {

   public function getFoo(array $params)
   {
      //return what you want. Your logic here
      return array('foo' => 'bar');
   } 
}

2 – Create a services_test.yml

services:
  service1__mock_client:
    class: MyApplication\MockBundle\Client\Service1Client
    calls:
      - [ setLogger, ['@my_logger']]
 service1_consumer:
    class: MyApplication\MyBundle\Client\Service1Consumer
    calls:
      - [ setClient, ['@service1_mock_client']]

3 – Load services_test.yml file if you are in a test environment

namespace MyApplication\MyBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
class MyApplicationMyBundleExtension extends Extension
{
 /**
 * {@inheritDoc}
 */
 public function load(array $configs, ContainerBuilder $container)
 {
     $configuration = new Configuration();
     $config = $this->processConfiguration($configuration, $configs);
     $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
     $loader->load('services.yml');
    
    //If we are on test env we load classes mocked defined on service_test.yml
    if ($container->getParameter('kernel.environment') == 'test') {
      $loader->load('services_test.yml');
    }
 }

 

Case 3) Useing Test Doubles of PHPUnit

1 – Using getMockBuilder

<?php
use PHPUnit\Framework\TestCase;

class ConsumerTest extends TestCase
{
    public function testConsumer()
    {
        // Create a stub for the SomeClass class.
        $stubClient = $this->getMockBuilder(Service1Client:class) 
       ->disableOriginalConstructor() 
       ->getMock(); 

       // Configure the stub. 
      $stubClient->method('getFoo')->willReturn(array('foo' => 'bar'));
      $consumer = new Service1Consumer();
      $consumer->setClient($stubClient)
      $this->assertArrayHasKey('foo', $consumer->getFoo()); 
   } 
} 
?>

2 – Using Prophecy

<?php
use PHPUnit\Framework\TestCase;

class ConsumerTest extends TestCase
{
    public function testConsumer()
    {
        $consumer = new Service1Consumer();

        // Create a prophecy for the Observer class.
        $client = $this->prophesize(Service1Client::class);

        // Set up the expectation for the update() method
        // to be called only once
        // as its parameter.
        $client->getFoo(Argument::type('array'))->shouldBeCalled();
        $client->willReturn(array('foo' => 'bar'));        
        // Reveal the prophecy and attach the mock object
        // to the Consumer.
        $consumer->attach($client->reveal());
        $this->assertArrayHasKey('foo', $consumer->getFoo());
    }
}
?>

Conclusion

Sometimes it is just plain hard to test the system under test (SUT) because it depends on other components that cannot be used in the test environment. This could be because they aren’t available, they will not return the results needed for the test or because executing them would have undesirable side effects. In other cases, our test strategy requires us to have more control or visibility of the internal behavior of the SUT. I have listed three strategies that i used, hoping that can be help to someone.

References:

Revue de code, les bonnes pratiques

La qualité du code source produit est essentielle pour assurer la cohérence, la performance et la maintenabilité des applications. Cette qualité peut être obtenue en continu via des outils d’analyse mais ce n’est pas toujours suffisant.

Les bugs trouvés en production restent les plus coûteux, c’est pourquoi il est primordial de pouvoir les déceler à temps de façon à pouvoir les corriger au plus tôt.

Les sources du projet doivent être correctement organisées, aisément lisibles et respectant les normes de codage pour en assurer la maintenance et les évolutions possibles. Il est fort probable que ça ne sera pas la même équipe qui s’occupera de la maintenance ou des évolutions qui seront faites tout au long du cycle de vie du projet.

Nous utilisons principalement deux formats de revue de code dans nos projets : la revue collective, plutôt formelle et la revue par un pair, un format plus léger. Les deux présentent des avantages et des inconvénients : revenons ensemble sur ces formats et comment les mettre en place dans une équipe.

Dans la plupart des domaines impliquant l’écriture, on n’imagine pas que ce qui est écrit soit publié sans avoir été relu. Un article sera toujours relu avant publication (par exemple celui que vous êtes en train de lire), que ça soit pour une vérification sur le fond – le sujet de l’article est-il bien traité ? – ou sur la forme – orthographe, grammaire, structure et lisibilité du texte.
De la même manière, la pratique de la revue de code consiste à faire relire son code afin d’y trouver le maximum de défauts, que ça soit sur le fond – est-ce que ce code fonctionne, et matérialise bien la fonctionnalité prévue ? – ou sur la forme – clarté, lisibilité, respect des standards, etc.

Et chez vous, combien de lignes de code mettez vous en production sans qu’elles aient été relues ?

La revue de code est une pratique presque aussi ancienne que le développement de logiciel, et très répandue chez des entreprises comme Microsoft ou Google. Il y a une bonne raison à cela, c’est qu’elle permet de détecter les défauts plus tôt dans le processus de développement.

Pourtant cette pratique est relativement peu répandue dans les équipes que nous rencontrons. C’est parfois parce qu’elle est méconnue, mais c’est plus souvent pour de mauvaises raisons : “On n’a pas le temps, ça coûte trop cher.” “On a essayé mais ça a tourné au troll.” Ou encore “Je ne veux pas le faire, c’est du flicage.”

Il semble donc que ça ne soit pas une pratique si simple à mettre en place !


Je vous invites a lire les articles à la source original.

Architecture Microservices – Les bonnes pratiques

Après plusieurs années de développement logiciel et de maintenance, certaines applications d’entreprise s’avèrent laborieuses et trop coûteuses à faire évoluer. Ce type de dette technologique est un constat, une difficulté majeure, que rencontrent à terme de nombreuses entreprises.

Cela conduit souvent à faire table rase des développements passés, et à les reconstruire à partir de zéro. L’essor des architectures micro-services (micro-services architectures – MSA) répond à cette problématique, et propose des moyens de la résoudre.

Les architectures micro-services permettent de développer, de déployer et de gérer opérationnellement des applications distribuées, constituées de services aux fonctionnalités complémentaires, potentiellement hétérogènes et interopérables.

Les micro-services favorisent drastiquement l’indépendance des cycles de vie, qu’il s’agisse des cycles de conception, de développement, ou de déploiement en production.

 

Elles se distinguent des architectures orientées services (SOA), répandues depuis environ une décennie :

 

  • Elles émergent de la recherche d’une agilité pratique et d’une efficacité accrue par des précurseurs du Cloud Computing, tels que Netflix, Amazon, Gilt ou Airbnb.
  • Elles sont naturellement adaptées au Cloud, et se déploient nativement sur les « Platforms as a Service » (PaaS). Il s’agit du type de plateformes sur lesquelles elles se sont développées et déployées historiquement, et elles en exploitent naturellement les bénéfices.
  • Elles ne dépendent aucunement d’une solution d’éditeur logiciel, tel que les Enterprise Service Bus (ESB), et minimisent les besoins d’intégration logicielle (EAI), mettant en œuvre des solutions décentralisées et alternatives aux fonctionnalités sophistiquées des ESB (médiation, orchestration de services, etc…)

 

OBJECTIFS DES ARCHITECTURES MICRO-SERVICES

« Qu’est-ce que l’architecture ? », Martin Fowler reprend à son compte la question dans son article ’Who Needs an Architect?’ . Il y développe sa propre définition :

  • À première vue, l’architecture d’une application se résume en la décomposition de la totalité du système applicatif considéré en éléments constitutifs plus simples, aux rôles, responsabilités et limites bien identifiés.
  • Mais, du point de vue pratique des personnes en charge d’une application, l’architecture, c’est surtout, ce qu’il est difficile de changer. De ce point de vue, l’architecture doit faire l’objet de décisions saines en amont d’un projet afin de minimiser les coûts d’évolution.

En effet, les évolutions d’une application nécessitent un effort d’adaptation, et le coût qu’elles induisent s’accroît au fur et à mesure que le système se complexifie. L’évolution d’un système a ainsi naturellement tendance à ralentir au fil du temps, et ce d’autant plus vite que « ce qu’il est difficile de changer » s’accumule.

En conclusion et un peu paradoxalement, une bonne architecture est minimaliste, et permet de changer facilement n’importe lequel de ses composants.

Les principaux buts des architectures micro-services sont :

  • de réduire les empêchements au changement,
  • de libérer les développeurs et les opérationnels des contraintes de la complexité,
  • et finalement d’accroître la compétitivité de l’entreprise.

 

Lire l’article a la source original: Partie 1, Partie 2

Autre article en langue français sur le sujet: Microservices architecture best practices