Beancount ou la comptabilité pour les hackers

En matière de comptabilité personnelle, l'offre en logiciels et autres applications pour smartphones ne manque pas, et pourtant après de nombreuses tentatives je n'ai rien trouvé qui me convenait: les solutions existantes étaient toujours ou trop simplistes ou trop complexes, trop chères, pas assez ergonomiques, trop instables, et j'en passe...

Sur le point de développer ma propre application, j'ai finalement découvert Beancount, qui s'approche de la perfection, en tout cas pour mes besoins. Je vais donc présenter dans cet article le principe de Beancount, et comment l'utiliser pour gérer ses comptes.

Beancount est basé sur la comptabilité en partie double, et repose sur l'enregistrement des transactions dans un simple fichier texte: il est donc possible de tout faire en ligne de commande, ce qui ravira les fans de Linux, et fera certainement fuir les autres utilisateurs habitués aux interfaces graphiques 😉 . Beancount fournit entre autres une interface Web pour explorer ses comptes, un langage de requêtes similaire à SQL,  et permet d'écrire ses propres plugins et scripts en Python pour étendre les fonctionnalités.

La comptabilité en partie double

Avant de comprendre Beancount, il faut d'abord maîtriser les bases de la comptabilité en partie double. Il s'agit de la méthode utilisée pour effectuer la comptabilité d'une entreprise, d'une organisation, ou d'un État dans les règles de l'art, mais on peut très bien l'appliquer pour gérer ses comptes personnels.

Son principe est assez simple: toute transaction (achat, vente, virement, etc.) est représentée par un transfert d'argent entre deux (ou plus) comptes. La notion de compte est ici à prendre au sens large: il peut s'agir d'un compte bancaire, d'un compte de caisse, mais aussi d'un poste de dépenses, d'un compte représentant des stocks, etc.

La règle absolue à respecter dans la comptabilité en partie double est que tout sortie d'argent doit être compensée par une rentrée équivalente (et vice-versa). Par exemple, supposons que vous achetez un lot de ramettes de papier pour 50 euros: votre compte bancaire sera donc diminué de 50 euros, et en contrepartie il faut augmenter votre compte "Fournitures de bureau" de 50 euros. De même, si vous recevez un salaire de 2000 euros, vous augmentez votre compte bancaire de 2000 euros, et en contrepartie vous devez donc diminuer votre compte "Salaires" du même montant.

A ce stade, voici comment on peut enregistrer ces opérations en comptabilité:

Date Compte Libellé Montant
2015-05-12 Banque Achat papier -50 EUR
2015-05-12 Fournitures de bureau Achat papier +50 EUR
2015-05-30 Banque Salaire mai 2015 +2000 EUR
2015-05-30 Salaire Salaire mai 2015 -2000 EUR

Grâce au principe de partie double, c'est-à-dire l'écriture de toute transaction dans deux comptes simultanément, la somme de toutes les opérations est toujours nulle, ce qui permet de s'assurer facilement qu'il n'y a pas d'erreur dans les comptes.

Il peut sembler peu intuitif que le compte "Salaire" soit négatif, puisque c'est de l'argent gagné, mais il suffit de se souvenir que les comptes doivent s'équilibrer, donc si le compte "Banque" augmente, le compte "Salaire" doit diminuer. Une autre façon de voir les choses est de considérer l'argent du salaire comme la contepartie d'un travail: le salarié reçoit de l'argent sur son compte en banque en échange du travail qu'il donne à son employeur. Puisque le travail est donné, c'est donc quelque chose qui "sort", et par conséquent il doit être comptabilisé en négatif.

Après avoir enregistré toutes les opérations, on peut calculer le solde de chaque compte, en additionant tous les montants affectés à ces comptes depuis leur ouverture:

Compte Solde
Banque +1950 EUR
Fournitures de Bureau +50 EUR
Salaire -2000 EUR

Si vous avez compris les explications précédentes, il doit être clair que la somme des soldes de tous les comptes doit être égale à 0, ce qui est une bonne façon de vérifier qu'il n'y a pas d'erreurs.

Pacioli

Actif, Passif, Dépenses et Recettes

Pour organiser la comptabilité, les différents comptes sont répartis en quatre catégories: actif, passif, recettes et dépenses, qu'on peut définir ainsi:

  • Actif: l'argent qu'on possède
  • Passif: l'argent qu'on doit
  • Dépenses (ou Charges): l'argent qui sort
  • Recettes (ou Produits): l'argent qui rentre

Si on reprend l'exemple précédent, on voit facilement que:

  • Le compte "Banque" est un compte d'actif
  • Le compte "Fournitures de bureau" est un compte de dépenses
  • Le compte "Salaire" est un compte de recettes

Les comptes de passif sont utilisés par exemple lorsqu'on achète un bien à crédit. Supposons que vous achetez vos ramettes de papier le 12 mai, et que vous payez le fournisseur (METRO par exemple) une semaine plus tard. Dans ce cas, il y a deux transactions à enregistrer dans la comptabilité:

Date Compte Libellé Montant
2015-05-12 Magasin METRO Achat papier facture 123456 -50 EUR
2015-05-12 Fournitures de bureau Achat papier facture 123456 +50 EUR
2015-05-19 Banque Paiement facture METRO 123456 -50 EUR
2015-05-19 Magasin METRO Paiement facture METRO 123456 +50 EUR

Le compte "Magasin METRO" (compte de fournisseur) est ici un compte de passif, car il correspond à une dette.

Si on fait la somme des opérations, on voit que le tout revient à transférer 50 euros du compte "Banque" vers le compte "Fournitures de bureau", car les opérations sur le compte "Magasin METRO" s'annulent une fois que la facture a été payée. Un des intérêts de la comptabilité en partie double est qu'elle permet de comptabiliser correctement ce genre de dettes, même si elles ne sont que temporaires. Dans le cas d'un crédit immobilier, la dette peut durer de nombreuses années donc il est encore plus important d'en garder une trace !

Pour être tout à fait complet, il faut préciser que le passif se compose en réalité de deux parties: les Dettes et le Capital. Dans la comptabilité anglo-saxonne, le capital est une catégorie de compte à part entière, alors que dans la comptabilité française, dettes et capital sont regroupés sous le même terme de "passif". La notion de capital n'est pas forcément intuitive, disons pour faire simple que dans le cas d'une entreprise, le capital représente la valeur de cette entreprise, c'est-à-dire l'actif moins les dettes. Dit autrement, le capital représente la dette de l'entreprise vis-à-vis de ses propres actionnaires (ou associés), c'est d'ailleurs pourquoi il est classé parmi les comptes de passif.

En pratique, il suffit de se souvenir que l'actif doit toujours être égal au passif, car tout ce qu'une société possède est une dette envers quelqu'un d'autre (envers les créanciers ou les associés). Le capital peut donc être considéré comme une "astuce" technique pour équilibrer les comptes: si l'actif est supérieur aux dettes (ce que je vous souhaite), la différence entre les deux se retrouve automatiquement au capital.

Pour finir, il est utile de remarquer que les comptes d'actif et de passif permettent d'évaluer l'état des finances d'une entreprise à n'importe quel instant, et sont appelés comptes de bilan. D'un autre côté, les comptes de recettes et de dépenses traduisent les mouvements financiers de l'entreprise sur une période donnée, et sont appelés comptes de gestion. Dans une entreprise, les comptes de gestion sont remis à zéro (soldés) chaque année lors de la clôture des comptes, et au passage le solde restant (appelé résultat de l'exercice comptable, ou également bénéfice lorsqu'il est positif) est transféré sur un compte de capital.

Débit et crédit

L'approche que j'ai décrite jusqu'ici (et qui est celle utilisée dans Beancount) pourra sembler surprenante à ceux qui ont déjà des notions de comptabilité.

En réalité, les comptables ne représentent pas les transferts entre comptes par des montants positifs ou négatifs, mais utilisent les notions (peu intuitives au premier abord) de débit et crédit:

  • Un débit représente une entrée vers un compte
  • Un crédit représente une sortie depuis un compte

Dans une écriture comptable, on note les débits et crédits dans deux colonnes différentes, le débit étant toujours à gauche, et le crédit à droite, et on utilise seulement des nombres positifs.

Si on reprend notre exemple initial, les transactions s'écrivent dans un comptabilité traditionnelle sous la forme suivante:

Date Compte Libellé Débit Crédit
2015-05-12 Banque Achat papier 50 EUR
2015-05-12 Fournitures de bureau Achat papier 50 EUR
2015-05-30 Banque Salaire mai 2015 2000 EUR
2015-05-30 Salaire Salaire mai 2015 2000 EUR

Le principe est le même que précédemment, mais au lieu d'utiliser des montants positifs pour les entrées d'argent, on écrit les montants dans la colonne "débit", et au lieu d'utiliser des montants négatifs pour les sorties, on écrit les montants dans la colonne "crédit", toujours en utilisant des nombres positifs.

Avec cette méthode, le calcul du solde des comptes est plus compliqué, puisqu'il faut manipuler des débits et des crédits au lieu de faire une simple addition. Si la somme des débits est supérieure à la somme des crédits, le solde du compte est débiteur, et si la somme des crédits est supérieure à la somme des débits, le solde du compte est créditeur.

Avec notre exemple, on obtient:

Compte Total débits Total crédits Solde débiteur Solde créditeur
Banque 1950 EUR 1950 EUR
Fournitures de Bureau 50 EUR 50 EUR
Salaire 2000 EUR 2000 EUR

Tout serait bien plus simple en se limitant à l'utilisation des nombres positifs et négatifs (comme le fait Beancount), mais malheureusement des siècles d'histoire de la comptabilité en ont décidé autrement !

Pour ajouter à la confusion, la terminologie est exactement l'inverse de ce que vous pouvez trouver chaque mois sur votre relevé bancaire, puisqu'un compte en banque est toujours censé être créditeur et non débiteur ! En fait le paradoxe s'explique facilement: du point de vue de votre banque, l'argent disponible sur votre compte est de l'argent qu'elle vous doit, c'est donc un crédit pour elle. Par contre de votre point de vue, la situation est exactement l'inverse et cet argent est donc compté comme un débit.

À noter que les comptes d'actif et de dépenses sont en principe toujours débiteurs (donc "positifs"), et les comptes de passif et de recettes sont en principe toujours créditeurs (donc "négatifs").

Plan de comptes

Le dernier point à aborder est la notion de plan de comptes. C'est tout simplement la liste de tous les comptes utilisés pour effectuer la comptabilité.

En France, il est obligatoire de suivre une réglementation appelée Plan Comptable Général (PCG) pour faire la comptabilité d'une entreprise. Le PCG définit un plan de compte standard, qui classe les différents comptes en 7 catégories principales, et attribue un numéro à chaque type de compte. Le compte "Fournitures consommables" porte par exemple le numéro 6022, et il contient (entre autres) un sous-compte "Fournitures de bureau" qui porte le numéro 60225.

Pour une comptabilité personnelle, il est inutile de suivre les recommendations du PCG, mais il faut tout de même réfléchir à la liste des comptes qu'on doit utiliser, et à la manière des les classer.

Dans Beancount, chaque compte doit être affecté à une des 5 catégories suivantes:

  • Assets (Actif)
  • Liabilities (Passif)
  • Equity (Capital)
  • Income (Recettes)
  • Expenses (Dépenses)

Comme expliqué précédemment, le Capital est une catégorie à part dans le système anglo-saxon, qui est utilisé par Beancount.

Par défaut ces noms sont en anglais dans Beancount, mais il est possible de définir une option pour les renommer en français (ou en n'importe quoi).

Un plan de compte utilisable dans Beancount pourrait ressembler à ceci:

  • Actif:LCL:CompteCheques
  • Actif:LCL:LivretA
  • Passif:LCL:CreditImmobilier
  • Recettes:Salaire
  • Recettes:Loyer
  • Depenses:Charges:RemboursementCredit
  • Depenses:Charges:Electricite
  • Depenses:Charges:Telephone
  • Depenses:Charges:Imports
  • Depenses:Alimentation
  • Depenses:Loisirs
  • Depenses:Sante
  • Depenses:Vetements
  • Depenses:Transports
  • Depenses:Transports:Voiture
  • Depenses:Logement
  • Depenses:Autres

L'utilisation du séparateur ":" permet de définir une hiérarchie de comptes, par exemple "Depenses:Transport:Voiture" est un sous-compte du compte "Depenses:Transport". Ce n'est pas obligatoire, mais permet de mieux s'y retrouver quand on utilise un grand nombre de comptes (l'exemple précédent est très simplifié; j'utilise personnellement une centaine de comptes différents).

Une petite limitation de Beancount est qu'il n'est pas possible d'utiliser des espaces dans un nom de compte, il faut donc utiliser des tirets à la place, ou coller les mots comme je l'ai fait dans l'exemple.

Fonctionnement général de Beancount

Grâce à ces notions de base de comptabilité, il est maintenant possible de rentrer dans le vif du sujet, à savoir le fonctionnement de Beancount.

Contrairement à la majorité des logiciels de comptabilité, Beancount se lance en ligne de commande, et n'a donc pas besoin d'interface graphique. Son auteur, Martin Blais, s'est inspiré de Ledger, qui fonctionne sur le même principe.

L'idée principale est d'utiliser un langage spécifique (un Domain Specific Language ou DSL, en anglais) pour décrire ses transactions dans un simple fichier texte. Une fois que ce fichier est écrit (avec n'importe quel éditeur de texte), Beancount fournit différents outils pour en tirer divers rapports et statistiques, sans jamais modifier le fichier original. Il est également possible d'accéder à certains rapports avec une interface Web, qui est très pratique pour naviguer dans les comptes, mais ne permet pas de toute façon de modifier le fichier de comptes.

Le format utilisé pour décrire les transactions a été conçu pour être facilement manipulable à la fois par un humain ou par un programme, contrairement à la quasi-totalité des autres formats existants.

Il est temps de passer à la pratique ! En langage Beancount, notre exemple d'achat de papier s'écrit comme ceci:

Le format est extrêmement simple: chaque transaction commence par une ligne avec la date et une description, puis en dessous on écrit les opérations pour les différents comptes impactés par la transaction. On remarque qu'il n'est pas question ici de débits et crédits: la notation utilise des montants positifs et négatifs comme expliqué dans l'introduction.

Étant donné que la somme des écritures d'une même transaction doit toujours être nulle, il est possible de laisser Beancount calculer automatiquement le montant d'une des écritures, ce qui donne la forme simplifiée suivante:

En fait avant d'enregistrer des transactions, il faut d'abord ouvrir les comptes utilisés, grâce à la directive "open". Par exemple on ouvre le compte "Banque" comme ceci:

L'ordre des écritures dans le fichier n'a pas d'importance, par contre les dates doivent être cohérentes, il faut donc évidemment que le compte soit ouvert avant d'apparaître dans une transaction.

Voici maintenant un exemple complet de fichier Beancount, qu'on appelera par exemple "compta.beancount":

Les options ne sont pas nécessaires si vous souhaitez garder les noms par défaut en anglais.

Cet exemple montre également une fonctionnalité extrêmement pratique de Beancount, qui est le remplissage automatique des "trous" dans la comptabilité, grâce aux directive "pad" et "balance":

  • "balance" permet d'indiquer le solde connu d'un compte à une certaine date
  • "pad" permet d'insérer automatiquement une écriture pour que le solde du compte soit respecté

Dans cet exemple, la directive "pad" est équivalente à la transaction suivante:

Le solde initial du compte est donc calculé automatiquement, alors qu'on ne connaissait que le solde final.

Au passage on remarque que le solde initial du compte "Banque" est pris depuis le compte "Capital:SoldeOuverture", qui est dédié à ce genre d'opérations. En effet l'argent doit toujours venir de quelque part, et ce compte représente le capital que l'on possédait avant de démarrer sa comptabilité sous Beancount.

Voilà, maintenant que nous avons un fichier Beancount, il faut bien faire quelque chose avec ! Pour commencer, nous pouvons utiliser la commande "bean-report" pour produire différents rapports, par exemple le solde courant de chaque compte, ce qu'on appelle la balance des comptes:

On peut aussi par exemple afficher le journal (l'ensemble des écritures) d'un compte donné, comme ceci:

La façon la plus simple d'explorer ses comptes reste encore l'interface Web, qui se lance avec la commande "bean-web":

Par défaut, l'interface est accessible à l'adresse http://127.0.0.1:8080/. Elle permet de visualiser le journal, le bilan, la balance des comptes, et le compte de résultat, éventuellement par année.

Voici par exemple le bilan (balance sheet en anglais) de notre exemple pour l'année 2015, c'est-à-dire le tableau récapitulant le solde de tous les comptes d'actif et passif:

beancount-bilan

Importation automatique des transactions

Bien sûr il n'est pas très pratique de rentrer à la main toutes les transactions, surtout en l'absence d'interface graphique pour faciliter la tâche.

La solution la plus pratique consiste à exporter ses comptes depuis le site de sa banque (au format CSV, Quicken, OFX, ou autre) et de convertir les fichiers automatiquement au format Beancount, par exemple grâce à l'outil LedgerHub (du même auteur).

Il est toujours possible de rectifier le fichier obtenu après coup, par exemple pour ajouter des remarques ou éliminer des doublons.

Requêtes personnalisées avec bean-query

Si on veut obtenir des rapports plus précis, il est possible d'utiliser l'outil "bean-query", qui fournit un langage de requêtes similaire à SQL:

Si on veut par exemple retrouver toutes les transactions dont la description contient le texte "123456" (un numéro de facture en l'occurence) pendant l'année 2015, on peut lancer la requête suivante:

On peut aussi regrouper les résultats par compte, en affichant uniquement la somme des écritures pour chaque compte:

Avec cet exemple, on vérifie ainsi que le compte "Passif:MagasinMETRO" a un solde nul, ce qui signifie que la facture a bien été payée.

Les possibilités sont sans fin, il ne reste plus qu'à faire preuve d'imagination !

Scripts et plugins en Python

Pour finir, voyons comment écrire ses propres programmes en utilisant l'API Python de Beancount.

Rien ne vaut un exemple, donc voici un petit programme Python qui ouvre un fichier Beancount, et affiche la date et la description de toutes les transactions:

L'exécution du programme produit le résultat suivant:

Et voilà ! J'espère vous avoir donné un bon aperçu des possibilités de Beancount, et pour plus de détails il vous reste à lire la documentation sur le site du projet !

Introduction à Docker

Depuis son lancement en 2013, Docker est un projet qui fait beaucoup parler de lui, et pour de bonnes raisons !

docker

Ceci est une révolution

En très très bref, Docker est un outil permettant de déployer facilement des applications sur un serveur Linux.

En un peu moins bref, Docker fournit un moyen d'encapsuler des applications dans des containers isolés, et de démarrer ces containers sur n'importe quel machine Linux, quelle que soit la distribution installée. En ce sens, Docker couvre les mêmes besoins qu'une machine virtuelle (VM), mais comme nous allons le voir, il y a tout de même des différences importantes entre containers et VMs.

Alors où est la révolution dans tout ça ? Après tout, n'importe quelle distribution Linux permet d'installer une nouvelle application en quelques clics, ou avec une simple ligne de commande. Mais que se passe-t-il si l'application qu'on souhaite installer n'est pas disponible dans la distribution, ou si seulement une vieille version est disponible ? Il faut alors récupérer un package par ses propres moyens, et c'est généralement là que les ennuis commencent:

  • Le package peut avoir des dépendances incompatibles avec les autres packages déjà installés, et c'est l'impasse...
  • Pire, il se peut qu'aucun package ne soit disponible, il faut alors télécharger le code source et passer des heures à essayer de compiler l'application soi-même (avec un fort risque de retomber sur les problèmes de dépendances)
  • En supposant que l'application démarre, elle n'a jamais été testée et validée sur sa propre machine, et donc des nouveaux bugs peuvent apparaitre. Même avec de la bonne volonté, l'auteur de l'application peut avoir beaucoup de mal à reproduire (et donc à corriger) le problème puisque son environnement de travail est différent.

Containers et union mount

Avec Docker, chaque application est exécutée à l'intérieur d'un container, qui contient l'ensemble des dépendances requises par cette application. Chaque container Docker possède son propre système de fichier, qui embarque l'intégralité d'une distribution Linux (par exemple une Ubuntu), avec les packages nécessaires pour faire tourner l'application. Il n'y a donc plus aucun problème de dépendances, car l'environnement d'exécution est complètement maitrisé et déterministe.

Mais alors si on souhaite lancer plusieurs dizaines (ou centaines) d'applications sur une même machine, l'espace disque ne risque-t-il pas d'exploser, avec toutes ces distributions Linux installées en même temps ? En fait non ! Docker utilise une astuce appelée union mount, qui consiste à découper un système de fichiers en plusieurs couches (layers), et à pouvoir partager ces couches entre plusieurs systèmes de fichiers. En pratique, tous les containers basés sur la même distribution Linux vont en fait partager les mêmes fichiers de base (les bibliothèques et binaires système, les fichiers de configuration, etc.), et seule la différence entre ces containers est stockée sur disque. C'est une des grandes différences entre container Docker et VM: il est littéralement possible de lancer des milliers de containers sur la même machine, tout en utilisant très peu d'espace disque si ces containers sont similaires.

sandwich

Un autre aspect fondamental du fonctionnement de Docker est qu'un container n'est rien de plus qu'un process Linux (en réalité, un arbre de process) isolé. La conséquence est que démarrer un container revient en fait simplement à exécuter un process, ce qui est pratiquement aussi rapide que lancer ce même process en dehors d'un container. Au contraire d'une VM qui doit lancer un système d'exploitation complet au démarrage, ce qui peut prendre plusieurs dizaines de secondes, le démarrage d'un container Docker est donc quasiment instantané (tout dépend de l'application, évidemment) !

Docker fournit donc un moyen beaucoup plus léger qu'une VM pour encapsuler une application, mais les innovations ne s'arrêtent pas là !

Images, repositories et registry

Une grande idée de Docker est d'avoir repris les mêmes concepts que les systèmes de gestion de versions modernes, comme Git. Le principe est qu'un container Docker est toujours créé à partir d'une image Docker, qui est en quelque sorte un modèle (template) de container. Ces images sont conservées, et versionnées, dans un dépôt (repository) stocké en local sur la machine. Il est donc possible à tout instant de recréer un container Docker à partir d'une image d'une version précédente, de passer facilement d'une version à l'autre, ou même d'exécuter simultanément des containers basés sur des versions différentes.

Là où Docker rejoint encore Git, c'est qu'il est possible d'envoyer des images Docker sur un repository distant, appelé registry, ce qui permet facilement de partager et échanger des images entre plusieurs personnes. De même que Github permet de publier son code source sous Git sur Internet, Docker fournit le Docker Hub, qui est un registry public contenant des milliers d'images Docker prêtent à l'emploi. Il est par exemple possible de télécharger l'image officielle de WordPress sur le Docker Hub, ce qui permet de lancer Worpdress (avec serveur Web et PHP déjà intégrés) sur sa machine en quelques secondes !

Encore plus fort: le concept de Dockerfile définit un standard simple pour créer une image Docker soi-même. Un Dockerfile n'est rien d'autre qu'un fichier texte, contenant quelques commandes à exécuter pour construire une image Docker à partir d'une autre image (généralement venant du Docker Hub).

Voici par exemple un Dockerfile minimaliste permettant de créer une image Docker Ubuntu contenant un serveur MySQL:

Du container au navire

Le nom de "Docker" vient de l'analogie entre les containers Linux et le transport de marchandises. Grâces aux conteneurs (ceux de la vraie vie, cette fois), il est possible de transporter n'importe quelle marchandise sur n'importe quel bateau, train ou camion, n'importe où dans le monde. Comment ce miracle de la logistique est-il possible ? Tout simplement parce que les conteneurs ont des dimensions standard, ce qui permet de les transporter toujours de la même façon, quel que soit leur contenu. Ainsi, le fournisseur n'a pas à se soucier du mode de transport de ses marchandises, il lui suffit de tout mettre dans un conteneur, et le transporteur fera le reste. De la même façon, le transporteur n'a pas besoin de savoir ce que contiennent les conteneurs pour les transporter, du moment que le standard est respecté.

bateau-containers

Il se passe exactement la même chose avec les containers Docker, sauf qu'ici, le fournisseur est le développeur de l'application, et le transporteur est l'hébergeur. Il suffit au développeur d'encapsuler son application dans un container Docker, sans se soucier de la plateforme technique de l'hébergeur, et l'application peut être ainsi déployée de la même façon sur la propre machine du développeur, dans un data center privé, dans un cloud public, etc. De son côté, l'hébergeur peut manipuler des applications "enfermées" dans des containers Docker sans se soucier de leur contenu: différentes applications développées en Java, PHP, Python, Go, Node.js pourront donc être déployées et opérées exactement de la même façon sur un même serveur.