Sur la route d'Oxiane digressions diverses

LeBlog OXiane

29 juil
2010

Une réfutation de l’écriture du test en premier (Test-Driven Development)

Conjectures et réfutations

Karl Popper est un philosophe des sciences ayant fait des apports majeurs à l’épistémologie, avec entre autres sa définition de la démarche scientifique par la réfutabilité. Je me suis amusé à appliquer certaines de ses thèses à la mise au point de programmes, en supposant qu’un programme soit une connaissance objective au même titre qu’un théorème ou qu’une théorie scientifique.

Si on applique ces thèses, on peut démontrer que la lecture du code source ne suffit pas, par la seule puissance de la déduction, à prouver que le programme est correct. D’ailleurs, un test ne peut pas prouver la validité d’un programme, au contraire, il ne peut que mettre en évidence une erreur. Popper démontre que le raisonnement inductif n’est pas la méthode rationnelle pour se rapprocher de la vérité, mais que nous procédons par conjectures et réfutations. Tout raisonnement fonctionnerait à partir de théories que l’on essaie de contredire, par l’expérimentation ou par la logique. Pour valider un programme on cherche à le mettre en défaut, ce qui est pourtant intuitivement l’inverse du résultat visé.

Je vois donc la programmation comme l’ajout de conjectures sur un fond initial (langage de programmation employé, librairies, système d’exploitation, autres applications). Fond qui, en passant, est également réfutable selon Popper, contredisant les philosophes affirmant que tout raisonnement rationnel ne se fait qu’à partir d’une base de vérités que l’on augmente par déduction.

En poussant plus loin l’analogie, le test unitaire consisterait donc à tenter de réfuter la conjecture (le programme). Popper affirme également qu’une théorie qui en supplante une autre doit expliquer mieux ou plus de choses que la précédente mais également « survivre » aux mêmes tentatives de réfutation. C’est ce que j’appellerais les tests de non-régression.

Mais alors, si programme = conjecture et test = réfutation, que penser de cette pratique XP : « écrire systématiquement les test unitaires en premier, et ensuite seulement le programme qui va passer les tests unitaires avec succès » (le fameux Test-Driven Development) ?

En termes « popperiens » cela revient à faire des réfutations avant même de conjecturer ! Les « XPeurs » feraient-ils de la programmation d’une façon irrationnelle ?

Disons plutôt que cela signifie que la conjecture est implicite, qu’elle trotte dans la tête du programmeur (ou est discutée au sein du binôme pour ceux qui pratiquent également le « pair-programming ») pendant la programmation des réfutations/tests. Et c’est seulement une fois que toutes les réfutations sont posées que l’on rédige l’équation ou le programme. Connaissant à l’avance les tests, la programmation ressemble plus à mon avis à une sorte de régression au sens statistique (trouver la courbe qui passe par tous les points connus à l’avance).

Cela revient à peser tous les cailloux de la terre et trouver l’équation vraie pour tout un tas de cailloux donné afin de formuler la gravité. Il me semble donc à la fois plus rationnel (et plus intuitif, je l’avoue) de poser la conjecture (le programme) avant d’essayer de le réfuter (par les tests).

La connaissance objective

Là où je rejoins les partisans du test extrême c’est que la qualité d’un programme est proportionnelle à la quantité de tests tentant de le réfuter, tout comme la meilleure théorie, toutes choses égales par ailleurs, est celle qui se prête et s’est prêtée au plus de tentatives de réfutation.

Ayant moins de connaissances en philosophie qu’en informatique, il est probable que je résume mal la pensée de Popper, je vous recommande donc chaudement la lecture de l’original, comme par exemple « la connaissance objective » disponible en livre de poche.

Guillaume Rams

Guillaume Rams

Guillaume Rams

30 juin
2010

JSONp, DOM et fonctions javascript

Vous avez sans doute déjà entendu parler de jsonp.
Si ce n’est pas le cas, vous trouverez des articles en français qui vous expliquent tout ça correctement.

un article

un autre article

Vous avez donc sous la main une techno super simple pour effectuer des appels vers des webservices directement depuis votre appli web, sans avoir à repasser par votre serveur web… intéressant. Le dialogue est direct puisque je n’ai pas à :
- faire mon appel serveur
- récupérer les données distantes
- les envoyer à ma vue
- les traiter dans ma vue pour les présenter

Un objet javascript formaté en json dans le callback de mon appel, et je peux faire ce que je veux, et pourquoi pas utiliser une notation simple avec JQuery.

Ce qu’il faut conserver en tête, c’est un peu ce que masque l’appel JQuery, c’est quelques spécificités de javascript.
Nous avons pris l’habitude, avec les fonctionnalités Ajax, de manipuler le contenu de nos pages, et donc, de réaliser un listener sur le chargement du DOM.

window.addEventListener("load", bodyLoaded, false);

function bodyLoaded() {

	var meuh = "meuh inside";

}

Nous faisons ce genre de manipulation, sinon, un appel à un élément de la page ne fonctionnera pas. Nous allons donc définir toutes sortes de fonctions internes dans ce bodyLoaded par exemple. Mais dans l’exemple du jsonp, nous faisons appel à un script externe, et le résultat de notre appel, c’est la création d’un élément de script dans la page. Ce script doit ensuite sans doute utiliser quelque fonction définie préalablement, fonction qui elle-même doit manipuler / modifier le contenu de la page, fonction qui donc logiquement aurait été déclarée au sein de bodyLoaded.

Imaginons une version « bouchon » de notre appel jsonp (appel lui même encapsulé dans bodyLoaded et déclenché au clic sur un lien par exemple) :

function clickJs(event) {
	event.preventDefault();
	var script = document.createElement("script");
	script.type = "text/javascript";
	script.text  = 'getmeuh(meuh);';
	document.getElementsByTagName('head')[0].appendChild(script);
}

la ligne script.text remplace l’appel réel du jsonp, ce n’est pas le sujet ici.
La fonction appelée, getmeuh() :

function bodyLoaded() {
	function getmeuh() {
		var content = document.getElementById("content");
		alert(content.innerHTML);
	}
}

Notre appel jsonp veut utiliser cette fonction, mais il ne la verra pas !
Pourquoi, l’explication est simple, elle n’est pas visible ;). Voici un article de mozilla qui explique les fonctions imbriquées.

Nous devons donc sortir cette fonction du fameux bodyLoaded pour que l’appel jsonp puisse l’utiliser.

Alors bien sûr, on peut utiliser un joli framework pour masquer tout ça, mais autant savoir à quoi s’en tenir pour éviter les mélanges ! On pourra regrouper les codes par type d’utilisation pour ne pas avoir de surprise.

Alain

Alain Boudard

aboudard

9 juin
2010

Eclipse totale d’iPad

ipad

Alain Boudard

aboudard

23 mar
2010

Créer une base sqlite dans android

Alors bon, j’en vois qui trépignent au fond du blog, sur l’article précédent qui utilise un ContentProvider.

Voici donc une petite procédure simple pour créer une base de données dans votre application google android et ce de façon, disons … propre.

L’intérêt de stocker des machins dans une base de données android, c’est en général de partager les données avec d’autres éventuelles applications, sinon, autant utiliser des objets non persistants … enfin on voit l’idée.
Pour créer ma base, je n’ai besoin que d’une classe en plus de mon Activity, un ContentProvider.

Voilà ma classe (ho pas de mérite, avec Eclipse, ça se monte tout seul !) :

public class MyProvider2 extends ContentProvider {
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public boolean onCreate() {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}
}

Lire la suite du bllet »

Alain Boudard

aboudard

23 mar
2010

Android SimpleCursorAdapter sélection de données

Dans notre désormais préféré OS mobile, nous voudrions sélectionner des données sur un écran, à partir d’une source de données à nous. Par exemple.

Nous avons déjà construit un ContentProvider (enfin à priori).
Nous allons lier le contenu de ce ContentProvider avec un élément de présentation, en l’occurence, un Spinner.
Tout ça n’est pas très complexe, mais il y a quelques subtilités.

L’avantage de cette petite présentation est l’utilisation de données entre applications, l’utilisation des ressources et la manipulation de l’interface.

Le ContentProvider

Tout d’abord, nous avons une application qui fournit un contenu sous forme d’un ContentProvider. C’est une classe qui hérite de ContentProvider et qui définit une URI pour y accéder.
Nous passons sur les étapes de création de cette classe, voici l’URI qui donne accès aux données :

content://com.oxiane.provider.Livres/livres

Les champs de notre modèle sont les suivants (ce code fait partie de la classe LivreProvider par exemple ici) :

public static final String _ID = "_id";
public static final String TITLE = "title";
public static final String BODY = "body";

Lire la suite du bllet »

Alain Boudard

aboudard