7
votes

Approchant de refactoring

J'ai une application très centrée sur les données, écrite à Python / Pyqt. je planifie faire un refactoring pour vraiment séparer l'interface utilisateur du noyau, principalement parce que Il n'y a pas encore de réel tests en place et cela doit clairement changer.

Il y a déjà une certaine séparation, et je pense que j'ai fait de nombreuses choses de bonne façon, mais c'est loin d'être parfait. Deux exemples, pour vous montrer quel genre de choses me dérange:

  • Lorsque l'utilisateur clique sur le bouton droit de la souris sur la représentation d'un objet de données, le menu contextuel qui apparaît est créé par l'objet de données, bien que cet objet de données (essentiellement le La représentation orm d'une ligne de base de données) devrait clairement avoir rien à voir avec l'interface utilisateur.

  • Lorsque quelque chose est écrit dans la base de données, mais l'écriture échoue (par exemple parce que l'enregistrement de la base de données est Verrouillé par un utilisateur différent), la boîte de message classique "Réessayer / Abort" est présentée à l'utilisateur. Cette La boîte de dialogue est créée par le fournisseur de données *, bien que le fournisseur ne dispose évidemment pas de fonctionnalité d'interface utilisateur. Clairement, le fournisseur peut plutôt soulever une exception ou indiquer une défaillance, et l'interface utilisateur peut attraper cela et agir en conséquence.

    * C'est le mot que j'utilise pour l'objet qui représente essentiellement une table de base de données et des médiateurs entre ses objets de données et le moteur de base de données; Je ne sais pas si c'est ce que l'on appelle habituellement un "fournisseur"

    Je n'ai pas d'expérience avec les tests, alors je ne "ressentirai pas facilement" des problèmes de testabilité ou similaires, mais avant d'entrer dans cela, une certaine réorganisation doit être faite.

    Il n'y a pas de logique commerciale compliquée impliquée (il s'agit principalement de Cru D , oui, même sans la D), et cela serait beaucoup plus réécrangée que la réécriture, donc je ne suis pas vraiment préoccupé par la réécriture. Introduction de bugs de régression comme discuté dans Cette question .

    Mon plan est de commencer à refrivre avec l'idée que la partie UI pourrait facilement être déchirée pour être remplacé par, disons, une frontière Web ou une interface texte à la place de l'interface QT. D'autre part, QT elle-même serait toujours utilisée par le noyau, car le mécanisme de signal / emplacement est utilisé dans un certain nombre de lieux, par exemple. Les objets de données émettent un signal modifié pour indiquer, bien, vous savez quoi.

    Donc, ma question: est-ce qu'une approche réalisable pour accroître la qualification et la maintenabilité? Toute autre remarque, en particulier avec Python à l'esprit?


0 commentaires

4 Réponses :


7
votes

Si vous ne l'avez pas déjà fait, lisez «Travailler efficacement avec le code hérité» par Michael Plumes - il traite exactement ce genre de situation et offre une multitude de techniques pour y faire face.

Un point clé qu'il fait est d'essayer d'obtenir des tests en place avant de refactoriser. Comme il ne convient pas aux tests unitaires, essayez d'obtenir des tests de bout en bout en place. Je crois que QT a son propre cadre de test pour la conduite de l'interface graphique, alors ajoutez des tests qui manipulent l'interface graphique contre une base de données connue et vérifie le résultat. Lorsque vous nettoyez le code, vous pouvez remplacer ou augmenter les tests de bout en bout avec des tests d'unités.


1 commentaires

Je ne l'ai pas encore lu, mais je l'ai vu mentionné dans de nombreux endroits, alors je vais certainement y jeter un coup d'œil. Merci.



2
votes

Si vous souhaitez extraire toutes les parties d'interface graphique de votre application à partir de toutes les autres pièces afin de tester toutes vos applications, vous devez utiliser le modèle-View-Presenter: vous pouvez trouver une explication ici et ici .

Avec ce modèle, tous vos services de votre application utilisent les présentateurs alors que seul l'utilisateur peut interagir directement avec les vues (parties d'interface graphique). Les présentateurs gèrent les vues de l'application. Vous aurez une partie de l'interface graphique indépendante de votre application dans le cas où vous souhaitez modifier le cadre de l'interface graphique. La seule chose que vous devrez modifier sont les présentateurs et les vues eux-mêmes.

Pour les tests d'interface graphique que vous souhaitez, il vous suffit d'écrire Tests de l'unité pour les présentateurs. Si vous souhaitez tester GUI utilise, vous devez créer Tests d'intégration .

espère que cela aide!


2 commentaires

Oui, je suis au courant de ce modèle et c'est plus ou moins je me dirigeais. En fait, à certains prolonger c'est ce que j'ai déjà fait. Donc, je prends votre réponse comme un indice que je prends la bonne direction :-) Merci


Vous êtes bienvenu Balpha. Je pense que c'est la meilleure façon pour votre application d'être plus testable.



1
votes

J'ai fait refactoring pour un grand code hérité visant la séparation UI / backend avant. C'est amusant et enrichissant.

/ louange;)

Quel que soit le motif que l'on appelle ou fait partie de MVC, il est inestimable d'avoir une couche d'API très claire . Si possible, vous pouvez acheminer toutes les demandes d'interface utilisateur via un répartiteur qui vous offrirait une plus grande commande sur la communication logique UI <-> par exemple. Mise en œuvre de la mise en cache, authentifiant, etc.

à visualiser: xxx

de cette façon

  • Il est plus facile d'ajouter une suite de test pour tester vos API.
  • aussi il fait d'ajouter plus de manière uniforme et plus facile.
  • Documentation API: Dites si vous souhaitez documenter et exposer des API bien que certaines interfaces RPC, il est plus facile de générer une documentation API. Si quelqu'un n'accepte pas l'importance de la documentation de l'API peut toujours regarder Twitter API et son succès.
  • Vous pouvez rapidement importer une couche d'API sur la coque Python et jouer avec elle

    La conception de l'API peut arriver bien avant de commencer à coder pour la couche d'API. Selon l'application, vous voudrez peut-être utiliser des packages tels que Zinterfaces. C'est une approche générale que je prends même en écrivant de très petites applications et il n'a jamais échoué pour moi.

    regarder


3 commentaires

Maintenant c'est une idée intéressante, j'adore ça! Vous n'avez pas de sources ou de Tipps concernant le répartiteur? C'est à dire. Différentes possibilités de mise en œuvre, des mises en garde possibles, des expériences, etc.?


Dispatcher passerait tous les appels de l'API à tous les sous-systèmes tels que Cache Manager, Validator, URL Mapper ... Donc Disterner passe l'appel, le contexte, les arguments de l'API à chacun des sous-systèmes (en fonction de certaines règles) et d'invoquer enfin l'API si nécessaire. . Nous avons initialement essayé d'avoir une conception générique du répartiteur afin de permettre l'enregistrement des sous-systèmes, mais ultérieurement sur réglé pour le répartiteur qui a une connaissance de la manière de faire face aux sous-systèmes. Malheureusement, ce cadre pour les applications centrées sur l'API est une source fermée, mais un effet est quelque chose comme une pile de décorateurs pour chaque API, mais de manière implicite.


Le contexte de détermination et de passage a également joué un rôle très important.



1
votes

Un point, non mentionné jusqu'à présent et ne répondez pas vraiment à la question, mais très important: dans la mesure du possible, vous devriez mettre le test maintenant, avant de commencer à refactoriser . Le point de test principal est que pour détecter si vous cassez quelque chose.

Le refactoring est quelque chose où il est vraiment utile de voir exactement où l'effet d'une certaine opération a changé et où le même appel produit un résultat différent. C'est ce que fait tout ce test: vous voulez voir si vous cassez quelque chose, vous voulez voir tous les changements involontaires.

Ainsi, faites des tests maintenant pour toutes les pièces qui devraient toujours produire les mêmes résultats après refactoring. Les tests ne sont pas pour un code parfait qui restera les mêmes tests pour toujours, les tests sont destinés au code à modifier, le code qui doit être modifié, le code qui sera refactored. Les tests sont là pour vous assurer que votre refactoring fait vraiment ce que vous avez l'intention de faire.


1 commentaires

Vous avez raison, cela n'a pas été explicitement mentionné, merci. C'est l'un des points essentiels de «travailler efficacement avec le code hérité» (que j'ai lu entre-temps) et une approche intéressante à cet égard se trouve dans le débordement de la pile répondant à Shekhar des liens dans sa réponse.