Je trouve que chaque fois que je travaille avec du code GUI, le code a tendance à gonfler plus rapidement que d'autres types de code. Il semble également plus difficile à refactoriser. Alors que dans d'autres types de code, je peux refactoriser assez facilement - je trouve que je peux décomposer une classe plus grande en de plus petites fonctionnalités - avec la plupart des frameworks GUI, je suis souvent lié à un framework qui nécessite mon widget/contrôle/quelle que soit la classe implémenter beaucoup plus de choses plus directement dans le widget/contrôle/que ce soit. Parfois, cela est dû à la nécessité (a) d'hériter d'un widget/contrôle/objet de base ou (b) d'avoir besoin d'accéder à des méthodes protégées.
Je dois également généralement, par exemple, répondre à une grande variété d'entrées via des signaux/événements/quoi que ce soit du cadre pour mettre en œuvre tous les modes d'interaction avec l'utilisateur. Je pourrais avoir besoin dans un widget/contrôle d'interface graphique pour gérer une grande variété d'entrées/sorties qui pourraient inclure:
... tout en gérant les classes sous l'interface graphique représentant la logique métier.
Une interface graphique simple et simple peut voir son code croître assez rapidement, même lorsque je sépare la logique commerciale et que j'utilise MVC, je trouve que le code GUI est un grand aimant pour le changement.
Existe-t-il un moyen de gérer le code GUI de manière saine et d'éviter de le laisser devenir une fenêtre cassée? Ou est-ce qu'une masse de gestionnaires d'événements aléatoires/méthodes surchargées est vraiment le meilleur que nous pouvons faire pour le code GUI?
La chose à retenir sur le code GUI est qu'il est piloté par les événements, et le code piloté par les événements aura toujours l'apparence d'une masse de gestionnaires d'événements organisés de manière aléatoire. Là où cela devient vraiment compliqué, c'est quand vous essayez de chausse-pied du code non piloté par des événements dans la classe. Bien sûr, il a l'air de fournir un support pour les gestionnaires d'événements et vous pouvez garder vos gestionnaires d'événements agréables et petits, mais tout ce code de support supplémentaire flottant autour fait que votre source GUI semble gonflée et désordonnée.
Alors, que pouvez-vous faire à ce sujet et comment pouvez-vous faciliter la refonte? Eh bien, je changerais d'abord ma définition de la refactorisation de quelque chose que je fais occasionnellement à quelque chose que je fais continuellement pendant que je code. Pourquoi? Parce que vous voulez une refactorisation pour vous permettre de modifier plus facilement votre code, et non l'inverse. Je ne vous demande pas simplement de changer la sémantique ici, mais je vous demande plutôt de faire un peu de gymnastique mentale afin de voir votre code différemment.
Les trois techniques de refactorisation que j'utilise le plus souvent sont Renommer, Méthode d'extraction et Classe d'extraction. Si je n'ai jamais appris un seul autre refactoring, ces trois me permettraient toujours de garder mon code propre et bien structuré, et d'après le contenu de votre question, il me semble que vous vous retrouverez probablement à utiliser les mêmes trois refactorings presque constamment dans afin de garder votre code GUI mince et propre.
Vous pouvez avoir la meilleure séparation possible de l'interface graphique et de la logique métier au monde, et le code de l'interface graphique peut toujours ressembler à un code qui a explosé au milieu. Mon conseil est que cela ne fait pas de mal d'avoir une ou deux classes supplémentaires pour vous aider à gérer correctement votre interface graphique, et cela ne doit pas nécessairement être vos classes Afficher si vous appliquez le modèle MVC - bien que vous constatiez fréquemment que les classes intermédiaires sont si similaires à votre point de vue que vous ressentirez souvent le besoin de les fusionner pour plus de commodité. Mon opinion à ce sujet est que cela ne fait pas vraiment de mal d'ajouter une couche supplémentaire spécifique à l'interface graphique pour gérer toute la logique visuelle, mais vous voudrez probablement peser les avantages et les coûts de le faire.
Mon conseil est donc:
Je pense que bon nombre des problèmes que vous rencontrez peuvent être attribués à une cause simple. La plupart des développeurs ne traitent pas le code GUI comme du "vrai" code. Je n'ai aucune preuve ou statistique ici, juste mon instinct.
Peut-être qu'ils pensent que c'est ' juste une présentation ' et pas important. ' Il n'y a pas de logique métier là-bas ', disent-ils, ' pourquoi le tester à l'unité '? Ils rient quand vous mentionnez l'orientation de l'objet et l'écriture de code propre. Ils N'ESSAYENT PAS même d'améliorer les choses. Il n'y a pas de structure pour commencer, ils giflent juste du code et le laissent pourrir tandis que d'autres ajoutent leur propre touche au fil du temps. Un beau désordre, du code graffiti.
Le code GUI a ses défis uniques doit donc être traité différemment et avec respect. Il a besoin d'amour et de développeurs qui veulent pour l'écrire. Ceux qui le garderont mince et lui donneront une bonne structure et des motifs corrects.
Pour une raison quelconque, le code GUI crée un angle mort chez les développeurs concernant la séparation des préoccupations. C'est peut-être parce que tous les tutoriels regroupent tout dans une seule classe. C'est peut-être parce que la représentation physique fait que les choses semblent plus étroitement couplées qu'elles ne le sont. C'est peut-être parce que les cours se développent lentement afin que les gens ne reconnaissent pas qu'ils ont besoin de refactoring, comme la grenouille proverbiale bouillie en augmentant lentement la chaleur.
Quelle que soit la raison, la solution est de rendre vos classes beaucoup plus petites. Je le fais en me demandant continuellement s'il est possible de mettre ce que je tape dans une classe séparée. S'il est possible de mettre dans une autre classe, et je peux penser à un nom raisonnable et simple pour cette classe, alors je le fais.
Vous voudrez peut-être jeter un œil au modèle de présentation du modèle/Vue passive. Ray Ryan a donné une bonne conférence sur Google IO sur les meilleures pratiques d'architecture pour GWT.
http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html
Il est facile de résumer les idées dans d'autres cadres et langages. Le principal avantage de MVP (à mon avis) est la testabilité unitaire. Et vous obtenez seulement cela, si votre code n'est pas gonflé et pas spaghetti (à en juger par votre question, c'est ce que vous voulez). Il fonctionne en introduisant une couche logique de vue appelée le présentateur. La vue réelle est découplée de celle-ci via une interface (et peut donc être facilement moquée dans les tests unitaires). Maintenant, puisque votre couche logique de vue (le présentateur) est libérée des éléments internes du cadre graphique concret, vous pouvez l'organiser comme du code normal et vous n'êtes pas lié par exemple Swings hiérarchie d'héritage. Idéalement, vous pouvez changer d'implémentation d'interface graphique dans différents cadres tant qu'ils sont conformes à la même interface.
Les trois premiers sont vraiment difficiles à faire!
Structure signifie faire très attention à utiliser le moins de code possible et le maximum de frameworks, bibliothèques, etc.
Simplicité signifie garder les choses simples de la conception initiale à la mise en œuvre réelle. Garder la navigation simple, utiliser des plugins simples, garder la mise en page assez "simple" aidera tout ici. Ils peuvent désormais être "vendus" à des clients/utilisateurs qui peuvent rapidement voir les avantages des pages qui fonctionnent sur PC, iPad, mobile et autres appareils.
Tester signifie inclure des outils de test de navigateur (webrat et capybara me viennent à l'esprit avec mon Rails travail) qui détecte les problèmes de navigateur à l'avance quand un meilleur code peut être conçu pour traitez-les au début par opposition aux fréquents "correctifs" de code par différents développeurs car ils sont "découverts" par les utilisateurs de différents navigateurs.
Syntaxe. Il est vraiment utile d'utiliser un vérificateur de code/IDE/éditeur-plugin, etc. pour votre HTML, CSS, Javascript, etc. L'avantage des navigateurs ont obtenu en étant capable de gérer le HTML mal formé fonctionne contre vous lorsque différents navigateurs fonctionnent différemment avec lui, donc un outil qui vérifie votre format HTML est essentiel. Avoir un HTML bien formé est très utile pour avoir du HTML non bloqué car un mauvais code devrait avoir plus de visibilité .
Il y a beaucoup de bonnes réponses ici.
Une chose qui m'a aidé à simplifier le code GUI est de s'assurer que l'interface graphique a son propre modèle de données.
Pour prendre un exemple simple, si j'ai une interface graphique avec 4 champs de saisie de texte, alors j'ai une classe de données distincte qui conserve le contenu de ces 4 champs de saisie de texte. Les interfaces graphiques plus complexes nécessitent plus de classes de données.
Je conçois une interface graphique comme une vue de modèle. Le modèle GUI est contrôlé par le contrôleur d'application du modèle d'application - vue - contrôleur. La vue de l'application est le modèle GUI, plutôt que le code GUI lui-même.
La solution que j'ai trouvée est un code déclaratif. Utiliser uniquement du code procédural est une recette pour le code GUI spaghetti. Bien sûr, une "façon spéciale de peindre le widget" va probablement rester du code. Mais c'est du code isolé dans une classe. Gestionnaires d'événements, raccourcis clavier, tailles de fenêtre - tout ce qui est salissant est mieux déclaré.
Les applications telles que le traitement de texte, les éditeurs graphiques, etc. ont des interfaces complexes et leur code ne peut pas être simple. Cependant, pour les applications d'entreprise, l'interface graphique ne doit pas être aussi complexe, mais un peu comment elle l'est toujours.
Certaines des clés pour simplifier l'interface graphique sont (la plupart s'appliquent à .NET):
Efforcez-vous d'une conception plus simple chaque fois que possible. Évitez les comportements fantaisistes si ce n'est pas demandé par l'entreprise.
Utilisez un bon fournisseur de contrôles.
Ne créez pas de fonctionnalité de contrôle personnalisé dans le code client lui-même. À la place, créez des contrôles utilisateur qui étendent le contrôle d'origine de manière à ce que vous puissiez refléter vos comportements spécifiques dans les contrôles plutôt que dans le code du formulaire/de la page utilisant.
Utilisez un cadre (même un produit local) pour gérer l'internationalisation, la gestion des ressources, les styles, etc. afin de ne pas répéter ce code dans chaque interface utilisateur.
Utilisez un composant (ou un framework) pour la navigation.
Créez des dialogues standard pour les erreurs, les avertissements, la confirmation, etc.
Appliquez la conception orientée objet à votre code et pour le développement de l'interface utilisateur:
Voici une petite application non triviale pour illustrer certains de mes points. Vous pouvez trouver le code et le diagramme d'interaction vue/modèle ici: https://github.com/vanfrankie/pushpopbox
Vous voulez jeter un œil au concept de "databinding" . Il s'agit d'un moyen de connecter des éléments d'interface utilisateur à des éléments de modèle abstraits d'une manière déclarative de telle sorte que les éléments de modèle sont automatiquement synchronisés avec le contenu de l'interface utilisateur. Cette approche présente de nombreux avantages, par exemple le fait de ne pas avoir à écrire vous-même des gestionnaires d'événements pour synchroniser les données.
Il existe une prise en charge de la liaison de données pour de nombreux cadres d'interface utilisateur, par exemple . NET et Eclipse/JFace .