/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   ft_techniques_and_strategies.c                     :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: rafade-o <rafade-o@student.42.rio>         +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2022/05/07 01:53:29 by rafade-o          #+#    #+#             */
/*   Updated: 2023/10/15 20:10:18 by rafade-o         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

Este artigo documenta um repositório criado durante projetos da 42 School 42networkcom o objetivo de testar e materializar ideias técnicas sob restrições de ambiente estabelecidas durante o curso de formação.

Elementos motivadores

Durante o curso me deparei com diversas restrições de ambiente que forçam o cadete(estudante) a ser mais criativo e praticar um domínio da computação mais apurado, economizando recursos, mantendo boa legibilidade do código, explicando com clareza o processo de desenvolvimento de acordo com práticas previamente estabelecidas.

Uma prática comum é receber os requisitos de um projeto uma lista de recursos e padrões permitidos e proibidos para o projeto e com isso levando o cadete a ser mais criativo para desenvolver a solução esperada para o projeto proposto.

Há durante a jornada do cadete no curso da 42 a possibilidade de criar suas próprias ferramentas para resolução de problemas assim como fazer reúso das que já foram criadas, desde que os requisitos propostos pelo projeto permitam e com isso surge a oportunidade de aplicar um pouco de engenharia de software a cada projeto e conhecimento da ciência da computação aplicada na solução dos desafios.

As ideias vão surgindo ao longo do percurso do cadete e com elas e o crescimento do portfólio de projetos surge a necessidade de organização, reúso, estruturação de processos de desenvolvimento e testabilidade dos projetos.

A criação do repositório

Todos os fatores e cenários mencionados acima fizeram com que eu pudesse materializar algumas das ideias e estratégias aplicadas em projetos em um repositório e poder compartilhar com outros companheiros de jornada e carreira.

“Quanto aos métodos, pode haver um milhão e mais alguns, mas os princípios são poucos. O homem que compreende os princípios pode selecionar com sucesso seus próprios métodos. O homem que tenta métodos, ignorando princípios, certamente terá problemas.” ~ Ralph Waldo Emerson

O repositório não tem como objetivo fornecer implementações finais ou padrões fechados, mas sim servir como um laboratório com exemplos didáticos de ideias técnicas aplicáveis ao dia a dia do desenvolvimento em C.

Em Resumo:

“Princípios mais que métodos”~Rafael Cunha

Espero ainda que o repositório possa se tornar um colab com outros cadetes e ser enriquecido com a visão e diversas pessoas criando suas abordagens próprias e métodos para resolução dos desafios da jornada.

Portanto, o que não é este repositório:

Este repositório não é um local de certezas, mais de livre criatividade baseada em princípios, o foco está em aproveitar cada desafio, problema ou restrição como oportunidade para aplicar princípios de engenharia de software, portanto o repositório não busca entregar uma abordagem completa e formal, não cobre todos os cenários, não substitui padrões formais, ele apenas sinaliza de que é possível aplicar o pensamento sistêmico e arquitetural ou ao menos seus princípios em projetos mais simples.

Técnicas e estratégias exploradas

Joke_Schrodinger

O nome é uma brincadeira inspirada no experimento do gato de Schrödinger que fala sobre um experimento onde trata de um elemento e o conhecimento de seu estado por superposição.

Aqui a brincadeira trata-se de ter a percepção de que o recurso está disponível de forma global na aplicação mesmo não sendo declarado com palavra chave ou em escopo global(Atenção: não há declaração global) e portanto não pode ser impedida de ser usada em restrições explícitas de recursos globais, o conceito aqui é contextual e não sintático, em outras palavras, o recurso é global? sim E não 🤡. Passa na norma? sim!

A ideia desta estratégia é resolver alguns problemas de restrição de ambiente e norma:

  • Limite de parâmetros em assinatura de funções;
  • Limite de variáveis presentes no protótipo de uma função;
  • restrição de uso de variáveis globais em grande parte dos projetos;
  • restrição de recursos disponíveis para uso (da linguagem C) no contexto de cada projeto;

Como Solução para as questões acima os princípios aplicados são inspirados nos padrões conhecidos na Engenharia de Software e programação orientação a Objetos(P.O.O.):

  • Singleton (conceito, não implementação);

    • Embora a técnica não seja um Singleton estrito, a ideia de armazenar um único estado de dados acessível de várias partes do código pode lembrar o padrão Singleton, que garante que uma única instância de uma classe seja criada e compartilhada em todo o sistema.
  • Memento (estado separado);

    • O padrão Memento é usado para capturar e externalizar o estado interno de um objeto, permitindo que ele seja restaurado posteriormente. Sua técnica não é exatamente um Memento, mas compartilha a ideia de manter e gerenciar o estado de dados de forma separada e fornecer métodos para recuperá-lo ou modificá-lo.
  • Adapter (acesso indireto);

    • O padrão Adapter, é um padrão de projeto estrutural que permite que objetos com interfaces incompatíveis possam trabalhar juntos. Ele atua como um intermediário entre duas classes que não podem se comunicar diretamente devido a diferenças em suas interfaces.
  • Logo, ao fazer uso de princípios podemos sob restrição de ambiente aplicar métodos criativos para resolução de problemas.

  • Obs.: Criei duas versões, uma “normal” e outra com uso de funções variáticas (eu disse que envolvia criatividade rs).

  • Complexidade conceitual;
  • Risco de abuso;
  • pode exigir maior controle e cuidado com o uso do recurso pois o mesmo está exposto a toda aplicação;

Quando usar?

  • Ambientes restritivos;
  • Contexto controlado;
  • Código educacional (de preferência);

Diagrama da estratégia de Schrödinger

Precisa usar uma variável global? e só é permitido ter uma (ou nenhuma)? e ela não pode ser uma struct? faça um bom uso desta técnica…

Strategy

Esta estratégia é inspirada padrões de projetos e práticas muito utilizadas com programação orientada a objetos que visam atender os princípios S.O.L.I.D. e ajudar com a criação e manutenção de aplicações de longa vida.

Aplicações de Longa vida são aplicações que permanecem rodando disponível para o usuário por um longo período, assim como pode-se considerar aplicações que evoluem a longo prazo crescendo e sendo modificadas para atender o valor esperado.

Alguns exemplos:

  • O console do sistema operacional, não atoa esta estratégia pode ser aplicada em um projeto muito famoso da 42 chamado “Minishell”;
  • Aplicações que possuem roteamento e crescimento constante de novas rotas e funcionalidades com dispatches, controllers e camada de negócios;
  • Servidores Web (Nginx, Apache, frameworks HTTP);
  • Gateways de Pagamento (Stripe, Adyen, PayPal);

O Strategy Pattern é um padrão comportamental que permite definir uma família de algoritmos, encapsulá-los e torná-los intercambiáveis. Cada algoritmo é encapsulado em um recurso/objeto separado (a estratégia), e o contexto que usa essas estratégias pode escolher qual estratégia usar em tempo de execução. Essencialmente, o Strategy Pattern permite que você altere o comportamento de um objeto sem alterar sua estrutura.

A aplicação desta estratégia visa atender algumas restrições e princípios de desenvolvimento:

  • Evitar uso de condicionais infinitas (if / else);

  • Atender o limite de linhas de código por função estabelecido pela norma de codificação da 42;

  • Manter boa legibilidade do código;

  • Evitar alterar o motor da aplicação todas as vezes que for preciso implementar uma nova funcionalidade e portanto gerar a necessidade de realizar teste geral da aplicação;

  • Gerar um contrato onde cada novo recurso deve respeitar para ser aceito e reconhecido pelo motor da aplicação;

  • Atender Alguns pilares do S.O.L.I.D. como:

    • Princípio da Responsabilidade Única: Uma classe deve ter um, e somente um, objetivo para realizar assim como em funções criadas em C podem ter apenas um objetivo a ser atendido.
    • Princípio Aberto-Fechado: Objetos ou entidades devem estar abertos para extensão, mas fechados para modificação, ou seja, quando novos comportamentos e recursos precisam ser adicionados no software, devemos estender e não alterar o código fonte original. Atender o princípio é possível mesmo que utilizando C pois é um princípio, portanto pode ser adaptado para os projetos dos cadete da 42.

Como exemplo foi implementado uma calculadora, que pode ter poucas ou muitas operações e novas operações podem ser criadas.

A ideia aqui é poder registrar operações/estratégias dinamicamente sem interferir em outras partes da aplicação, ou seja, quando cadastradas não afetam o núcleo da aplicação e seu funcionamento.

O conceito a ser demonstrado aqui está diretamente ligado a duas funções: add_operation e exec_operation.

Podem ser construídas diversas operações e será necessário apenas adicioná-las com add_operation e desta forma o motor da aplicação não precisará ser alterado com mais condicionais “else if” para seleção de uso de novas operações pois exec_operation suportará todas as que forem acrescidas, sem limites e sem alterações.

Obs.: Lembrando que o pattern apresentado acima foi utilizado de inspiração para a construção deste modelo, além disso pode-se criar de outras formas esta estratégia.

Obs².: Junte os conceitos expressos aqui com structs compostas de union para seleção de tipos de dados ou generics e terá um motor mais eficiente pois a passagem de params não será restrita a apenas inteiros(como no exemplo abordado aqui).

  • Pontos positivos:

    • Elimina cadeias de condicionais;
    • Facilita extensão;
    • Preserva o núcleo lógico da aplicação;
  • Porém:

    • Complexidade maior que if / else;
    • Uso de alocação dinâmica;
    • Busca linear (lista ligada) em implementações rudimentares;
    • Overhead conceitual para casos simples;

Quando usar?

  • Motores extensíveis;
  • Interpretadores simples (ouvi Minishell? 🫣);
  • Casos onde operações crescem com o tempo;

Diagrama da estratégia Strategy

Tenha sempre em mente:

Sistemas saudáveis crescem por adição, não por modificação.


💡 Saiba mais

A implementação de mais algumas estratégias, incluindo exemplos em C, variações de abordagens está disponível no repositório:

🔗 https://github.com/rafael-o-cunha/ft_strategies


Aprendizados gerais

  • Restrições geram criatividade;
  • Padrões podem emergir sem OOP;
  • C não impede boas decisões arquiteturais;
  • Testes e ferramentas moldam comportamento;
  • Prática aprimora o pensamento computacional;
  • Princípios mais que métodos;

Próximos passos

  • Continuar enriquecendo o repositório com mais ideias e aplicações práticas de princípios de engenharia de software;
  • Criar benchmarks entre entre estratégias;
  • Incluir exemplos aplicados em projetos reais(como projetos Open Source)
  • Incluir exemplos testáveis com uso de ferramentas online;
  • Realizar colab com cadetes para transformar o repositório em um verdadeiro Open Source Project e contribuir com a jornada de outros cadetes da 42 Global.

#42

#written_by_human