[JAVA] [Note de lecture] Principes de conception de système utiles sur le terrain - "Petit et facile à comprendre"

(Pourquoi) Pourquoi avez-vous besoin de le rendre plus facile à comprendre?

Le coût de livraison d'un produit (*) dépend de la compréhensibilité du programme, qui se traduit par la conception.

(Comment) Comment faites-vous?

Les points sont les cinq suivants.

  1. Les bases de l'organisation du code sont les noms et les paragraphes
  2. Organisez votre code avec des méthodes courtes et de petites classes
  3. Facilitez la compréhension et la sécurité avec un objet de valeur
  4. Collectez et organisez une logique complexe avec des objets de collection
  5. Plus le nom de classe ou le nom de méthode correspond au terme métier, plus il est facile de comprendre l'intention du programme et plus il est facile et sûr de le changer.

(Quoi) Plus précisément?

1. Les bases de l'organisation du code sont les noms et les paragraphes

Un exemple déroutant.kt


var a = 2000
val b = if (c < 2014) 1.05 else 1.08
a = a * b
a = if (a < 2500) a * 0.8 else a
println("total${a}C'est un cercle.");

Exemple facile à comprendre.kt


val basePrice = 2000

val taxRate = if (year < 2014) 1.05 else 1.08
val afterTax = basePrice * taxRate

val result = if (afterTax < 2500) afterTax * 0.8 else afterTax

println("total${result}C'est un cercle.");

point --Donner un nom de variable pour que "nom représente le corps"

2. Organisez votre code avec des méthodes courtes et de petites classes

Grâce aux modifications ci-dessus, il est plus facile de supprimer la méthode. Tout d'abord, dans la même classe, c'est un exemple d'extraction de traitement vers une méthode.

Exemple facile à comprendre (republication).kt


val basePrice = 2000

val taxRate = if (year < 2014) 1.05 else 1.08
val afterTax = basePrice * taxRate

val result = if (afterTax < 2500) afterTax * 0.8 else afterTax

println("total${result}C'est un cercle.");

Exemple d'extraction d'une méthode.kt


fun main(args: Array<String>) {
    val basePrice = 2000

    val afterTax = getAfterTaxAmount(year, basePrice)

    val result = getDiscountedPrice(afterTax)

    println("total${result}C'est un cercle.");
}

fun getAfterTaxAmount(year: Int, basePrice: Int): Double {
    return basePrice * if (year < 2014) 1.05 else 1.08
}

fun getDiscountedPrice(amount: Int): Int {
    return if (amount < 2500) amount * 0.8 else amount
}

Les avantages des méthodes d'extraction sont les suivants.

  1. Être capable d'apporter des corrections en toute confiance car les changements futurs seront piégés dans la méthode.
  2. Être capable de transmettre l'intention de coder sous la forme de noms de méthodes.
  3. Il devrait être possible de réutiliser le processus.

Voici un exemple d'élimination du code en double dans différentes classes.

User.kt


class User(name: String, prefecture: String) {
    fun isInTokyo(): Boolean {
        return prefecture == "Tokyo"
    }
}

Article.kt


class User(title: String, prefecture: String) {
    fun isInTokyo(): Boolean {
        return prefecture == "Tokyo"
    }
}

Les deux objets ci-dessus ont la même valeur que «prefecture» et ont également une méthode à traiter basée sur cette valeur. Ceci est un code en double.

Dans ce cas, la stratégie de refactoring diffère entre les deux méthodes suivantes. i. Il n'y a pas de relation de référence entre les deux objets ii. Il existe une relation de référence entre deux objets

i. Il n'y a pas de relation de référence entre les deux objets

C'est une bonne idée de créer une classe appelée Préfecture et d'y apporter une logique dupliquée. De cette façon, lorsque vous ajoutez, modifiez ou supprimez une logique de décision basée sur prefecture, seule la classe Prefecture sera modifiée. En même temps qu'il est plus facile à corriger, il est moins probable que des bogues inattendus se produisent en raison d'une omission de correction.

Prefecture.kt


class Prefecture(name: String) {
    fun isInTokyo(): Boolean {
        return name == "Tokyo"
    }
}

«Utilisateur» et «Article» sont les suivants. La méthode ʻisInTokyo` est réalisée en déléguant chaque méthode. Par conséquent, il n'y a pas de changement dans le client même après la modification.

User.kt


class User(name: String, prefecture: Prefecture) {
    fun isInTokyo(): Boolean {
        return prefecture.isInTokyo()
    }
}

Article.kt


class User(title: String, prefecture: Prefecture) {
    fun isInTokyo(): Boolean {
        return prefecture.isInTokyo()
    }
}

ii. Il existe une relation de référence entre deux objets

En supposant que l'utilisateur dispose d'un article, le code d'implémentation ressemble à ceci: Assurez-vous d'appeler la méthode de l'objet que vous possédez. (Déléguer.) (La mise en œuvre de l'article reste la même)

User.kt


User(name: String, prefecture: String) {
    private val article: Article
    fun isInTokyo(): Boolean {
        return article.isInTokyo()
    }
}

3. Facilitez la compréhension et la sécurité avec un objet de valeur

À titre d'exemple extrême, vous avez probablement vu du code comme celui-ci:

Type de données de base.kt


class Item {
    val price: Int
    val quantity: Int
}

Ce qui ne va pas, c'est que dans le cas ci-dessus, il est déclaré que les valeurs admissibles pour le prix et la quantité sont comprises entre -2,1 milliards et +2,1 milliards. Les prix doivent généralement avoir une limite supérieure raisonnable. Vous devez donc définir une classe Money pour la représenter et l'avoir dans la classe Item. Ce faisant, vous pouvez déléguer la vérification des valeurs anormales, etc., qui est requise lors du traitement du prix, à la classe Money, et les perspectives pour le code dans l'élément seront plus claires.

Par exemple, supposons que vous disposiez d'une méthode pour trouver le prix d'achat total. De plus, il comporte les restrictions suivantes:

  1. Si le prix unitaire est-, lancez une erreur.
  2. Si le prix unitaire dépasse 10 000, une erreur sera émise.

Type de données de base.kt


class Item(price: Int, quantity: Int) {
    private val price: Int
    private val quantity: Int

    init {
        this.price = price
        this.quantity = quantity
    }

    fun calculateTotalAmount(): Int {
        if (price < 0 || price > 100000) throw IllegalArgumentException()

        return price * quantity
    }
}

fun main(args: Array<String>) {
        val price = 10000000
        val item: Item = Item(price, 1)
        item.calculateTotalAmount()    
}

Si c'est vrai, tout ce que vous voulez faire avec CalculateTotalAmount () devrait être une ligne, mais cela prend trois fois plus. C'est parce que nous avons dû vérifier la valeur. Ce contrôle de valeur est délégué à la classe Money.

ValueObject.kt


class Item(price: Money, quantity: Int) {
    private val price: Money
    private val quantity: Int

    init {
        this.price = price
        this.quantity = quantity
    }

    fun calculateTotalAmount(): Int {
        return price.getPrice() * quantity
    }
}

class Money(price: Int) {
    private val price: Int

    init {
        if (price < 0 || price > 100000) throw IllegalArgumentException()

        this.price = price
    }

    fun getPrice(): Int {
        return price
    }
}

Maintenant, l'élément «Item # CalculateTotalAmount» tient sur une ligne et il n'y a pas de traitement supplémentaire, donc les perspectives sont meilleures. Même si vous êtes responsable du traitement de l'objet, il est logiquement plus facile pour la classe Money de vérifier le montant.

4. Collectez et organisez une logique complexe avec des objets de collection

_ Écrivez demain! _

Impressions

Écrire à Kotlin a pris beaucoup de temps. .. .. Je me demande si cela ne peut pas être aidé au début. Quand il s'agit de nouvelles langues et de nouvelles informations, cela peut être assez fastidieux, je vais donc garder un bon équilibre.

Recommended Posts

[Note de lecture] Principes de conception de système utiles sur le terrain - "Petit et facile à comprendre"
J'ai beaucoup appris sur les «principes de conception de systèmes utiles sur le terrain», je les ai donc résumés ~ Chapitre 1 ~
À propos de "Injection de dépendances" et "Héritage" qui sont faciles à comprendre lorsqu'ils sont mémorisés ensemble
Classes et instances Java comprises dans la figure
Mémo qui passe à l'écran de connexion si vous n'êtes pas connecté avec l'appareil
Facile à comprendre la différence entre la méthode d'instance Ruby et la méthode de classe.
[Bootstrap] Comment utiliser le "système de grille" qui prend en charge la conception Web réactive
Référence Java à comprendre dans la figure
[Java] Que faire si le contenu enregistré dans la base de données et le nom de l’énumération sont différents dans l’énumération qui reflète la définition de la base de données