DevSecOps

23 ago, 2013

Princípio KISS aplicado à Gestão de Software

Publicidade

Anos atrás, ganhei da minha madrinha um livrinho, a princípio bobo pela simplicidade (acho que ela me presenteava com livros desde antes de antes de eu aprender a ler).

Trata-se do livro “Ideias Geniais”, de Surendra Verma.  Ele aborda (pelo menos tenta) princípios, teorias, leis e princípios científicos – do Teorema de Pitágoras à Teoria de Tudo, mas de uma forma muito superficial – é uma blasfêmia falar do “Principia” em uma única página. Mas pela minha fixação no assunto e carinho pela minha adorável madrinha, li o livro inteiro. E eis que deparo com “A Navalha de Ocam”, um princípio que remonta do século 14 e resumidamente diz que “Entidades não devem ser multiplicadas desnecessariamente”, que serviu de inspiração para, entre outras aplicações, o princípio KISS.

Isaac Newton - Principia
Isaac Newton – Principia

O princípio KISS – de “Keep It Simple, Stupid” – postula que a simplicidade deve ser a palavra de ordem em projetos (de engenharia civil, elétrica, mecânica ou computacional) e que complexidades devem ser evitadas.

Em desenvolvimento de software, arquitetura de sistemas, modelagem de dados, design de websites, enfim, em qualquer segmento, esse princípio deve ser lembrado – aliás, é um mantra que repito para as equipes que lidero.

São inúmeros os exemplos que podemos apresentar para ilustrar os benefícios e aplicabilidades do principio KISS, a saber:

  • No paradigma procedural, temos o uso de bibliotecas com funções e procedures pequenas e SIMPLES reutilizáveis
  • O simples uso de CSS em um website
  • Acredito que a própria orientação a objetos foi motivada pelo principio KISS

Caros colegas, simplicidade está longe de ser sinônimo de facilidade; alias é exatamente o oposto: soluções simples são EUREKAS de criatividade e genialidade.

Alguns anos atrás, num desses trabalhos como arquiteto deparei com um sistema com sérios problemas de performance e manutenção. Diversos eram os problemas, mas o que de fato me chamou atenção e, tive meu momento EUREKA, foi o seguinte: no gerenciamento de eventos em uma agenda. Uma das características é a periodicidade, podendo ser única, diária, semanal e mensal. Suponhamos que na periodicidade semanal, além de informar a quantidade de semanas de ocorrência do evento, seja necessário especificar os dias da semana de ocorrência do evento, por exemplo:

  • As aulas do curso de c# ocorrerão a partir do dia 20/08/2013, pelas próximas 4 semanas às segundas, quartas e sextas-feiras.
  • As reuniões de acompanhamento do projeto, ocorrerão a partir do dia 01/12/2014, pelos próximos 4 meses.
  • A apresentação do projeto será realizada dia 20/12/2013.

Uma modelagem de dados muito utilizada nesse tipo de cenário, (verifique o que tem aí na sua empresa), seria algo semelhante ao apresentado abaixo, ou muito próximo a isso, com uma tabela somente com os dias da semana relacionada à tabela de eventos, e foi exatamente isso que encontrei.

EVENTO_TIPO_FREQUENCIA Char
EVENTO_TOTAL_DIAS Int
EVENTO_TOTAL_SEMANAS Int
EVENTO_TOTAL_MESES Int
EVENTO_DIA_SEGUNDA Bit
EVENTO_DIA_TERCA Bit
EVENTO_DIA_QUARTA Bit
EVENTO_DIA_QUINTA Bit
EVENTO_DIA_SEXTA Bit
EVENTO_DIA_SABADO Bit
EVENTO_DIA_DOMINGO Bit

Tabela 1 – modelo parcial da tabela de eventos.

Onde o atributo TIPO_FREQUANCIA é definido em um domínio pré-estabelecido, por exemplo [1-único, 2 – diário, 3 – semanal, 4 – mensal].

Os atributos TOTAL_DIAS, TOTAL_SEMANAS, TOTAL_MESES contabilizam o período de ocorrência do evento baseado no tipo da frequência.

E finalmente os atributos DIA_XXX, que especificam os dias da semana de ocorrência do evento.

Essa modelagem é fácil e até mesmo intuitiva, mas gera uma série de problemas, tais como:

  • Temos uma quantidade razoável de atributos, em que sempre teremos desperdício de espaço em nosso repositório de dados.
  • Toda codificação terá que contemplar todos esses conjuntos de atributos [procedures com muitos parâmetros, classes com todas essas propriedades, métodos de validação e operações de CRUD com vários parâmetros].
  • Processo de alteração mais complexo – um evento inicialmente cadastrado como semanal, 4 vezes, às terças, quintas e sábados, ao ser modificado para mensal, 2 vezes, será necessário atualizar todos os atributos.

Momento EUREKA:

Redução drástica na quantidade de atributos na tabela de eventos.

EVENTO_TIPO_FREQUENCIA Char
EVENTO_PERIODO Int
EVENTO_DIAS_DA_SEMANA Byte

Tabela 2 – modelo parcial da tabela de eventos – solução proposta.

O atributo TIPO_FREQUENCIA mantém a mesma definição da solução anterior.

Aqui, o atributo PERIODO armazena o total de ocorrência do evento, seu sentido será dado em função do TIPO_FREQUENCIA.

E, finalmente, a grande simplificação do cenário, em um único atributo, DIAS_DA_SEMANA, do tipo byte, armazenaremos os dias da semana e todas as suas combinações, caso tenhamos uma frequência do tipo semanal. Obviamente ainda teremos “desperdício” de atributos, mas somente um, e ainda apenas para tipo da frequência diferente de semanal.

Como isso é possível??

Lembram do filme “Matrix”, quando o personagem Neo passou a ver o mundo decodificado? Eis o caminho para nossa solução: precisamos recorrer ao cerne do mundo digital – os bits.

Recordar é viver – “Os tipos de dados são formados por conjuntos de bits” – um inteiro tem 4 bytes x 8 bits = 32 bits, um double tem 8 bytes x 8 bits = 64 bits, etc. No nosso caso, onde temos que manipular 7 informações (os dias da semana), a melhor opção é um campo do tipo byte que tem 8 bits – tudo bem, ainda desperdiçamos 1, mas nem tudo é perfeito.

Decodificando um campo byte temos:

0000 0001  1
0000 0010 2
0000 0100 4
0000 1000 8
0001 0000 16
0010 0000 32
0100 0000 64

Atribuindo um dia da semana para cada valor:

0000 0001  1 Domingo
0000 0010 2 Segunda-Feria
0000 0100 4 Terça-Feria
0000 1000 8 Quarta-Feria
0001 0000 16 Quinta-Feria
0010 0000 32 Sexta-Feria
0100 0000 64 Sábado

Decodificando os dias da semana:

0000 0001  01 ↔ 2 0 Domingo
0000 0010 02 ↔ 2 1 Segunda-feira
0000 0100 04 ↔ 2 2 Terça-feira
0000 1000 08 ↔ 2 3 Quarta-feira
0001 0000 16 ↔ 2 4 Quinta-feira
0010 0000 32 ↔ 2 5 Sexta-feira
0100 0000 64 ↔ 2 6 Sábado

Ora, concluímos que o valor associado a um dia corresponde a 2 elevado ao seu “peso”,  2 (dia da semana) 

E para combinação de vários dias, como nos exemplos acima?? Simples, é só “ligar” os bits correspondentes a cada dia, vejamos:

Segunda, Quarta e Sexta == 0010 1010 == 2 + 2 + 2 == 02 + 08 + 32 == 42

Terça, Quinta e Sábado   == 0101 0100 == 2 + 2 + 2 == 04 + 16 + 64 == 84

Logo, em vez de manipular diversos atributos, propriedades e parâmetros na codificação, calculamos um único valor numérico que representa a combinação de todos os dias da semana e assim manipulamos somente um atributo, simplificando e otimizando nosso trabalho.

Finalmente a expressão para obtenção desse valor será : Valor += 2 (dia da semana) , onde o dia da semana será obtido de sua interface.

E o processo inverso: como recuperar o valor armazenado no repositório de dados e disponibilizá-lo ao usuário? Ora, precisamos desse valor representado em bits novamente, ou melhor, em um conjunto de bits (7), em seu devido estado fundamental – ligado x desligado, mais precisamente devido à interação com a interface, true x false.

Mais uma vez, recorremos à maravilhosa matemática. Nosso algoritmo foi baseado em funções exponenciais, nas quais uma das formas de análise dessas funções é o processo conhecido como fatoração, lembram?

64 2
32 2
16 2
8 2
4 2
2 2
1

64 = 2 6

Pois bem, precisamos de um conjunto ou array de bits ligados e desligados,  correspondente ao valor armazenado; combinando as operações de fatoração e o resto das divisões sucessivas, teremos exatamente as informações de que precisamos:

42 = ?

O resto da divisão 42/2 = 0 (fatorando = 21)

O resto da divisão 21/2 = 1 (fatorando = 10)

O resto da divisão 10/2 = 0 (fatorando = 5)

O resto da divisão 05/2 = 1 (fatorando = 2)

O resto da divisão 02/2 = 0 (fatorando = 1)

O resto da divisão 01         1 (fim)

E esses “zeros” e “uns” gerados, tomados de baixo para cima, correspondem exatamente ao nosso conjunto inicial de bits (10 1010), complementando-os com zeros à esquerda, bingo: 0010 1010, ou melhor, um array do tipo [false – false – true – false    true – false – true –false].

É isso aí, pessoal, o principio KISS é de uma utilidade tremenda em nosso dia a dia, seja implementando, coordenado ou gerindo atividades relacionadas ao mundo de tecnologia. Espero com este artigo ter lhes despertado a pensar de maneira KISS.

Nosso trabalho deve ir muito além de pesquisar códigos ou fórmulas no Google para resolução de problemas. Precisamos, sim, analisar, pensar um pouco e propor soluções da melhor forma possível. Como vimos no exemplo apresentado, a codificação utilizada foi mínima, e aí está o grande mérito da proposta – conseguimos muito com bem pouco, uma amostra das leis natural do mínimo esforço (não em vão, fizemos uso da matemática).

É claro que pensar de maneira a simplificar é ótimo, mas também devemos prestar atenção a Einstein que disse “Tudo deve ser tornado o mais simples possível, porém não mais simples que isso”.

Finalmente, meu muito obrigado à minha madrinha (in memoriam), que desde sempre me estimulou o hábito da leitura e fica a lição: não existe livro “bobo”,  sempre tem algo interessante a ser aproveitado.