• [^] # Re: Show me the code

    Posté par . En réponse au journal L’homme orchestre, partie 2 : écrire du code (en Java). Évalué à 4.

    Pour les détails de l'architecture et tous les détails techniques, ça viendra. Ce n'est pas ma priorité,

    Ceci entre en contradiction avec cela:

    Mais pas forcément quand vous devez construire une grosse application. Vous devez avoir un coup d’avance sur ce que vous allez peut-être avoir besoin, et le prévoir en amont.

    L'architecture ça se résume à ca: Réfléchir ... un peu... avant de te lancer. Les mauvais choix d'aujourd'hui sont le temps perdu de demain. La fameuse dette technique que tu évoques.

    Je vais à nouveau essayer de t'illustrer en quoi il est utile d'apprendre contrairement à que tu as écrit en gros:

    Pas de temps à perdre à apprendre

    Prenons déjà le framework Play.
    Tu écris:

    Pour la partie ACLs/Utilisateurs, le code que tu montre est un code écrit juste pour que ça marche. C'est un vieux code qui sera refait totalement. Je n'utiliserais plus le moteur de Play pour accéder aux données, et donc plus besoin du Model de Play.

    Play était-il le bon choix pour ton besoin ? Il semble que non. A présent que devras tu casser pour réécrire les fonctionnalités équivalentes ?
    Déjà certains de tes contrôleurs embarquent de la logique de persistance. Play par simplicité encourage à embarquer toute ta logique de persistance en même temps que ta logique métier (le comme ici :

     public static CrudOrmEngine<UserProfile> getORMEngine(String key) throws Exception {
     UserProfile userprofile = new UserProfile();
     CrudOrmEngine<UserProfile> engine = new CrudOrmEngine<UserProfile>(userprofile);
     if (engine.exists(key)) {
     userprofile = engine.read(key);
     } else {
     userprofile = engine.create();
     userprofile.key = key;
     engine.saveInternalElement();
     }
     return engine;
     }

    N'eut t'il pas été préférable de les séparer ces 2 aspects (par exemple en utilisant des DAOs) et de les isoler dans 2 couches sans tout disséminer y compris dans les contrôleurs. Car à présent le passage vers un autre framework va t'obliger a tout réécrire ou à créer une couche d'abstraction pour rediriger tous tes appels aux méthodes CRUD de Play. Comment cela se passera t'il si finalement Cassandra ne fait plus l'affaire et que tu veuilles partir sur du Mongo ? Comment t'assureras tu que tu fonctionnes correctement alors que tu n'as aucun test ?
    Imagine que le départ tu aies conçu ton architecture avec juste des classes métiers (celles qui traiteraient de Médias, de répertoires et de métadata pas d'ACLs) de simples POJO et que tu aies séparé la persistence.
    Le travail ne serait-il pas plus simple. Au départ tu te concentres que sur ça et comme tu ne peux pas tester ton appli dans son ensemble que tu n'as pas de GUI ou de CLI, tu écris quelques tests pour valider tes "itérations" comme tu les appelles. Bienvenu dans le monde du TDD.
    De plus de ce que je vois de Play, il s'agit d'un framework basé sur l'héritage ("extends Model"). Il t'oblige à surcharger ou à utiliser ses méthodes par héritage. Tu es donc fortement couplé à lui et il me parait intrusif.
    Pour des problématiques techniques transverses tel que la persistence (ou même le logging que tu réécrit from scratch) il existe la programmation par aspect qui vient en complément et un framework comme Spring MVC me parait plus adapté.

    Toujours pas convaincu du fait que l'architecture (qui inclue la testabilité) et la conception se concoivent au fil de l'eau et pas après ?

    Prenons cette fois-ci cette classe MetadataCenter que tu m'a explicitée.

    Quand a MetadataCenter, c'est un point de départ pour instancier les moteurs d'analyse et de génération de bas débits. Le nom n'est peut-être pas le meilleur, j'avoue, mais cette classe à beaucoup changée au cours du temps.

    Lorsque je vois des switchs partout ou des bouts de code de ce genre:
    ```java
    try {
    addProvider(new ImageMagickAnalyser());

     addProvider(new FFprobeAnalyser());
     addProvider(new FFmpegInterlacingDetection());
     addProvider(new FFmpegSnapshot());
     addProvider(new FFmpegAlbumartwork());
     addProvider(new ImageMagickThumbnailer(FullDisplay.class, PreviewType.full_size_thumbnail, FullDisplay.profile_name));
     addProvider(new ImageMagickThumbnailer(Cartridge.class, PreviewType.cartridge_thumbnail, Cartridge.profile_name));
     addProvider(new ImageMagickThumbnailer(Icon.class, PreviewType.icon_thumbnail, Icon.profile_name));
     addProvider(new ImageMagickFFmpegThumbnailer(FullDisplay.class, PreviewType.full_size_thumbnail, FullDisplay.profile_name));
     addProvider(new ImageMagickFFmpegThumbnailer(Cartridge.class, PreviewType.cartridge_thumbnail, Cartridge.profile_name));
     addProvider(new ImageMagickFFmpegThumbnailer(Icon.class, PreviewType.icon_thumbnail, Icon.profile_name));
     addProvider(new FFmpegLowresRenderer(JobContextFFmpegLowresRendererLQ.class, PreviewType.video_lq_pvw, false));
     addProvider(new FFmpegLowresRenderer(JobContextFFmpegLowresRendererSD.class, PreviewType.video_sd_pvw, false));
     addProvider(new FFmpegLowresRenderer(JobContextFFmpegLowresRendererHD.class, PreviewType.video_hd_pvw, false));
     addProvider(new FFmpegLowresRenderer(JobContextFFmpegLowresRendererAudio.class, PreviewType.audio_pvw, true));
     } catch (Exception e) {
     Loggers.Metadata.error("Can't instanciate Providers", e);
     }
    }
    
    Ca m'évoque ce qu'on appelle un "code smell" et j'ai envie de sortir tout ça pour en faire quelque chose de plus souple qui évitera de modifier mon code à chaque fois que je veux rajouter un provider et faire en sorte que cette classe ne "change" pas au cours du temps comme ici:
    https://github.com/hdsdi3g/MyDMAM/commit/bb024c2f1aa8f7f994be38ea740c7bf7feae3534#diff-dbab17a2baa241511ef42fd413ac083c
    J'imagine que tout ces providers sont appellés par un comportement quelquepart, peut-être déjà regroupés dans un interface ou alors peut-être que tu es obligé de modifier ton code à plein d'endroits.
    Je soupçonne que ceci se prêterait bien à une Factory: http://www.jmdoudoux.fr/java/dej/chap-design-patterns.htm
    Revoici encore l'intérêt principal du paradigme objet. En réunissant code et données au même endroit, en usant du polymorphisme, tu n'as besoin de le changer qu'à un endroit.
    Apprendre la technique est très bien mais la théorie aussi a du bon.