Bonjour, c'est @ hairgai. Cette fois, j'écrirai ma propre utilisation des avantages et des inconvénients de la classe Service.
Groupe de classes décrivant une fonction dérivée (et auto-reconnue) d'un service dans DDD (Domain Driven Design). Je vais l'omettre car il y a beaucoup de gens qui l'expliquent en détail, mais je l'utilise souvent parce que je peux écrire la logique métier proprement entre le modèle et le contrôleur. Cette fois (bien que mon utilisation puisse être erronée), j'écrirai ma propre utilisation et la partie qui semble être son mérite.
Tout d'abord, je voudrais présenter l'utilisation de base avec un exemple de code. (Je ne sais pas si c'est la bonne réponse, mais je pense que ce n'est pas grave car c'est facile à voir.) Par exemple, si vous décrivez la fonction de «suivre» sur SNS, etc. en tant que couche de service dans un fichier, cela ressemblera à ceci. ** * Je répète, mais ce n'est pas la bonne réponse. ** **
class FollowService
attr_reader :user, :target_user
attr_accessor :follow
def initialize(user, target_user)
@user = user
@target_user = target_user
end
def perform
check!
create_follow!
run_after_worker!
end
private
def check!
check_following!
check_blocking!
end
def check_following!
return true unless user.following?(target_user)
raise ArgumentError, 'User following target user'
end
def check_blocking!
return true unless user.blocking?(target_user)
raise ArgumentError, 'User blocking target user'
end
def create_follow!
self.follow = user.follows.create!(target_user: target_user)
end
def run_after_worker!
AfterFollowWorker.perform_in(0.2.seconds, follow.id)
end
end
En gros, je ne fais rien avec Gem etc. En l'implémentant en Ruby pur, nous visons l'effet "d'abaisser la barrière à la compréhension de l'implémentation". La classe de service a tendance à avoir une logique compliquée (quand il s'agit de fonctionnalités lourdes), j'essaie donc de la garder aussi simple que possible afin que tout le monde puisse la comprendre immédiatement.
Je pense que vous aimez la dénomination, mais comme c'est une classe qui symbolise la fonction, elle est unifiée avec [verb]([objectif]) Service
.
Avoir une convention de dénomination a l'avantage de faciliter la déduction des fonctions.
Je pense qu'il y a beaucoup de préférence ici (beaucoup de gens l'appellent "call"), mais fondamentalement, une seule méthode publique est utilisée, et les autres ne peuvent pas être appelées. Cela est dû au fait que la classe Service est une classe qui symbolise une seule fonction et que les fonctions qui peuvent être réalisées en l'utilisant sont limitées à une seule. Il y a pas mal de gens qui parlent de cette méthode publique unique, mais je l'ai aussi adoptée car il n'y avait aucune hésitation au moment de la conception et la vitesse de mise en œuvre a considérablement augmenté.
Ceci est également adopté car il améliore la visibilité + 1 La responsabilité de chaque méthode devient plus légère et la clause de garde devient plus facile à utiliser. Je pense que c'est là que vous avez des goûts différents.
Comme je l'ai écrit dans Follow Service ci-dessus, je pense d'abord à la réponse à l'utilisateur tant qu'elle est utilisée dans les affaires. En tant qu'approche dans un tel cas, il existe une méthode pour "effectuer uniquement le traitement nécessaire pendant une réponse", et le traitement ultérieur, etc., est stocké dans la file d'attente en tant que travail et traité par le serveur de travaux, etc. À ce moment-là, si le processus d'appel du travail est dispersé à divers endroits tels que le contrôleur et le modèle, la visibilité de l'ensemble du projet sera mauvaise.
Par conséquent, vous pouvez améliorer les perspectives générales en utilisant une convention de dénomination telle que ʻAfterHogeJob pour les travaux de post-traitement de
HogeService` et en appelant uniquement dans la classe Service.
Il va sans dire.
class FollowsController < ApplicationController
def create
target_user = user.find(params[:target_user_id])
service = FollowService.new(current_user, target_user)
service.perform
redirect_to user_path(target_user)
end
end
Il va sans dire. Apportez tout ce qui est écrit dans le modèle à la classe Service, et le modèle ne sera que l'association de données, la validation et d'autres méthodes liées à un seul modèle. En conséquence, il n'y a plus de méthodes riches en logique dans le modèle, ni de modèles gonflés et difficiles à voir.
Quand je l'écris à nouveau de cette manière, je pense que j'écris d'une manière qui met diverses responsabilités sur la classe Service. Je pense que l'on peut soutenir que la classe Service n'est pas nécessaire, mais comme une telle histoire de conception n'est qu'une des méthodes, ce serait bien si elle pouvait être utilisée de manière appropriée en fonction de notre entreprise.
Recommended Posts