Viser à diviser les programmes en composants plus petits
L’une des choses dont les programmeurs parlent souvent est le désir de diviser les programmes en composants ou fonctions plus petits, de sorte qu’ils soient plus faciles à tracer, plus faciles à lire et plus faciles à déboguer.
Mais il n’est pas si rare de voir des fonctions monolithiques avec beaucoup de commentaires de code pour aider à expliquer ce qui se passe dans le programme.
Je ne frappe pas là-dessus, vraiment, parce que je ne connais pas les contraintes sous lesquelles un programmeur travaillait. C’est-à-dire:
- De quel budget disposait-il lors de la création du programme ?
- Combien de temps a été accordé pour réaliser le projet ?
- Y avait-il beaucoup de personnes travaillant sur le projet ?
- Le programmeur a-t-il eu le temps d’écrire le code afin de pouvoir le tester unitairement, le refactoriser ou simplement le rendre plus facile à lire ?
En bref, il y a beaucoup de raisons – je crois – pour lesquelles nous pouvons lire du "mauvais code", et cela ne doit pas toujours être la faute du programmeur (c’est juste la chose la plus naturelle que nous devons rejeter lorsque nous lisons quelque chose que nous n’aimons pas).
Cela signifie-t-il, cependant, que nous ne devrions pas nous efforcer de refactoriser ou d’écrire du code de manière à le rendre plus facile à comprendre? Bien sûr que non. En supposant que nous ayons le temps de le faire, comment pourrions-nous le faire ?
Diviser les programmes en composants plus petits
Lorsqu’il s’agit d’écrire sur un sujet comme celui-ci, en particulier dans une économie aussi active que le commerce électronique dans WordPress, cela peut être un défi.
"Soyons précis, Bob."
Autrement dit, je peux écrire à ce sujet à un niveau très détaillé en utilisant une suite de plugins, en regardant les données, en disséquant les requêtes et en montrant comment le faire. Ou je peux l’écrire à un niveau légèrement supérieur avec le but ultime étant de montrer comment diviser les programmes en composants plus petits.
Parce qu’il y a tellement de façons de réaliser le premier, j’opte pour le second. Autrement dit, cela n’utilisera pas nécessairement des plugins spécifiques sont des requêtes directes. Cependant, il utilisera des exemples de haut niveau pour vous aider à parcourir ce qui pourrait être une série de requêtes et de boucles et à les diviser en fonctions plus petites.
Un exemple générique
Par exemple, disons que je travaille sur une fonctionnalité d’un plugin WordPress dont le but ultime est de récupérer toutes les différentes méthodes de paiement qu’un utilisateur a stockées et qui sont liées à son compte.
Le défi est que ces informations sont dispersées sur plusieurs tables de base de données (en raison des différents plugins utilisés), il y a donc des requêtes qui doivent être exécutées puis récupérées.
Les étapes pour faire de telles requêtes pourraient ressembler à ceci :
- obtenir l’identifiant client de l’utilisateur actuel,
- obtenir tous les numéros d’identification de commande pour le client
- déterminer quels modes de paiement ont été utilisés pour chaque commande
- récupérer lesdits moyens de paiement puis transmettre les informations faites au client
Selon la façon dont la base de données est configurée, selon votre niveau de prouesses SQL et selon la façon dont les différents plugins pour gérer toutes les données ci-dessus fonctionnent en tandem, il peut être facile d’écrire une grande requête pour récupérer ces informations.
Mais si vous avez travaillé avec le commerce électronique dans WordPress et divers plugins, vous savez que ce n’est pas toujours aussi simple.
Au lieu de cela, vous regardez quelque chose comme :
- nous devons obtenir le profil d’un client à partir des métadonnées de l’utilisateur,
- nous devons trouver toutes les commandes que l’utilisateur a passées, et cela peut souvent être associé à la publication ou à la table de métadonnées de la publication,
- les méthodes de paiement peuvent très probablement être stockées dans leur table associée à l’utilisateur via un type de jeton,
- le jeton ci-dessus se trouve dans une table et est lié à une information donnée dans une autre table à partir de laquelle vous devez ensuite déduire en regardant les données qui existent dans la base de données.
En fin de compte, vous devez créer un ensemble de requêtes uniquement en comprenant d’abord comment interroger les données que vous recherchez. C’est assez difficile comme ça. Mais lorsque vous arrivez à faire cela, disons que vous écrivez vos requêtes de manière séquentielle, puis que vous utilisez les résultats de chacune pour obtenir le résultat souhaité.
Cela peut donner quelque chose comme ça :
<?php
// First, read the user ID and meta value to get authorization information
global $wpdb;
$results = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
user_id, meta_value
FROM $wpdb->usermeta
WHERE meta_key LIKE %s
AND user_id = %d
",
'%customer_profile_id%',
filter_input(INPUT_GET, 'customer_id')
),
ARRAY_A
);
$result = isset($results[0])? array_column($results[0], 'meta_value'): [];
if (empty($result)) {
return $result;
}
// Get the ID of the current customer.
$customers = $wpdb->get_results(
$wpdb->prepare(
"", // Your custom query goes here.
filter_input(INPUT_GET, 'customer_id')
),
ARRAY_A
);
$customer = isset($customers[0])? array_column($customers[0], 'customer_id'): [];
if (empty($customer)) {
return $customer;
}
// Get all of the order IDs from the set of orders returned from the previous query.
$orderIds = $wpdb->get_results(
$wpdb->prepare(
"", // Your custom query goes here.
$customer
),
ARRAY_A
);
return $orderIds;
// Finally, get all of the payment methods for the orders based on their Ids.
$orders = [];
foreach ($orderIds as $orderId) {
$results = $wpdb->get_results(
$wpdb->prepare(
"" // The query for retrieving various payment method information based on the $orderId
),
ARRAY_A
);
if (empty($results)) {
continue;
}
$orders[$orderId] = $results;
}
// Now send the information back to the user.
wp_send_json_success($orders);
Mais il n’a pas à être de cette façon.
Premièrement, ce sont toutes des requêtes indépendantes avec des ensembles de résultats indépendants, même si elles doivent être utilisées en tandem. Cela signifie que nous pouvons les séparer et évaluer les résultats de chacun avant de passer à l’étape suivante.
De plus, cela nous permet d’écrire des fonctions plus petites et plus cohérentes. Même s’ils peuvent dépendre les uns des autres, nous pouvons configurer chaque fonction pour qu’elle accepte un argument (ou un ensemble d’arguments à partir duquel nous pouvons récupérer toutes les informations.
Peut-être que le résultat final ressemblera à ceci :
<?php
public function getPaymentMethods()
{
$authInfo = $this->getAuthorizationInformation();
$currentCustomerId = $this->getCurrentCustomerId($authInfo);
$orders = $this->getCustomerOrders($currentCustomerId);
$paymentMethods = $this->getPaymentMethodsFromOrders($orders);
wp_send_json_success($orders);
}
private function getAuthorizationInformation()
{
global $wpdb;
$authInfo = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
user_id, meta_value
FROM $wpdb->usermeta
WHERE meta_key LIKE %s
AND user_id = %d
",
'%customer_profile_id%',
filter_input(INPUT_GET, 'customer_id')
),
ARRAY_A
);
return isset($authInfo[0])? array_column($authInfo[0], 'meta_value'): [];
}
private function getCurrentCustomerIdFromAuthInfo($authInfo)
{
global $wpdb;
$customers = $wpdb->get_results(
$wpdb->prepare(
"", // Your custom query goes here.
$authInfo;
),
ARRAY_A
);
return isset($customerId[0])? array_column($customerId[0], 'meta_value'): [];
}
private function getCustomerOrders($customerId)
{
global $wpdb;
$orderIds = $wpdb->get_results(
$wpdb->prepare(
"", // Your custom query goes here.
$customerId
),
ARRAY_A
);
return empty($orderIds)? []: $orderIds;
}
private function getPaymentMethodsFromOrders($orderIds)
{
$paymentMethods = [];
foreach ($orderIds as $orderId) {
$results = $wpdb->get_results(
$wpdb->prepare(
"" // The query for retrieving various payment method information based on the $orderId
),
ARRAY_A
);
if (empty($results)) {
continue;
}
$paymentMethods[$orderId] = $results;
}
return $paymentMethods;
}
Bien sûr, je ne peux pas montrer de SQL réel – enfin, du moins pas partout – parce que je ne connais pas la configuration générale et je ne sais pas exactement avec quels plugins ou schémas vous travaillez.
Mais cela n’a jamais été le but de ce post.
Au lieu de cela, le point ultime que j’essaie de transmettre est le suivant : même si nous travaillons sous des contraintes très limitées, nous pouvons toujours diviser les programmes en composants plus petits qui nous aident à décrire ce qui se passe, à comprendre comment cela se passe, puis à envoyer des données va-et-vient entre diverses fonctions et vers et depuis l’utilisateur.