Maison > interface Web > js tutoriel > Changer le paradigme : de la refactorisation prématurée et de la fausse « réutilisabilité » à l'adaptabilité, l'extensibilité et la fiabilité

Changer le paradigme : de la refactorisation prématurée et de la fausse « réutilisabilité » à l'adaptabilité, l'extensibilité et la fiabilité

DDD
Libérer: 2024-12-10 20:38:10
original
476 Les gens l'ont consulté

Changing the Paradigm: From Premature Refactoring and Fake

Dans le monde du logiciel, il existe une obsession omniprésente pour le refactoring prématuré et la recherche de fausse réutilisabilité. Les développeurs, en particulier ceux qui débutent, apprennent souvent que la « réutilisabilité » est le Saint Graal. Mais la recherche de la réutilisabilité à tout prix aboutit souvent à des solutions sur-conçues, trop génériques, trop rigides et trop éloignées des besoins spécifiques du projet en cours. En fait, cela peut conduire à ce que nous appelons souvent l'« l'enfer de l'abstraction » : un scénario dans lequel rien ne fonctionne vraiment à moins que vous ne compreniez parfaitement comment et pourquoi chaque partie du système a été abstraite pour s'adapter à une interface générique.

Nous suggérons un changement de paradigme : Au lieu d'être obsédés par la réutilisabilité, concentrons-nous sur l'adaptabilité, l'extensibilité et la substitution.

Dans ce contexte, nous cessons d'essayer de prédire les besoins futurs de notre base de code (comme une voyante de bonne aventure prédisant l'avenir) et nous nous concentrons plutôt sur la création d'une base solide et flexible pour aujourd'hui qui a encore de la place pour se développer et évoluer à mesure que l'avenir se déroule.


Le dilemme de la refactorisation prématurée : la fausse réutilisabilité

Le problème avec le refactoring prématuré est qu'il vient de la conviction que tout ce que vous écrivez doit être réutilisable. Cela peut sembler un objectif noble. Cependant, la réutilisabilité conduit souvent à une complexité inutile et à des abstractions inutiles. Prenez, par exemple, l'idée de créer un adaptateur API universel qui fonctionne pour tous vos modèles. L'idéal est que cet adaptateur puisse gérer n'importe quel point de terminaison d'API, n'importe quel format de données et n'importe quelle condition de réseau. Mais en réalité, cela signifie que vous construisez un cadre pour un avenir incertain, sans résoudre efficacement les problèmes d’aujourd’hui.

Exemple :

Prenons nos précédentes classes BaseAdapter et APIAdapter :

export class BaseAdapter {
    constructor(modelClass) {
        this.modelClass = modelClass;
    }

    async get(id) {
        throw new Error("Method 'get' must be implemented.");
    }

    async *all() {
        throw new Error("Method 'all' must be implemented.");
    }

    async query(params = {}) {
        throw new Error("Method 'query' must be implemented.");
    }

    async create(payload) {
        throw new Error("Method 'create' must be implemented.");
    }

    async update(payload) {
        throw new Error("Method 'update' must be implemented.");
    }

    async delete(id) {
        throw new Error("Method 'delete' must be implemented.");
    }
}
Copier après la connexion
Copier après la connexion

Dans le code ci-dessus, le BaseAdapter définit toutes les méthodes possibles, nous laissant les implémenter dans des sous-classes spécifiques (comme APIAdapter, LocalStorageAdapter, etc.). Il s'agit d'un modèle pour divers adaptateurs. Cela semble bien en théorie, non ? Un jour, si nous devons nous connecter à un nouveau service ou intégrer une nouvelle solution de stockage, nous pourrons simplement créer une autre sous-classe.

Mais soyons réalistes : Est-il vraiment réutilisable ? Ou va-t-il simplement devenir une grosse boule de complexité, rendant votre système plus difficile à maintenir, à comprendre et à étendre ? Construisez-vous vraiment quelque chose qui peut être réutilisé dans le monde réel, ou êtes-vous simplement en train de deviner l'avenir ?


Le changement : de la réutilisabilité à l'adaptabilité, à l'extensibilité et à la substitution

Au lieu de rechercher une réutilisabilité prématurée, nous proposons de nous concentrer sur l'adaptabilité et l'extensibilité. Qu'est-ce que ça veut dire ?

  1. Adaptabilité : créez une base qui peut changer ou s'étendre facilement sans réécrire de grandes portions de code.
  2. Extensibilité : laissez de la place à de nouvelles fonctionnalités sans avoir à refactoriser l'intégralité de votre architecture.
  3. Remplacement : permettez à votre code d'être facilement étendu ou remplacé par d'autres (ou par vous-même à l'avenir) sans risquer de tout casser.

Il ne s’agit pas de créer le code parfaitement réutilisable qui fonctionne pour tous les cas extrêmes aujourd’hui. Au lieu de cela, nous nous concentrons sur la construction d'une base solide sur laquelle vous pouvez construire, ajouter et modifier au fil du temps. La clé est la flexibilité, pas une optimisation prématurée.


Le vieux paradigme de « l’interface » : prédire l’avenir

Dans l'ancien temps de Java (et de nombreux autres langages à typage statique), l'accent était souvent mis sur la création d'interfaces et sur la nécessité de rendre votre code « évolutif ». L’idée était d’anticiper chaque scénario à l’avance et de concevoir en fonction de celui-ci.

Cependant, cette approche peut souvent aboutir à une sur-ingénierie : concevoir pour des choses qui pourraient ne jamais se produire ou construire des cadres abstraits autour de problèmes qui n'ont pas encore fait surface. Vous écrivez effectivement du code censé être « universel » sans comprendre les besoins concrets du système sur lequel vous travaillez.

En Java, les interfaces étaient utilisées pour définir les contrats. Mais et si nous changeions cette façon de penser de « définir des contrats » à simplement fixer des attentes pour le présent ? Une promesse claire et fiable pour le contexte immédiat, sans supposer ce qui se passera dans le futur.


Un nouveau type de promesse : une promesse pour notre avenir

Dans notre nouvelle approche, nous ne faisons pas de promesses sur l'avenir de l'application comme une diseuse de bonne aventure mystique. Au lieu de cela, nous fixons des promesses claires et fiables pour aujourd'hui, et veillons à ce que ces promesses puissent être étendues et adaptées facilement lorsque le besoin s'en fait sentir.

Pensez-y comme ceci : nous ne prédisons pas à quoi ressemblera le monde dans 5 ans ; nous veillons à ce que le code que nous écrivons aujourd'hui puisse évoluer et s'adapter à mesure que le monde change. C'est comme poser des fondations solides pour un bâtiment, en s'assurant qu'il est suffisamment solide pour résister à tous les changements qui surviennent.

La « promesse » que nous faisons est un engagement envers l’adaptabilité et l’extensibilité. Le but n'est pas de prédire l'avenir, mais de créer les outils qui permettront aux futurs développeurs (ou à vous-même) d'ajouter, de modifier ou d'étendre facilement des fonctionnalités selon vos besoins.


Exemple concret : extension et remplacement d'adaptateurs

Reprenons notre exemple avec le BaseAdapter et l'APIAdapter. Au lieu de créer des méthodes super génériques qui tentent de gérer toutes les situations, nous nous concentrerons sur la nécessité de rendre le code adaptable et facilement extensible.

Voici une réarchitecture rapide de l'APIAdapter :

export class BaseAdapter {
    constructor(modelClass) {
        this.modelClass = modelClass;
    }

    async get(id) {
        throw new Error("Method 'get' must be implemented.");
    }

    async *all() {
        throw new Error("Method 'all' must be implemented.");
    }

    async query(params = {}) {
        throw new Error("Method 'query' must be implemented.");
    }

    async create(payload) {
        throw new Error("Method 'create' must be implemented.");
    }

    async update(payload) {
        throw new Error("Method 'update' must be implemented.");
    }

    async delete(id) {
        throw new Error("Method 'delete' must be implemented.");
    }
}
Copier après la connexion
Copier après la connexion

Maintenant, au lieu de créer un tout nouveau BaseAdapter pour chaque nouveau type d'adaptateur, nous avons créé une base qui peut être facilement étendue et adaptée aux besoins futurs.

Exemple d'extension pour un nouveau point de terminaison d'API :

export class APIAdapter extends BaseAdapter {
    static baseURL;
    static headers;
    static endpoint;

    async *all(params = {}) {
        // Custom logic, but easily extensible if needed
        const url = `${this.baseURL}/${this.endpoint}`;
        const response = await API.get(url, { params, headers: this.headers });
        return response.data;
    }

    async query(params = {}) {
        // Simplified for illustration
        const url = `${this.baseURL}/${this.endpoint}/search`;
        const response = await API.get(url, { params });
        return response.data;
    }

    // Easily extendable for specific cases
    async customRequest(method, endpoint, params = {}) {
        const url = `${this.baseURL}/${endpoint}`;
        const response = await API[method](url, { params });
        return response.data;
    }
}
Copier après la connexion

Dans ce scénario, si vous devez ajouter un comportement spécifique pour un point de terminaison d'API (par exemple, une gestion personnalisée des erreurs pour les commandes), vous pouvez remplacer ou étendre l'APIAdapter pour l'adapter à votre besoins sans refactoriser l'ensemble du système.


Conclusion : la promesse faite à notre avenir

Dans ce nouveau paradigme, nous n’essayons pas de prédire tous les besoins ou problèmes futurs. Au lieu de cela, nous nous concentrons sur la construction d'une base solide et flexible qui s'adapte à mesure que les exigences changent et que de nouveaux défis surviennent. Nous n'abstrayons pas prématurément ni ne sur-concevons des solutions basées sur des problèmes hypothétiques. Au lieu de cela, nous créons des outils qui peuvent évoluer et être facilement adaptés à mesure que de nouveaux besoins apparaissent.

La clé n'est pas d'être à l'épreuve du temps comme une voyante de bonne aventure, mais de créer une fondation qui résistera de manière fiable à l'épreuve du temps, même si le monde change. C'est une promesse que vous pouvez faire à votre futur moi : le code est solide, adaptable et prêt à être étendu à mesure que de nouvelles exigences entrent en jeu.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal