La dernière fois, j'ai écrit que les noms des objets sont d'une grande importance, et qu'ils doivent être sélectionnés avec soin et avec une attention aux détails. La mauvaise réputation fait peur et ne permet pas de comprendre l'essence de ce qui se passe. Mais quelle est l'essence de tout cela?
Il est difficile d'évaluer un héros sans comprendre ses «statistiques» et ses «capacités» . Ce qu'il peut et ce dont il est capable, c'est le prochain niveau de difficulté dans lequel nous devons plonger. Il ne suffit pas de refléter le sanctuaire interne de l'objet à l'aide d'un nom exact, vous devez également vous assurer qu'il s'agit toujours d'un sanctuaire , et non des écuries des getters.
À ce sujet - dans l'article.
Table des matières du cycle
- Les objets
- Actions et propriétés
- Code comme texte
Actions
Le personnage attaque, défend, esquive, tire d'un arc, utilise des sorts, agite une lame. Le nom reflète l'objet, mais l'objet lui-même est en mouvement, en réaction, en action. Sinon, nous parlerions de tableaux dans Excel.
En C #, les actions sont des méthodes et des fonctions. Et pour nous: les verbes, les atomes du mouvement verbal. Les verbes déplacent le temps, car les objets existent et interagissent. Là où il y a un changement - il doit y avoir un verbe.
Setters
De tous les changements, l'affectation est la moins mobile. Il décrit strictement et mathématiquement quelles sont les quantités et ce qu'elles sont égales, mais ne communique jamais la vie et la vigueur à un texte, comme le font les verbes.
Par exemple, il existe IPullRequest
avec la propriété Status
, qui peut être Approved
, Declined
ou Merged
. Vous pouvez écrire pullRequest.Status = Status.Declined
, mais cela revient à dire "Définir la demande de pool sur le statut annulé", est impératif. pullRequest.Decline()
est beaucoup plus pullRequest.Decline()
et, par conséquent, pullRequest.Approve()
, pullRequest.Merge()
.
Un verbe actif est préférable à un setter, mais pas tous les verbes.
Voix passive
PerformPurchase
, DoDelete
, MakeCall
.
Comme dans HeroManager
un nom important est masqué par un Manager
vide de sens, donc dans PerformMigration
- Perform
. Après tout, plus vivant - il suffit de Migrate
!
Les verbes actifs rafraîchissent le texte: pas «hit» , mais «hit» ; pas «fait un swing» , mais «agité» ; pas «pris une décision» , mais «décidé» . Donc dans le code: PerformApplication
→ Apply
; DoDelete
→ Delete
; PerformPurchase
→ Purchase
, Buy
. (Mais DealDamage
s'est calmé, bien que dans de rares cas, l' Attack
puisse être signifiée .)
En évitant la voix passive, nous développons l'histoire, déplaçons les personnages, mais nous devons également nous assurer que le film ne se déroule pas en noir et blanc.
Verbes forts
Certains mots véhiculent des nuances de sens mieux que d'autres. Si vous écrivez «il a bu un verre d'eau» , ce sera simple et clair. Mais «vidé un verre d'eau» - au sens figuré, plus fort.
Ainsi, le changement de santé du joueur peut être exprimé par player.Health = X
ou player.SetHealth
, mais plus pittoresque est player.RestoreHealth
.
Ou, par exemple, nous connaissons Stack
non pas par Add/Remove
, mais par Push/Pop
.
Les verbes forts et actifs saturent l'objet de comportement, s'ils ne sont pas trop spécifiques.
Pièces redondantes
Comme avec ManualResetEvent
, plus nous nous rapprochons des internes techniques de .NET, qui sont complexes et il serait agréable de les exprimer simplement, plus les détails et les excès de l'API sont riches.
Il arrive que vous ayez besoin de travailler sur un autre thread, mais pour ne pas vous soucier de le créer et de l'arrêter. En C #, il y a ThreadPool
pour cela. Seulement ici est un simple «faire le travail» ici - QueueUserWorkItem
! Le type d'élément de travail ( WorkItem
) et ce qu'il peut être, sinon l'utilisateur ( User
), n'est pas clair. Beaucoup plus facile serait - ThreadPool.Run
ou ThreadPool.Execute
.
Un autre exemple. Se souvenir et savoir qu'il existe une instruction atomique de comparaison et d'échange (CAS) est bien, mais le porter propre au code n'est pas la meilleure solution. Interlocked.CompareExchange(ref x, newX, oldX)
est inférieur aux Atomically.Change(ref x, from: oldX, to: newX)
(utilisant des paramètres nommés).
Le code n'est pas un doctorat en travail avec un ordinateur quantique, pas une application aux calculs mathématiques, mais le lecteur est parfois complètement indifférent à ce que les instructions de bas niveau sont appelées. L'utilisation quotidienne est importante.
Répétitions
UsersRepository.AddUser
, Benchmark.ExecuteBenchmark
, AppInitializer.Initialize
, UniversalMarshaller.Marshal
, Logger.LogError
.
Comme je l'ai dit dans la dernière partie, la répétition érode le sens, comprime l'espace.
Pas UsersRepository.AddUser
, mais UsersRepository.Add
; pas Directory.CreateDirectory
, mais Directory.Create
; pas HttpWebResponse.GetResponseStream
, mais HttpWebResponse.Stream
; pas Logger.LogError
, mais Log.Error
.
Litière fine
Check
est un mot à plusieurs facettes. CheckHasLongName
peut renvoyer un CheckHasLongName
ou CheckHasLongName
une exception si l'utilisateur a un nom trop long. Mieux vaut bool HasLongName
ou void EnsureHasShortName
. J'ai même rencontré CheckRebootCounter
, qui ... Quelque part à l'intérieur, j'ai redémarré IIS!
Enumerate
- de la même série. Il existe une méthode Directory.EnumerateDirectories(path)
dans .NET: pour une raison quelconque, il est spécifié que les dossiers seront répertoriés, bien que Directories.Of(path)
ou path.Directories()
.
Calc
- Calculate
est si souvent réduit, bien qu'il ressemble davantage à des dépôts de calcium.
Proc
est une autre abréviation de fantaisie pour Process
.
Base
, Impl
, Internal
, Raw
- mots parasites qui indiquent la complexité des objets.
Total
Une fois de plus, un lecteur attentif le remarquera, tout se résume à la simplification, à l'assimilation de la parole naturelle, et les conseils eux-mêmes se rapportent en grande partie non seulement au code, mais à l'écriture en général. En les utilisant, le développeur peaufine à la fois le code sous forme de texte et le texte lui-même, s'efforçant d'obtenir une présentation transparente et fluide, pour plus de simplicité.
Maintenant que nous avons compris le mouvement et les «effets spéciaux» , regardons comment les relations entre les objets sont décrites.
Les propriétés
Le personnage a de la santé et du mana; les articles sont dans le panier; le système solaire est composé de planètes. Les objets agissent non seulement de façon altruiste, mais ils sont également liés: hiérarchiquement (ancêtre-héritier), compositionnels (partie entière), spatiaux (élément de stockage), etc.
En C #, les propriétés et les relations sont des méthodes (commençant généralement par Get
), des getters (propriétés avec un corps get
spécifique) et des champs. Mais pour nous c'est: des ajouts de mots exprimant l'appartenance d'un objet à un autre. Par exemple, un joueur a la santé - Player.Health
, qui correspond presque exactement à la «santé du joueur» en anglais .
Ce qui est le plus confus aujourd'hui, ce sont les méthodes d'action et les méthodes de propriété.
Verbe au lieu d'un nom
GetDiscount
, CalculateDamage
, FetchResult
, ComputeFov
, CreateMap
.
Les tassements se font entendre partout: les méthodes doivent commencer par les verbes. Vous voyez rarement quelqu'un douter: est-ce vraiment le cas? Après tout, il ne peut pas y avoir de différence significative entre Player.Health
et Player.Health()
. Que les enregistrements soient syntaxiquement différents, ils signifient la même chose.
Supposons que, dans IUsersRepository
un GetUser(int id)
soit facilement attendu. Pourquoi, pour représenter l'utilisateur, penser à une sorte de reçu ( Get
)? Ce sera plus précis - User(int id)
!
Et vraiment: pas FetchResult()
, mais Result()
; pas GetResponse()
, mais Response()
; pas CalculateDamage()
, mais Damage()
.
Un exposé DDD donne un exemple de «bon» code: DiscountCalculator
avec la méthode CalculateDiscountBy(int customerId)
. Non seulement il y a une répétition symétrique sur le visage - DiscountCalculator.CalculateDiscount
, ils ont également spécifié que la remise est calculée . Et quoi d'autre, demande-t-on, à faire avec elle?
Il serait plus fort de passer de l'entité elle-même - Discount
avec la méthode static decimal Of(Customer customer, Order order)
pour appeler Discount.Of(customer, order)
- est plus simple que _discountCalculator.CalculateDiscountBy(customerId)
et correspond à une seule langue.
Parfois, en omettant le verbe, nous perdons quelque chose, comme, par exemple, dans CreateMap()
: un remplacement direct par Map()
peut ne pas être suffisant. Ensuite, la meilleure solution est NewMap()
: encore une fois, l'objet est en tête, pas l'action.
L'utilisation de verbes vides vides est caractéristique d'une culture impérative obsolète, où l'algorithme est primaire et en avance sur le concept. Vous y trouverez souvent une «lame trempée» qu'une «lame trempée» . Mais le style des livres sur James Bond ne convient pas pour décrire le paysage. Là où il n'y a pas de mouvement, il n'y a pas de place pour le verbe.
Autre
Les propriétés et les méthodes exprimant les relations entre les objets sont également des objets, par conséquent, ce qui précède à bien des égards s'applique à eux.
Par exemple, les répétitions dans les propriétés: pas Thread.CurrentThread
, mais Thread.Current
; pas Inventory.InventoryItems
, mais Inventory.Items
, etc.
Total
Les mots simples et compréhensibles ne sont pas confondus, et donc le code qui les compose n'est pas non plus confondu. En écriture, il est tout aussi important d'écrire facilement: éviter les prépositions passives, une abondance d'adverbes et d'adjectifs, les répétitions, car les actions préfèrent un verbe à un substantif. Un exemple bien connu: "Il a hoché la tête, d'accord", au lieu de "Il a hoché la tête" , il QueueUserWorkItem
, et je me souviens de QueueUserWorkItem
.
Le texte du code est également différent en ce que dans le premier cas, vous serez payé si la maison est debout, noyée dans les rayons du soleil couchant ; dans le second - si la maison est debout ; mais cela vaut la peine de se rappeler: une maison doit rester debout, et non des bâtons d'aides.
Dans les deux premiers articles de la série, je voulais montrer combien il est important de travailler non seulement sur l'algorithme, mais aussi sur le mot; comment les noms déterminent le contenu de ce qui est appelé; comment le code redondant et trop compliqué éloigne le lecteur.
Parallèlement à cela, les bons noms ne sont que des notes. Pour jouer , ils doivent être écrits et incarnés dans la musique. Je vous en dirai plus dans le prochain article final.