Objetivo de quebrar programas em componentes menores
Uma das coisas sobre as quais os programadores costumam falar é o desejo de dividir os programas em componentes menores, ou funções, para torná-los mais fáceis de rastrear, ler e depurar.
Mas não é tão incomum ver funções monolíticas com muitos comentários de código para ajudar a explicar o que está acontecendo no programa.
Eu não estou criticando isso, realmente, porque eu não conheço as restrições sob as quais um programador estava trabalhando. Aquilo é:
- Qual era o orçamento que ele/ela tinha ao construir o programa?
- Quanto tempo foi dado para concluir o projeto?
- Havia muitas pessoas trabalhando no projeto?
- O programador teve tempo para escrever o código para que pudesse testá-lo, refatorá-lo ou simplesmente torná-lo mais fácil de ler?
Resumindo, há muitas razões – acredito – para que possamos ler “códigos ruins", e nem sempre tem que ser culpa do programador (essa é a coisa mais natural que temos que jogar fora quando lemos algo que não gostamos).
Isso significa, porém, que não devemos nos esforçar para refatorar ou escrever código de tal forma que o torne mais fácil de entender? Claro que não. Supondo que tenhamos tempo para fazê-lo, como poderíamos fazê-lo?
Divida os programas em componentes menores
Quando se trata de escrever sobre um tópico como esse, especialmente em uma economia tão ativa quanto o comércio eletrônico no WordPress, pode ser um desafio.
“Vamos ser específicos, Bob.”
Ou seja, posso escrever sobre isso em um nível muito detalhado usando um conjunto de plugins, analisando os dados, dissecando consultas e mostrando como fazê-lo. Ou posso escrever sobre isso em um nível um pouco mais alto, com o objetivo final de mostrar como dividir programas em componentes menores.
Como há tantas maneiras de alcançar o primeiro, estou optando pelo último. Ou seja, isso não necessariamente usará plugins específicos, são consultas diretas. No entanto, ele usará exemplos de alto nível para ajudá-lo a percorrer o que poderia ser uma série de consultas e loops e dividi-los em funções menores.
Um exemplo genérico
Por exemplo, digamos que estou trabalhando em um recurso de um plugin do WordPress cujo objetivo final é recuperar todos os vários métodos de pagamento que um usuário armazenou e que estão relacionados à sua conta.
O desafio é que essas informações estão espalhadas por várias tabelas de banco de dados (por causa de vários plugins que são usados), então há algumas consultas que devem ser executadas e depois recuperadas.
As etapas para fazer essas consultas podem ser mais ou menos assim:
- obter o ID de cliente do usuário atual,
- obter todos os números de identificação do pedido para o cliente
- determinar quais métodos de pagamento foram usados para cada pedido
- recuperar os referidos métodos de pagamento e enviar a informação ao cliente
Dependendo de como o banco de dados está configurado, dependendo do seu nível de proeza SQL e dependendo de como os vários plugins para lidar com todos os dados acima funcionam em conjunto, pode ser fácil escrever uma consulta grande para recuperar essas informações.
Mas se você já trabalhou com comércio eletrônico no WordPress e vários plugins, sabe que nem sempre é tão fácil.
Em vez disso, você está olhando para algo como:
- precisamos obter o perfil de um cliente dos metadados do usuário,
- precisamos encontrar todos os pedidos que o usuário fez, e isso geralmente pode ser associado à postagem ou à tabela de metadados da postagem,
- os métodos de pagamento muito provavelmente podem ser armazenados em sua tabela associada ao usuário por meio de algum tipo de token,
- o token acima fica em uma tabela e está relacionado a uma determinada informação em outra tabela da qual você deve deduzir observando os dados que existem em todo o banco de dados.
Em última análise, você precisa criar um conjunto de consultas apenas entendendo primeiro como consultar os dados que está procurando. Isso é desafiador o suficiente como é. Mas quando você fizer isso, digamos que você esteja escrevendo suas consultas sequencialmente e, em seguida, usando os resultados de cada uma para obter a saída desejada.
Isso pode resultar em algo assim :
<?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);
Mas não precisa ser assim.
Primeiro, todas essas são consultas independentes com conjuntos de resultados independentes, embora tenham que ser usadas em conjunto. Isso significa que podemos separá-los e avaliar os resultados de cada um antes de avançar com a próxima etapa.
Além disso, nos permite escrever funções menores e mais coesas. Mesmo que eles dependam um do outro, podemos configurar cada função para aceitar um argumento (ou conjunto de argumentos do qual podemos recuperar todas as informações.
Talvez o resultado final seja algo assim :
<?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;
}
Claro, não posso mostrar nenhum SQL real – bem, pelo menos não em todos os lugares – porque não conheço a configuração geral nem sei exatamente com quais plugins ou esquemas você está trabalhando.
Mas esse nunca foi o objetivo deste post.
Em vez disso, o ponto final que estou tentando transmitir é o seguinte: embora possamos estar trabalhando sob restrições altamente limitadas, ainda podemos dividir os programas em componentes menores que nos ajudam a descrever o que está acontecendo, entender como é feito e, em seguida, enviar dados para frente e para trás entre várias funções e de e para o usuário.