2011-02-15 1 views
4

Je suis développeur Web .NET pour une petite organisation. Nous avons quelques développeurs qualifiés ici, mais ce que nous n'avons pas, c'est quelqu'un qui a travaillé pour des grands magasins de logiciels plus organisés. Nous faisons bien, mais je me trouve à vouloir mieux structurer mon code avec peu de place pour obtenir des conseils.Utilisation pratique de l'architecture N-Tier

Il s'agit de cela. À un moment donné, quelqu'un de notre organisation a décidé que nous allions utiliser les services Web chaque fois que nous devions accéder à des données, peu importe le cas. Ainsi, notre architecture matérielle est organisée de manière à ce que nous puissions accéder à nos bases de données. Cela semble bien en théorie, mais le problème est la plupart de nos applications tournent comme ceci:

mess spaghetti de code dans le aspx.cs -> Service Web qui ne fait rien appeler un procédure stockée

Au-delà il n'y a pas beaucoup de séparation. Chaque fois que je commence à essayer de rechercher de meilleures pratiques structurelles, je finis par lire des choses comme des injections de dépendance, des propriétés sales et des usines de classe, ma tête commence à nager et je passe à autre chose de frustration.

Voici un exemple de base de mes interrogations. Alors disons que je dois faire une page pour sélectionner les employés d'une liste, les éditer, et mettre à jour la base de données. Est-il préférable que le service Web renvoie un objet Employee sur un get et accepte un objet Employee sur une mise à jour? Ou vaut-il mieux que l'objet Employee appelle le webservice pour se remplir lui-même?

En d'autres termes: Employé emp = svc.GetEmployee (42); vs Employé emp = nouvel employé (42);

Le deuxième exemple semble être une meilleure organisation pour les mises à jour (mettre à jour les propriétés pertinentes et appeler emp.Update()), mais le problème est que faire si j'ai besoin d'une liste des employés? Il serait incohérent de faire Employee emp = new Employee (id); pour un employé singulier, mais faites svc.GetAllEmployees() pour une liste.

Je sens que je suis un peu décousu, donc je vais cesser d'essayer d'expliquer et espère que quelqu'un comprend ma confusion. J'apprécie tous les conseils que tout le monde peut offrir. Merci!

Répondre

3

Comme pour tout, il y a un certain nombre d'approches différentes que vous pouvez prendre. (Nous espérons qu'il y aura un certain nombre de bonnes et différentes réponses ici, car c'est certainement une question importante.)

Une question que vous devriez probablement vous poser à propos de votre conception est "combien la logique devra être partagée entre les applications ? " Aller avec le petit exemple GetEmployee que vous avez donné, il semble que vous voulez savoir où placer les modèles dans votre domaine. Ces modèles sont-ils utilisés par plusieurs applications? La logique métier est-elle partagée entre les applications?

Si oui, alors vous voudrez peut-être vos modèles de domaine derrière le service Web. Peut-être construire un domaine riche derrière ces services avec son accès aux données et les dépendances externes (souvenez-vous que l'injection de dépendance, les meilleures décisions de conception doivent être dans le domaine derrière la couche de service car c'est le noyau de tout le système).

Ensuite, bien sûr, comment avez-vous accès à cette logique? Encore une fois, il y a beaucoup d'options. Ma conception préférée personnelle est d'avoir une sorte de système de demande/réponse qui résume la couche de service. Quelque chose d'aussi cool que NServiceBus pour un système asynchrone vraiment déconnecté, quelque chose d'aussi simple que Agatha pour seulement abstraire le service réel et de mettre la logique de demande/réponse dans le code, ou peut-être jouer autour avec ServiceStack (quelque chose que je sens à faire) ou un autre projet, etc. Enfer, vous pourriez juste rouler une vieille couche de service WCF ou même SOAP et rien de plus. C'est à vous.À ce stade, vous recherchez un système assez procédural au niveau de la couche de service. Ce n'est pas une chose terrible. Pensez à la couche de service comme un site MVC. Vous lui envoyez une requête, peuplée d'un type de viewmodel entrant, elle fait son domaine dans toute sa qualité orientée objet, et renvoie une vue sous la forme d'une représentation XML d'un viewmodel sortant. Maintenant, vous avez un motif répétitif. Vos applications côté client sont simplement de grandes vues pour votre domaine. Plus ils sont bêtes, plus ils sont interchangeables et remplaçables, mieux c'est.

Cela vous permet d'encapsuler diverses "actions métier" dans un unit of work à la limite du service. Étant donné une demande d'une application client, soit l'ensemble réussit, soit l'ensemble échoue. Enveloppez-vous dans une bonne gestion des erreurs et une erreur au niveau de l'application/logger d'exception pour vous donner tous les détails des demandes échouées. (Imaginez que chaque requête peut être sérialisée en une chaîne et incluse dans un message d'erreur.) Maintenant vous avez tout ce dont vous avez besoin pour recréer l'erreur dans une chaîne simple, plutôt que de demander aux utilisateurs "sur quoi avez-vous cliqué?" erreurs.)

Si, au contraire, le back-end ne partage pas vraiment quoi que ce soit avec des applications différentes et chaque application est entièrement sa propre entité distincte. À ce stade, vous n'avez pas vraiment besoin de partager toute cette logique derrière la couche de service, et il est tout à fait possible que ne devrait pas essayer de faire n'importe quel type de chevauchement. L'accès aux données est-il la seule chose derrière le service? Qu'en est-il des choses comme l'accès au système de fichiers ou l'accès au service Web externe? Si la seule chose derrière le service est l'accès aux données, vous pouvez conserver vos modèles et vos référentiels d'accès aux données dans vos applications clientes comme vous en avez l'habitude et simplement échanger vos implémentations de référentiel avec des implémentations qui référencent et accéder à la couche de service. (Ce serait la deuxième option dans votre exemple GetEmployee.) Des référentiels d'accès direct et d'accès aux services correctement abstraits peuvent être échangés de manière triviale selon l'endroit où l'application doit vivre.

Bien sûr, cela penche un peu vers une véritable approche persistance-ignorance, qui peut être dangereuse. Les implications de performance doivent être prises en compte. Une partie de la logique ou de l'unité de travail sur le back-end peut frapper plusieurs fois la base de données pour faire plusieurs choses. Si cela se produit sur un service, cela ajoute un surcoût de service à chaque appel de base de données. Vous voudrez donc aborder cette question au cas par cas.

Je suppose que je suis peut-être décousu à ce stade, alors pour revenir à quelque chose de concret, il faut vraiment se poser quelques questions sur votre domaine. Comment persévérance-ignorante pouvez-vous vous permettre d'être? Vos applications partagent-elles la logique du domaine métier? Avez-vous besoin d'accéder à d'autres dépendances externes n'appartenant pas à la base de données derrière le service uniquement? Il n'y a pas de conception universelle qui soit toujours la bonne réponse. Vous finirez probablement par expérimenter différentes conceptions et homogénéiser sur un design adapté à vos développeurs et à votre environnement.

+0

Merci pour votre réponse très complète! Dans de nombreux cas, nous menons de petits projets secondaires qui ne se chevauchent pas beaucoup. La plupart de notre code d'application croisée (accès à Active Directory, accès au serveur d'échange) se trouve dans les services Web et bien que nous n'utilisions aucun bus de service, nous partageons au moins les informations de cette façon. Merci encore. – Landon

Questions connexes