Análise assintótica em OutSystems

Ricardo Pereira
4 min readJul 18, 2022

--

Uma das coisas que mais é salientado no desenvolvimento Low-Code é a sua rapidez. Com este novo paradigma, as empresas conseguem com que os seus softwares acompanhem e evoluam ao mesmo ritmo dos seus negócios, aumentando muitas vezes esse potencial.

No entanto, algo que deve estar sempre na mente de qualquer equipa de desenvolvimento, tech lead, developer ou arquiteto de software, é a sua qualidade. O facto de se desenvolver o software mais rápido faz com que se falhe mais rápido e, se estivermos atentos é uma coisa boa, senão, pode ser péssima.

O facto de não se criar o software com a melhor qualidade possível leva a que, num futuro próximo, a dívida técnica seja muito elevada, levando a um atraso na reestruturação aplicacional e, com isso, prejuízo.

Sabemos que (e neste caso vou falar na tecnologia que conheço, OutSystems) temos bastantes ferramentas disponíveis para evitar a queda no precipício e imensa documentação e conhecimento partilhados na Internet, mas cabe-nos a nós ser auto-conscientes e seguir os melhores exemplos, padrões e apoiarmo-nos nos artefactos existentes de modo a construirmos com a melhor qualidade possível.

Sabemos que há vários temas que podem ser abordados relativamente a este conceito. Um que me parece bastante interessante e, por vezes, negligenciado, é a análise assintótica de algoritmos. Conforme o tempo passa e seguindo (pelo menos para já) a lei de Moore, o hardware consegue colmatar as falhas de otimização de software, sendo que conseguem baixar tempos de resposta e aumentar ao espaço necessário em memórias lentas e rápidas de modo a correr algoritmos lentos quase de forma impercetível. No entanto, há um cenário que (provavelmente muitos que estão a ler isto já o encontraram) não corre como o esperado. Uma funcionalidade que é executada conforme esperada em ambientes de desenvolvimento e que depois, com carga, não funcionam como esperado. Porquê? Porque, por muito rápida que uma máquina seja, se determinada ação (ou função, método, aproveitando as designações de outras tecnologias) depender do seu input, este interfere no seu tempo/espaço de resposta. Baseado nesta premissa, a análise assintótica tornar-se bastante relevante.

Como definição, a análise assintótica de algoritmos é um método de análise de comportamento de algoritmos com base num elevado volume de dados de input independentemente da máquina que o corre. Em resumo, calcula o tempo de execução com base no valor de n. No caso de OutSystems, temos o caso em que pode não ser o volume de dados de um determinado input, mas sim o tratamento de n registos obtidos da base de dados e/ou registos locais (variáveis locais) da própria ação (Server Action ou Client Action).

Considerando isto, partimos para um exemplo de modo a demonstrar melhor o que o conceito é:

Se tivermos uma ação com um for each que itera n registos de um aggregate/SQL node, o custo dessa iteração é n. Se tivermos apenas uma atribuição de um valor a uma variável o seu valor é constante, ou seja, 1. Partindo disto analisemos o seguinte:

Aqui temos:

Exemplo algoritmo de Server Action em OutSystems

· uma atribuição de início, ou seja, O(1) (constante);

· um fetch da base de dados, ou seja, consideremos O(1) (constante, apesar de não ser uma realidade em muitos casos mas para o exemplo funciona);

· Um for each, que itera todos os registos, logo, O(n);

· Dentro do for each temos uma atribuição, ou seja, O(1) (constante);

Efetuando os cálculos, temos O(1)+O(1) + O(n)*O(1) (sendo que, por cada iteração, repete-se o O(1) da atribuição feita dentro do loop).

Considerando que, para grandes valores de n as constantes não têm grande significado, podemos descartar os valores constantes, resultando então que a Server Action do exemplo tem um algoritmo com ordem de crescimento O(n).

Agora surge a questão, o que é o “O”?

O “O” é a forma de representar a notação Big-O, utilizada para analisar a complexidade no pior cenário. Temos também a notação Big-theta (cenário médio) e Big-omega (melhor cenário). Neste caso, o foco foi o Big-O por denotar o pior caso possível, sendo o mais relevante para grandes cargas e chamadas.

Para podermos compreender se os nossos algoritmos são viáveis e prever o seu comportamento para grandes volumes (sendo as iterações com taxa de crescimento prevista um caso a ter em conta) segue a seguinte tabela relativa ao tipo de algoritmo e qual a sua viabilidade:

Tabela com as diferentes notações Big-O

Um algoritmo O(1) corre sempre em tempo constante, independentemente da dimensão do input (ou do número de items a tratar). No outro extremo da tabela, os algoritmos exponenciais são normalmente considerados “intratáveis”, no sentido em que o seu tempo de execução cresce muito rapidamente com n.

A análise assintótica é uma ferramenta muito útil para garantirmos que as nossas aplicações vão cumprir com os requisitos a longo prazo, ajudando a evitar comportamentos indesejados em ambientes com muito processamento de registos e muitas iterações.

Para o caso de interesse em aprofundar mais o tema (que tem muito conteúdo relevante) podemos consultar os seguintes links:

https://en.wikipedia.org/wiki/Asymptotic_analysis

https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/asymptotic-notation

https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/big-o-notation

https://pt.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/big-big-theta-notation

https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/big-big-omega-notation

Espero que este artigo ajude e/ou contribua para a curiosidade de investigarem mais sobre o tema e que traga valor para cada um de nós.

--

--

Ricardo Pereira
Ricardo Pereira

Written by Ricardo Pereira

Passionate about software development, started my journey in Outsystems in 2016, getting completely addicted to the platform.

No responses yet