Je suis un ingénieur électrique et je ne sais pas ce que je fais. Veuillez enregistrer les futurs mainteneurs de mon code.
Récemment, j'ai travaillé sur un certain nombre de petits programmes (en C #) dont la fonctionnalité est logiquement "procédurale". Par exemple, l'un d'entre eux est un programme qui collecte des informations à partir de différentes bases de données, utilise ces informations pour générer une sorte de page de synthèse, l'imprime, puis les sorties.
La logique requise pour tout cela est d'environ 2000 lignes. Je ne veux certainement pas tracer tout cela dans un seul main()
, puis "nettoyer-le" avec #region
s comme certains développeurs précédents ont fait (frissonnant).
Voici certaines choses que j'ai déjà essayées sans beaucoup de satisfaction:
Faire des utilitaires statiques pour chaque bit grossière de fonctionnalité, par ex. Base de donnéesInfogetter, SommairePageGenerator et une imprimante. Faire ressembler la fonction principale:
int main()
{
var thisThing = DatabaseInfoGetter.GetThis();
var thatThing = DatabaseInfoGetter.GetThat();
var summary = SummaryPageGenerator.GeneratePage(thisThing, thatThing);
PrintUtility.Print(summary);
}
Pour un programme, je suis même allé avec des interfaces
int main()
{
/* pardon the psuedocode */
List<Function> toDoList = new List<Function>();
toDoList.Add(new DatabaseInfoGetter(serverUrl));
toDoList.Add(new SummaryPageGenerator());
toDoList.Add(new PrintUtility());
foreach (Function f in toDoList)
f.Do();
}
Aucun de cela ne se sent bien. Comme le code devient plus long, ces deux approches commencent à devenir laids.
Quel est un bon moyen de structurer des choses comme ça?
Puisque vous n'êtes pas un programmeur professionnel, je recommanderais de rester à la simplicité. Il sera beaucoup plus facile pour le programmeur de prendre votre code de procédure modularisé et de le faire OO plus tard que ce sera pour eux de fixer un programme mal écrit OO. Si vous n'êtes pas expérimenté, il est possible de créer des programmes OO pouvant se transformer en un désordre impie qui ne vous aidera ni qui ne vous aidera ni qui vient après vous.
Je pense que votre premier instinct, la "cette chose - cette chose" dans le premier exemple est la bonne voie. C'est clair et évident ce que vous voulez faire. Ne vous inquiétez pas trop sur l'efficacité du code, la clarté est beaucoup plus importante.
Si un segment de code est trop long, rompez-le en morceaux de taille, chacun ayant sa propre fonction. Si c'est trop court, envisagez d'utiliser moins de modules et de mettre plus en ligne.
---- PostScript: OO pièges de conception
Travailler avec succès avec OO La programmation peut être délicate. Il y a même certaines personnes qui considèrent tout le modèle imparfait. Il y a un très bon livre que j'ai utilisé lors de la première connaissance OO _ Programmation appelée pensant à Java (maintenant dans sa 4ème édition). Le même auteur a un livre correspondant pour C++. Il y a en fait une autre question sur les programmeurs traitant pièges communs dans la programmation orientée objet .
Certains pièges sont sophistiqués, mais il existe de nombreuses façons de créer des problèmes de manière très fondamentale. Par exemple, il y a quelques années, il y a quelques années, il y avait un stagiaire chez mon entreprise qui a écrit la première version de certains logiciels que j'ai hérité et il a fait des interfaces pour tout ce qui pourrait Un jour avoir plusieurs implémentations. Bien sûr, dans 98% des cas, il n'y avait qu'une seule implémentation de votre part, le code a donc été chargé avec des interfaces inutilisées qui ont fait du débogage très gênant car vous ne pouvez pas reculer à travers un appel d'interface, vous devez donc avoir à faire une La recherche de texte de la mise en œuvre (bien que maintenant j'utilise Intellij a été une fonctionnalité "Afficher toutes les implémentations", mais de retour dans la journée je n'avais pas cela). La règle ici est la même que pour la programmation procédurale: toujours du disque dur une chose. Seulement lorsque vous avez deux choses ou plus, créez une abstraction.
Un type similaire de gaffe de conception peut être trouvé dans l'API Java _ Swing. Ils utilisent un modèle de publication-abonnement pour le système de menu Swing. Cela fait de la création et du débogage des menus dans un cauchemar complet. L'ironie est que c'est complètement inutile. Il n'y a pratiquement jamais une situation dans laquelle plusieurs fonctions n'auraient besoin de "souscrire" à un menu clic. En outre, la publication-Subscribe était un ratif complet, car un système de menu est normalement toujours utilisé. Ce n'est pas que des fonctions s'abonnent et ne se désabonnent ensuite au hasard. Le fait que les développeurs "professionnels" au soleil ont fait une gaffe comme celle-ci montrent simplement à quel point il est facile de faire des bis à vis monumentales dans OO.
Je suis un développeur très expert avec des décennies d'expérience dans OO _ programmation, mais même je serais le premier à admettre qu'il y a des tonnes que je ne sais pas et même maintenant je suis très prudent de l'utilisation de beaucoup de OO . J'écoutais de longues conférences d'un collègue qui était un OO zélote sur la façon de faire des conceptions particulières. Il savait vraiment ce qu'il faisait, mais dans toute l'honnêteté, j'ai eu du mal à comprendre ses programmes car ils avaient des modèles de conception aussi sophistiqués.
Je réponds 4 ans de retard mais quand vous essayez de faire les choses procédurales dans un OO Langue, alors vous travaillez sur un anticitatoire. Ce n'est pas quelque chose que vous devriez faire! J'ai trouvé un blog Cela aborde cet antidiatre et montre une solution pour cela, mais cela nécessite beaucoup de refactorisation et un changement de mentalité. Voir code de procédure dans le code orienté objet Pour plus de détails.
Comme vous avez mentionné "cela" et "ça", vous suggérez essentiellement que vous avez deux classes différentes. Une ce cours (mauvais nom!) Et une classe. Et vous pourriez par exemple traduis cela:
var summary = SummaryPageGenerator.GeneratePage(thisThing, thatThing);
dans ceci:
var summary = SummaryPageGenerator.GeneratePage(new This(DatabaseInfoGetter), new That(DatabaseInfoGetter));
Maintenant, il serait intéressant de voir ces 2 000+ lignes de code de procédure et de déterminer la manière dont diverses parties pourraient être regroupées dans des classes distinctes et déplacer diverses procédures dans ces classes.
[.____] Chaque classe doit être simple et axée sur juste faire une chose. Et il me semble que certaines parties du code traitent déjà des superclasses, qui sont réellement trop grossières pour être utiles. La base de donnéesInfogetter, par exemple, semble être confuse. Qu'est-ce qu'il devient de toute façon? Cela semble trop générique. Pourtant, SommairePageGenerator est terriblement spécifique! Et la printtilité est à nouveau générique.
Donc, pour commencer, vous devez éviter les noms génériques de vos classes et commencer à utiliser des noms plus spécifiques. La classe de printibilité, par exemple, serait plus une classe d'impression avec une classe d'en-tête, une classe de pied de page, une classe de textblock, une classe d'image et éventuellement un moyen d'indiquer comment ils couleraient dans l'imprimé lui-même. Tout cela pourrait être dans le Imprimutilité Espace de noms , cependant.
[.____] Pour la base de données, histoire similaire. Même si vous utilisez le framework d'entité pour l'accès à la base de données, vous devez le faire limiter aux choses que vous utilisez et l'avoir divisé en groupes logiques.
[.____] Mais je me demande si vous avez toujours affaire à ce problème après 4 ans. Si tel est le cas, c'est une mentalité qui doit être éloignée du "concept de procédure" et dans le "concept orienté objet". Qui est difficile si vous n'avez pas l'expérience ...