C'est encore un malentendu : avec une organisation adéquate, dans une équipe de 200 personnes, chaque développeur pourra travailler en solo sur un ou plusieurs fichiers.
Version imprimable
oui, et ton cerveau ?
Ce que veut dire ce truc "académique" (qui est quand même l'état des recherches en psychologie cognitive), c'est que, présenté avec un grand nombre d'informations, ton cerveau (pas le tien, celui de l'Homme en général ;)) ne retient vraiment que 7 informations.
Donc "trop d'information tue l'information".
C'est tout ce que je veux dire..
L'exemple donné par Zartan étant que il serait difficile d'appréhender un fichier de 20 000 lignes, je dis qu'il est tout autant, voire plus (car nettement moins structuré, les noms de fichiers étant moins explicites que les noms de méthode) difficile d'appréhender 4000 noms de fichiers pour savoir lequel ouvrir...
Mon expérience..
Voir ci-dessus.. Que ce soit l'exemple avec les classes et énormément de classes, ou que ce soit le fait d'être "bien organisé".
Prenons encore 2 exemples pour bien faire comprendre le concept :
- Déjà cité : 85 classes d'objets s'affichant. Trouver les méthodes d'affichage.
- Autre : 85 classes d'objets à charger depuis une BD. Trouver les méthodes de chargement.
Je maintiens que en général (mais cela dépend évidemment du découpage en module) si on a fait un module par classe cela va être un jonglage permanent pour comparer les différentes méthodes. Et il faudra avoir l'ensemble des fichiers ouverts.
Si on a fait un découpage fonctionnel, on aura peut-être les mêmes 85 méthodes, mais rassemblées dans 1 (2 avec les 2 fonctionalités ci-dessus) fichier(s).
C'est tout ce que je dis...
Absolument. C'est ce que je disais dans mes posts précédents..
:D
T'es capable de me dire comme ça ce que font ces 60 000 fichiers de la JDK ?? :aie:
Et tu as 1500 pages à lire avant de comprendre, ce qui est au moins aussi long et fastidieux que d'avoir à parcourir le fichier de 20 000 lignes... :P
Le débat est un débat général. Pré-supposer une organisation du travail est une aberration dans ce cadre, et donc baser des conseils sur une telle organisation supposée n'est pas un bon conseil, c'est tout...
Dans 99% des cas de notre travail, nous n'avons aucun contrôle sur l'organisation du travail , à moins que nous ne soyons le Chef du Projet (et encore), ou que l'on travaille tout seul..
Que tu recommandes ceci pour une oganisation du travail, soit.
Mais tu ne peux pas baser un conseil à des informaticiens "lambda" en te basant sur une organisation du travail particulière.
Sauf qu'avec les outils dont nous disposons tu n'as pas besoin de savoir où se trouve l'information (dans quel fichier). N'importe quel éditeur un minimum évolué sait où trouver ce que tu cherches.
Trop de couplage => mauvais design.Citation:
Je maintiens que en général (mais cela dépend évidemment du découpage en module) si on a fait un module par classe cela va être un jonglage permanent pour comparer les différentes méthodes. Et il faudra avoir l'ensemble des fichiers ouverts.
Quel est l'intérêt de savoir ce que font ces 60000 fichiers ? Est-ce que dans un projet de plusieurs millions de lignes tu es censé savoir ce que font chacunes de ces lignes ? Bah avec les fichiers c'est pareil (pour ce qui est de retrouver l'info, voir ma remarque ci dessus).Citation:
T'es capable de me dire comme ça ce que font ces 60 000 fichiers de la JDK ?? :aie:
Si le design est correct tu n'as pas à lire 1500 pages pour comprendre une fonctionnalité.Citation:
Et tu as 1500 pages à lire avant de comprendre, ce qui est au moins aussi long et fastidieux que d'avoir à parcourir le fichier de 20 000 lignes... :P
Pour moi rien ne justifie les monstres que tu décris dans un environnement de développement actuel (et déjà il y a 20 ans on disait de ne pas mettre plus de 25 lignes, la fameuse hauteur d'un écran, par fonction, donc ce n'est pas nouveau en soi).
C'était une manière polie d'indiquer que mes propos avaient été interprétés de travers.
Comme je l'ai indiqué précédemment tous les grands projets open source dont j'ai cité la métrique ont une moyenne de 500 lignes par fichiers : Linux, apache, MySQL, etc... je n'ai rien présupposé du tout car ces projets ont des centaines de développeurs travaillant dessus, je préfère donc avoir tort avec eux.
D'autre part j'estime qu'un source de 20000 lignes est une manière de coder archaïque, qui tient plus de l'obfuscation de code qu'une méthode de codage propre.
Un code propre est un code qui peut être compris d'emblée par un informaticien qui ne connait pas le projet ou bien qui n'y a pas touché pendant six mois ou plus. On en est manifestement très loin ici.
Les recherches systématiques font perdre du temps... Beaucoup de temps.
Sans parler du fait que plus tu as de fichiers, plus tu rallonges le temps de compilation total, ce qui est là aussi une perte de temps significative. Je ne parle même pas des pages de #include (ou équivalents) consécutifs qui sont de vrais nids à dépendances inutiles et à code tentaculaire... Isoler une fonction d'un peu haut niveau peut parfois devenir un vrai casse-tête.
Même un fichier include peut être codé proprement :
et dans le code appelant :Code:
1
2
3
4
5
6
7 #ifndef MONMODULE_H #define MONMONDULE_H /* les définitions */ #endif
Quant à la recompilation totale elle n'est pas censée arriver fréquemment, et n'est donc pas une perte de temps significative puisque le temps de recompilation d'un fichier de 500 lignes est largement inférieur au temps de compilation d'un fichier de 20000 lignes. Sans oublier que pendant que le fichier de 500 lignes est compilé, on peut en éditer un autre alors que pour un fichier de 20000 lignes on se tourne les pouces en attendant que ce soit fini.Code:
1
2
3
4 #ifndef MONMODULE_H #include "monmodule.h" #endif
J'ajouterai que les EDI modernes nous aident en analysant le code et en nous permettent de cliquer directement sur une fonction pour atteindre son source. Dans un fichier contenant plus de 100 fonctions cette fonctionnalité devient quasiment inutilisable, cela n'a d'intérêt que si la liste des fonctions apparaît à l'écran sans qu'on ait besoin d'utiliser trop souvent les ascenseurs, ce qui serait une perte de temps.
Il faut s'adapter à son environnement de développement et mettre à profit les facilités qu'il nous offre.
Ah ? Tu travailles en RAMdrive ? T'as un indexeur qui tourne en permanence en bouffant 10% du temps CPU de la machine ?
Moi, mon projet actuel, c'est 4 Go (oui, GIGAOCTET) de fichiers dans la vue compilée, et plus de 500 Mo de sources répartis sur environ 15.000 fichiers... Chercher là-dedans, c'est du masochisme primaire.
Ce qui ne change absolument rien si tu as 20.000 fichiers sources (CPP) qui le référencent : il sera lu, préprocessé et compilé 20.000 fois... Et les entêtes précompilés ne sont pas toujours utilisables pleinement.
EDIT : Et devoir inclure N #include pour chaque bout de fonction un peu évolué, c'est la porte ouverte au copier/coller abusif de la liste des #include, et donc à des dépendances entre modules qui ne devraient JAMAIS arriver...
Mais le temps de compilation d'un fichier de 20.000 lignes est largement inférieur au temps de compilation de 40 fichiers de 500 lignes...
Quant à la recompilation totale, elle DOIT être prise en compte, c'est aussi ce qui détermine en combien de temps on peut livrer une version, et dans tous les cas elle doit être faite plus que régulièrement... De préférence avant chaque mise en configuration pour éviter d'avoir une vue qui ne compile plus.
Donc, tous les jours, pour chaque développeur... Yahou, quand ça prends deux heures, non ?
Certes. Sauf que construire ce genre d'index prends là aussi du temps, requiert souvent une compilation totale auparavant (tiens donc... :mrgreen:) et qu'il est hors de question de balancer un fichier binaire de plus de 200 Mo directement en configuration, surtout quand il change tous les jours.
Sans être partisan du "fichier unique", l'hyper-séparation en fichiers contenant 3 lignes de code est tout aussi débile que de travailler sur un CPP unique incluant "en dur" tous les entêtes. Mais quitte à avoir une usine à gaz, je préfère celle qui se construit vite.
C'est un faux débat. Ce sont là des choix qui peuvent se défendre en termes de coût, d'efficacité ou de rapidité mais jamais en termes de "codage propre".
Je continue quand même à penser que la division en petits fichiers nous fait gagner du temps ;)
D'ailleurs si ce n'était pas le cas tous les grands projets auraient des sources de taille monstrueuse, et en ce qui concerne ceux auxquels nous avons accès cela n'est pas avéré.
Pas mieux, les seuls arguments avancés se résument à "quand c'est crade, vaut mieux que ce soit encore plus crade"...
Faire une recherche de méthode sous eclipse dans un projet (même très important) est quasi instantané... Et même s'il faut compiler une fois, ce n'est qu'une fois (et par défaut, sous eclipse, le projet est recompilé à la moindre modif, vive la compil incrémentale)... Donc oui, j'utilise un environnement moderne, et si ce n'est pas ton cas je compatis (et pas besoin de ramDrive).
PS : pour les include rien n'empêche de les encapsuler par modules...
Voici par exemple l'arborescence du Zend Framework un "petit" projet de 2000 fichiers (44Mo zippé), sur lequel une centaine de développeurs travaillent régulièrement.
Voyez comme c'est aisé de s'y retrouver, si demain je veux écrire un gestionnaire PDO pour une base de données non référencée je saurai exactement :
- où le faire en consultant rapidement l'arborescence
- quoi faire en m'appuyant sur les sources de 200 lignes des gestionnaires déjà écrits.
De plus une erreur éventuelle dans mon code ne mettra pas en danger ce qui a déjà été écrit, à l'inverse de ce qui se passerait si tous les gestionnaires de BDD partageaient un source commun.
http://img197.imageshack.us/img197/5889/zend.jpg
Ça l'est tout autant sur Visual ou Delphi...
Sauf qu'Eclipse est monstrueusement lent, bouffe trop de ressources à mon goût et la mise en configuration de l'environnement est quasi impossible (je hais ce répertoire ".metadata"...).
Quant à la compilation incrémentale... Certes, ça marche souvent. Et ça ne change absolument rien au fait qu'une compilation totale reste nécessaire dans plusieurs cas, ce qui implique donc un vidage intégral des fichiers générés (=vue propre), et recompilation complète.
Et alors ? Cela ne change rien au fait que l'élément basique de compilation en C/C++, c'est le fichier source, pas l'entête, et qu'à chaque nouveau fichier source, les entêtes sont de nouveau totalement compilés... Ce qui est une perte de temps si tu as à chaque fois 300 entêtes lus et compilés, surtout si certains ne contiennent presque rien.
Et, je le répète, les entêtes précompilés ne sont pas toujours utilisables, et/ou provoquent des dépendances inutiles.
Question de goût... Quelques niveaux de répertoires, OK, mais trop, ça devient franchement pénible.
Inversement, quand tu corriges un bug, tu n'es jamais certain d'avoir impacté tous les sources qui devraient l'être, ce qui provoque le phénomène amusant d'avoir le bug corrigé dans un cas d'utilisation et pas dans les autres...
Sans parler que certaines fonctions de haut niveau deviennent totalement impossibles à classer : une organisation aussi éclatée marche à peu près pour un framework, ça l'est rarement pour un système... Ne serait-ce qu'à cause des modules transversaux !!!
Et c'est là que tu te trompes, et lourdement en plus... Tu n'as qu'à voir les changelogs de beaucoup de projets open-source pour en être convaincu, ceux de Firefox sont de bons exemples justement : à chaque version, t'as la correction d'un problème que 99% des gens n'ont jamais vu, et qui arrive dans un cas vicieux donné... A chaque fois, tu avais une correction similaire dans les versions précédentes, dans un autre cas plus ou moins tordu.
Si tu as des "œillères" en regardant ton code, et que tu corriges par exemple le code de suppression d'une table sous MySQL, tu n'as absolument AUCUNE raison d'aller vérifier si c'est pareil avec Oracle ou SQLite. Je dirais même mieux : tu dois toujours toucher le moins de fichiers possibles pour conserver l'avantage d'une telle découpe... Et tu peux donc laisser le même bug non corrigé dans d'autres cas d'utilisation.
Ou tu peux oublier d'aller faire la même chose dans le module MySQL crypté, ou dans le générateur de requêtes, ou n'importe où ailleurs. Et avoir donc le bug dans certains cas de figures.
Si ton arbre de dépendances référence trop de fichiers, tu n'auras JAMAIS le budget alloué pour aller tous les vérifier, ça c'est également certain.
Avec quelque chose organisé différemment, c'est à dire moins éclaté partout, avec un minimum de partage de code et dans lequel les modules sont orientés macroscopiquement, tu ne touches qu'à quelques fichiers seulement, mais tu corriges le bug dans tous les cas de figure, tu répercutes la correction sur les modules similaires et tu peux plus facilement vérifier les dépendances pour les régressions.
En plus, c'est plus facile de faire un programme modulaire à haut niveau avec un découpage macroscopique des modules. Quand ta découpe est presque au niveau de la fonction, soit t'as un plat de spaghetti indémontable, soit tu finis toujours par ajouter du code mort (ou redondant) à ton programme.
Visiblement tu fais beaucoup d'amalgames dans tes propos. A la base de l'école que nous défendons ici sur le code propre, il y a le précepte "aucune duplication de code". Et c'est vraiment la base de la base.
Multiplier les fichiers pour de bonnes raisons ne signifie absolument pas dupliquer du code.
La duplication de code c'est le Mal.
Donc, en découpage "intensif" mais SANS duplication de code, tu as donc un joli plat de spaghetti... Ou des trucs tellement séparés les uns des autres (type framework) que tu n'as forcément aucune duplication de code.
J'suis vraiment pas certain de préférer ça à un code plus "condensé", tu vois...
Dans mon exemple, je n'ai pas à impacter les sources du pilote Oracle si j'écris le pilote MySQL. Si je dois faire quelque chose dont dépendent ces deux modules, par exemple rajouter une fonctionnalité commune, ce sera probablement dans le fichier Abstract, ou bien en créant un nouveau répertoire avec les classes adéquates.
Ca ne me pose aucun problème de gérer un module transversal de cette manière, par exemple un système de log peut tout à fait être contenu dans un répertoire à part, on n'a besoin que d'un nombre limité de fonctions à interfacer.
J'ai pris ici l'exemple d'un framework, mais j'aurai pu prendre à peu près n'importe quel projet open source un peu conséquent, que ce soit GCC, MySQL, apache, ou même le noyau Linux, et j'aurai retrouvé le même type d'organisation.
Des projets importants avec des fichiers sources extrêmement grands j'en ai vu, mais ceux-ci étaient l'oeuvre d'un seul programmeur, jamais le fruit d'un travail d'équipe.
Et sur un module réellement transversal, tu fais du code tentaculaire qui référence 200 modules... Et quand tu fais l'arbre d'impact de ta modification, tu pleures.
De plus, je le redis : un framework étant composé par nature de briques élémentaires, un tel découpage semble "beau et merveilleux"... C'est nettement moins le cas avec un projet plus conséquent implémentant des fonctions de bien plus haut niveau.
Et le même genre de changelog que j'ai cité avec Firefox : corrections de bugs arrivant dans des cas "pointus", et à la prochaine version ça sera encore le cas, comme c'était le cas à la version d'avant...
A chaque fois que j'ai ce genre de bugs, pour ma part, c'est à chaque fois dû à une fonctionnalité éclatée sur plusieurs fichiers, souvent de façon pas spécialement immédiate d'ailleurs. C'est bien plus rare sur un "gros" module dont les entrées / sorties sont, finalement, très simples quand on les regarde macroscopiquement.
Faut pas non plus exagérer sur le "extrêmement grands", mais faut pas non plus tomber dans l'effet inverse.
Quand supprimer une fonction se résume à enlever un répertoire et une liaison, c'est "modulaire".
Quand ça revient à supprimer N fichiers sources dans M répertoires et patcher K autres fichiers pour enlever la référence, ce n'est plus modulaire mais "tentaculaire"...
Mon cerveau ne se mets pas en kernel panique lorsque plus de 7 images, 7 textes ou 7 noms de fichiers/répertoires se trouvent dans mon champs optique, il faut arrêter de délirer une étude scientifique reste une étude scientifique c'est tout, l'interprétation qu'on en fait est relative, tu crois à cela de manière absolu ?
Est-ce que 8 c'est trop ? Est-ce que 9 aussi c'est trop et tue l'information ?Citation:
Donc "trop d'information tue l'information".
Bref nous nous éloignons de la propreté de code et comme dis précédemment on peut trouver des fichiers avec 20000lignes de code (ce qui peut faire un sacré bouquin de chevet) lisible et propre en tout cas en théorie mais à mon avis c'est le côté pratique de faire du code propre qui pose problème.