Écrire un code agréable, bien conçu et esthétique n'est pas aussi difficile qu'il n'y paraît. Cela demande un peu d'effort pour connaître les règles principales et les utiliser dans votre code. Et il n'est pas nécessaire de tout faire en même temps, mais au fur et à mesure que vous vous sentez à l'aise avec une chose, essayez d'en penser une autre, et ainsi de suite.
Construire un code solide et non stupide
Commençons par introduire les règles les plus élémentaires appelées SOLID. Il s'agit d'un terme décrivant un ensemble de principes de conception pour de bonnes code qui a été inventé par Robert C. Martin et comment cela se passe :
S : principe de responsabilité unique
Il stipule qu'une classe doit avoir une et une seule raison de changer. En d'autres termes, une classe ne doit avoir qu'une seule tâche à accomplir, et nous devons donc éviter d'écrire de grandes classes avec de nombreuses responsabilités. Si notre classe doit faire beaucoup de choses, chacune d'entre elles doit être déléguée dans des classes distinctes.
classe Notification
def initialize(params)
@params = params
end
def call
EmailSender.new(message).call
end
private
def message
# un peu d'implémentation
fin
fin
O : principe d'ouverture/fermeture
Il stipule que vous devez être en mesure d'étendre le comportement d'une classe sans la modifier. En d'autres termes, il doit être facile d'étendre une classe sans la modifier. Nous pouvons y parvenir, par exemple, en utilisant le modèle de stratégie ou les décorateurs.
classe Notification
def initialize(params, sender)
@params = paramètres
@sender = expéditeur
fin
def call
sender.call message
end
private
def message
# un peu d'implémentation
fin
fin
classe EmailSender
def call(message)
# un peu d'implémentation
fin
fin
classe SmsSender
def call(message)
# un peu d'implémentation
fin
fin
Grâce à cette conception, il est possible d'ajouter de nouveaux expéditeurs sans modifier le code.
L signifie principe de substitution de Liskov
Il stipule que les classes dérivées doivent être substituables à leurs classes de base. En d'autres termes, l'utilisation de classes issues d'un même ancêtre doit être facile à remplacer par un autre descendant.
class Logger {
info (message) {
console.info(this._prefixFor('info') + message)
}
error (message, err) {
console.error(this._prefixFor('error') + message)
if (err) {
console.error(err)
}
}
_prefixFor (type) {
// une certaine implémentation
}
}
class ScepticLogger extends Logger {
info (message) {
super.info(message)
console.info(this._prefixFor('info') + 'Et c'est tout ce que j'avais à dire.')
}
error (message, err) {
super.error(message, err)
console.error(this._prefixFor('error') + 'Big deal!')
}
}
Nous pouvons facilement remplacer le nom de la classe, car les deux ont exactement la même interface d'utilisation.
Je veux dire le principe de ségrégation des interfaces
Elle indique qu'il faut créer des interfaces fines et spécifiques au client. Qu'est-ce qu'une interface ? Il s'agit d'un mode d'utilisation fourni d'une partie du code. Ainsi, une violation de cette règle pourrait être par exemple une classe avec trop de méthodes ainsi qu'une méthode avec trop d'options d'argument. Un bon exemple pour visualiser ce principe est le modèle de dépôt, non seulement parce que nous plaçons souvent beaucoup de méthodes dans une seule classe, mais aussi parce que ces méthodes sont exposées au risque d'accepter trop d'arguments.
# pas le meilleur exemple cette fois-ci
classe NotificationRepository
def find_all_by_ids(ids :, info :)
notifications = Notification.where(id : ids)
info ? notifications.where(type : :info) : notifications
end
fin
# et une meilleure
classe NotificationRepository
def find_all_by_ids(ids :)
Notification.where(id : ids)
end
def find_all_by_ids_info(ids :)
find_all_by_ids(ids).where(type : :info)
end
end
D signifie principe d'inversion de la dépendance
Il stipule qu'il faut dépendre des abstractions et non des concrétions. En d'autres termes, une classe qui en utilise une autre ne doit pas dépendre des détails de son implémentation, l'important étant l'interface utilisateur.
classe Notification
def initialize(params, sender)
@params = paramètres
@sender = expéditeur
fin
def call
sender.call message
end
private
def message
# un peu d'implémentation
fin
fin
Tout ce que nous avons besoin de savoir sur l'objet sender est qu'il expose la méthode `call` qui attend le message comme argument.
Ce n'est pas le meilleur code qui soit
Il est également très important de connaître les choses qui devraient être strictement évitées lors de l'écriture du code, alors voici une autre collection avec des principes STUPIDES qui rendent le code non maintenable, difficile à tester et à réutiliser.
S signifie Singleton
Les singletons sont souvent considérés comme des anti-modèles et devraient généralement être évités. Mais le principal problème de ce modèle est qu'il s'agit d'une sorte d'excuse pour les variables/méthodes globales et qu'il peut être rapidement surutilisé par les développeurs.
T signifie accouplement étanche
Il est préservé lorsqu'un changement dans un module nécessite également des changements dans d'autres parties de l'application.
U signifie non testable
Si votre code est bon, l'écriture de tests devrait être un plaisir et non un cauchemar.
P signifie Optimisation prématurée
Le mot prématuré est la clé ici, si vous n'en avez pas besoin maintenant, c'est une perte de temps. Il est préférable de se concentrer sur un code propre et de qualité plutôt que sur des micro-optimisations - qui entraînent généralement un code plus complexe.
J'entends par là une dénomination indescriptive
C'est la chose la plus difficile dans l'écriture d'un bon code, mais rappelez-vous que c'est non seulement pour le reste de votre vie, mais aussi pour le reste de votre vie. équipe mais aussi pour vous futurs, alors traitez vous bien 🙂 Il vaut mieux écrire un nom long pour une méthode mais qui dit tout, qu'un nom court et énigmatique.
D signifie duplication
La principale raison de la duplication du code est le principe de couplage étroit. Si votre code est étroitement couplé, vous ne pouvez pas le réutiliser et du code dupliqué apparaît, alors suivez le principe DRY et ne vous répétez pas.
Ce n'est pas vraiment important pour l'instant
Je voudrais également mentionner deux choses très importantes qui sont souvent laissées de côté. Vous devriez avoir entendu parler de la première - c'est YAGNI, ce qui signifie : vous n'en aurez pas besoin. De temps en temps, j'observe ce problème en faisant une revue de code ou même en écrivant mon propre code, mais nous devrions changer notre façon de penser au sujet de l'implémentation d'une fonctionnalité. Nous devrions écrire exactement le code dont nous avons besoin à ce moment précis, ni plus ni moins. Nous devons garder à l'esprit que tout change très rapidement (en particulier les exigences des applications) et qu'il est donc inutile de penser qu'une fonctionnalité nous sera utile un jour. Ne perdez pas votre temps.
Je ne comprends pas
Et la dernière chose, qui n'est pas vraiment évidente je suppose, et qui peut être assez controversée pour certains, c'est un code descriptif. Je ne veux pas dire par là qu'il suffit d'utiliser les bons noms pour les classes, les variables ou les méthodes. C'est vraiment, vraiment bien quand l'ensemble du code est lisible dès le premier coup d'œil. Quel est le but d'un code très court alors qu'il est aussi énigmatique que possible et que personne ne sait ce qu'il fait, à l'exception de la personne qui l'a écrit ? A mon avis, il vaut mieux écrire quelques caractèresénoncés de conditionsquelque chose d'autre de plus d'un mot et puis hier, on s'assoit et on se demande : attendez, quel est le résultat, comment c'est arrivé, etc.
const params = [
{
movies : [
{ title : 'The Shawshank Redemption' },
{ title : 'Un vol au-dessus d'un nid de coucou' }
]
},
{
movies : [
{ title : 'Saving Private Ryan' },
{ title : 'Pulp Fiction' },
{ title : 'The Shawshank Redemption' },
]
}
]
// première proposition
function uniqueMovieTitlesFrom (params) {
const titles = params
.map(param => param.movies)
.reduce((prev, nex) => prev.concat(next))
.map(movie => movie.title)
return [...new Set(titles)]
}
// deuxième proposition
function uniqueMovieTitlesFrom (params) {
const titles = {}
params.forEach(param => {
param.movies.forEach(movie => titles[movie.title] = true)
})
return Object.keys(titres)
}
En résumé
Comme vous pouvez le voir, il y a beaucoup de règles à retenir, mais comme je l'ai mentionné au début, écrire un bon code est une question de temps. Si vous commencez à penser à une amélioration de vos habitudes de codage, vous verrez qu'une autre bonne règle suivra, car toutes les bonnes choses naissent d'elles-mêmes, tout comme les mauvaises.
En savoir plus :
Qu'est-ce que Ruby on Jets et comment construire une application en l'utilisant ?
Vuelendar. Un nouveau projet de Codest basé sur Vue.js
Le rapport hebdomadaire de Codest sur les meilleurs articles technologiques. Construire un logiciel pour 50 millions de sockets simultanés (10)