Linguagens de Programação

O que são as linguagens funcionais?

Ultimamente, as linguagens ditas funcionais estão ganhando cada vez mais a atenção dos desenvolvedores em geral. Já não é tão difícil encontrarmos projetos que utilizem uma linguagem funcional para resolver problemas que envolvem principalmente paralelismo e/ou processamento de quantidades grandes de dados. As ideias fundamentadas pelo paradigma funcional dão essa “vocação” para o paralelismo e processamento de quantidades extensas de dados para estas linguagens ditas funcionais.
Mas, no final das contas, o que torna as linguagens funcionais tão adequadas para a resolução destes tipos de problemas? E quais são os contrapontos entre o paradigma funcional e o paradigma orientado a objetos? Será que o paradigma funcional pode substituir completamente o paradigma orientado a objetos?

O que é o paradigma funcional?

Antes de qualquer coisa: não, o paradigma funcional não tem esse nome porque ele funciona.

O paradigma funcional possui esse nome porque ele está fortemente fundamentado nos conceitos das funções matemáticas.
Mas calma! Muita gente já “torce o nariz” ao ouvir falar de matemática, mas os conceitos envolvidos na descrição do paradigma funcional podem ser mais tranquilos de se entender do que você imagina.

Relembrando alguns conceitos de funções matemáticas

Vamos recapitular um pouco sobre uma função matemática. Uma função matemática tem essa aparência:

Se verificarmos, uma função matemática possui uma única entrada. Em uma função matemática, essa única entrada sofre um tipo de processamento, processamento este que retorna uma saída de qualquer maneira. No caso da função acima:

  • A entrada é definida por x;
  • O processamento é a elevação de x ao quadrado mais 3;
  • A saída é o resultado do processamento descrito acima.

Mais um exemplo: se entrarmos com o número 2 nessa função matemática, teremos a saída 7, pois 2^2 (4) + 3 é igual a 7.

Existem alguns detalhes importantes. A função acima, além de sempre retornar um resultado compulsoriamente, ela sempre retornará a mesma saída para uma determinada entrada. Por exemplo: podemos “chamar” esta função passando para ela a entrada 2 hoje, amanhã ou daqui 10 anos… Não importa: o resultado dela sempre será 7, independente da situação. Nós chamamos esta característica de determinismo. Por isso, dizemos que funções matemáticas em sua essência são determinísticas.
Outro fato interessante: funções matemáticas não possuem o conceito de escopo. Isso quer dizer que a entrada é processada e a saída correspondente é devolvida imediatamente. Não existem “variáveis” intermediárias que só podem ser acessadas dentro da função matemática: só existe a entrada e a saída.

Trazendo conceitos de funções matemáticas para as linguagens de programação

O paradigma funcional se baseia fortemente nos conceitos de funções matemáticas que discutimos no tópico anterior. E, sendo um paradigma, não necessariamente precisa ser implementado com uma linguagem funcional…
Por exemplo, poderíamos reescrever a função matemática anterior com o seguinte código Java:

public int doFunction(int x){
    return (x * x) + 3;
}

System.out.println(doFunction(2)); // A saída será "7"!

Veja que, na função acima:

  • Temos uma única entrada;
  • Não existe o conceito de escopo, pelo menos não explicitamente (já que não existem variáveis criadas dentro do método doFunction());
  • O método sempre irá produzir uma saída;
  • O método é determinístico, pois ele irá sempre produzir a mesma saída para uma mesma entrada.

Sendo assim, conseguimos criar um código funcional, mesmo utilizando o Java, que não é uma linguagem essencialmente funcional.
Acima, ainda temos uma outra característica intrínseca ao paradigma funcional que é fantástica: a imutabilidade! Veja que, em nossa versão Java da função matemática, a entrada nunca é modificada: ela simplesmente sofre um processamento, produzindo uma saída. A saída produzida também nunca é modificada… Isso é fantástico, pois ao final, estamos quase que trabalhando com constantes o tempo inteiro.
Obviamente, o Java e outras linguagens majoritariamente orientadas a objeto não dão um suporte 100% para estes conceitos que descrevemos… Porém, se pegarmos linguagens majoritariamente funcionais, nós teremos estes princípios básicos levados mais à risca. Por exemplo: vamos considerar a reescrita desta função em F#, uma linguagen funcional:

let doFunction x = (x * x) + 3

let result = doFunction 2
printfn "Resultado: %i" result

Acima, temos a mesma função reescrita em uma linguagen funcional. Veja que os conceitos de ausência de escopo, massa de entrada e saída e determinismo são respeitados aqui. Aliás, se você tentar modificar a “variável” result (que aqui é chamada de binding), o compilador irá produzir um erro.

Por que linguagens funcionais podem ser interessantes para paralelismo, assincronia e processamento de grandes quantidades de informações?

Nós estamos, em maioria, acostumados a escrever código orientado a objetos, e uma das premissas da orientação a objetos é a transição de estado: nós criamos variáveis e/ou objetos que mudam de conteúdo o tempo inteiro, fazendo com que o nosso código tome decisões em cima destas flutuações de estado que acontecem. Isso não existe dentro do paradigma funcional, tendo em vista o determinismo e a imutabilidade.
Quando estamos falando sobre o processamento de quantidades muito grandes de dados, tornar esse processamento assíncrono e paralelo é essencial. E isso pode se tornar um problema muito complicado quando falamos de transição de estado neste cenário. Um exemplo simples: quando criamos threads, uma thread não pode acessar o conteúdo que está sendo processado por outra thread. Quando precisamos que threads por alguma razão compartilhem alguma varíavel, nós acabamos precisando recorrer a patterns (como o famigerado singleton ). E no final, nós ainda precisamos nos preocupar em garantir que a modificação destes recursos compartilhados não irá ocorrer de maneira concorrente, com uma thread sobrescrevendo ou passando por cima do resultado de uma outra thread ao mesmo tempo. Para isso, precisamos recorrer a recursos como semáforos e monitores. Veja que, somente por termos um código baseado em transições de estados, nós precisamos recorrer a uma certa complexidade de código para garantir que tudo ocorra bem. Logicamente isso é factível, mas é extremamente trabalhoso.
Linguagens funcionais não possuem estes problemas, pois elas já trabalham com imutabilidade e determinismo nativamente. Imutabilidade e determinismo são pilares do paradigma funcional. Se não existem transições de estado, nós não teríamos este tipo de problema se utilizássemos uma linguagem funcional.

Então devo chutar a orientação a objetos e aprender somente o paradigma funcional?

Não! Não faça isso!
O paradigma funcional também possui seus problemas… A curva de aprendizado tende a ser ligeiramente maior do que a curva do paradigma orientado a objetos, principalmente porque muitas pessoas já criam um “bloqueio” pela associação à matemática. Existem também alguns conceitos dentro do paradigma funcional que não são tão “naturais” de serem entendidos, como currying e monads. Sendo assim, a curva de aprendizado tende a ser um pouquinho mais íngreme.
Também temos o fato de que pouca coisa no mundo real é determinística: estamos falando das típicas situações de I/O. O acesso a uma tabela de um banco de dados, por exemplo, não pode ser determinístico: nós podemos tanto conseguir acessar a tabela como podemos em algum momento ter uma queda de conexão… Logicamente, as linguagens funcionais modernas são preparadas para também lidar com situações não-determinísticas, mas cada uma delas pode tratar de maneira diferente, o que contribui para aumentar um pouco mais o processo de aprendizagem e aplicação correta em situações do dia-a-dia.
Existe também a questão de legibilidade do código. Eu particularmente observo que é mais fácil produzir código ilegível em linguagens funcionais do que em linguagens orientadas a objeto. Tudo bem, um desenvolvedor iniciante (ou um desenvolvedor infelizmente ruim) irá produzir código ruim de qualquer maneira… Mas observo que as linguagens funcionais dão uma “forcinha” a mais nesse sentido por diferentes fatores: sintaxe propriamente dita das linguagens que implementam este paradigma, a maior ocorrência da não-observância dos pilares funcionais, entre outros.
Por isso, pelo menos para mim, o ideal é: aprenda e domine os dois paradigmas. Ambos serão muito úteis, dependendo-se da situação. Precisa criar uma página de cadastro de algo? Provavelmente a orientação a objetos pode ser mais aplicável… Precisa gerar um CSV a partir de um conjunto grande de dados? Provavelmente uma linguagem ou até mesmo uma abordagem funcional será mais aplicável. Aqui vale o velho mantra: não existe bala de prata no mundo de desenvolvimento de software. Aprenda os dois paradigmas e seja feliz!

3 linguagens de programação que continuam em alta

Você provavelmente já se pegou pensando em qual linguagem você deve focar seus estudos. Seja se você está iniciando ou não, é sempre bom ver o que o mercado está pedindo. Claro que não devemos avaliar apenas o mercado, mas também suas preferências. A ideia é fazer uma junção dessas duas coisas: escolher uma linguagem em alta, mas que dentre elas, você escolha a que mais se identificar.

No começo deste ano fizemos um post sobre as linguagens promissoras para se estudar neste ano. Mas como na área de TI tudo muda muito rápido, será que agora, perto do final do ano, essas linguagens ainda estão no topo? Vamos focar hoje nas 3 principais do momento.

1) JavaScript

Assim como no começo do ano, o JavaScript aparece em primeiro lugar. Como é uma linguagem dinâmica pode ser utilizada para várias coisas. Temos um post que aborda justamente isso: O que se pode fazer com JavaScript hoje em dia?

O site Stack Overflow sempre realiza uma pesquisa para obter estatísticas da comunidade de desenvolvedores. E nas tecnologias mais populares, está ela, em primeiro lugar, com uma porcentagem de 69,8%.

O GitHub (site de compartilhamento de código) também diz que o JavaScript é o mais utilizado.

Como podemos ver acima, em segundo aparece a linguagem Python, que veremos a seguir.

2) Python

Desde o começo do ano ela era uma das linguagens mais promissoras, e ela ainda está no pódio. O Python é uma linguagem poderosa e que cada vez mais ganha popularidade em meio aos desenvolvedores.

Podendo ser utilizada por uma variedade de tarefas, desde desenvolvimento web, aprendizado de máquina, análise de dados e muitas outras.

Ainda na pesquisa do Stack Overflow, quase 40% dos usuários utilizam Python em seus projetos. E ainda tem mais: segundo o site TIOBE, podemos ver como o Python tem crescido.

3) Java

Muitas pessoas quando pensam em estudar uma linguagem, já pensam logo no Java. Se você gostar, porque não? Apesar de não ter aparecido como uma das linguagens mais promissoras para este ano, o Java voltou a ser um dos centros a partir de julho/2018.

Como é uma linguagem de programação bem versátil, você pode utilizá-la para diversas finalidades como desktop, web e até mobile. Para tudo isso, o Java atenderá suas necessidades.

Concluindo

Agora você pode estar se perguntando… “Ok, então eu tenho que escolher uma dessas três linguagens?” e a resposta é: não exatamente…

Por que não aprender as três? Essas são as linguagens mais bem classificadas pelos sites como pudemos ver acima.

Quanto maior o seu conhecimento, tanto na linguagem em si quanto na quantidade, pode abrir um leque de oportunidades. Você pode estudar uma por vez, para poder levar sua carreira a um próximo nível.

Até a próxima! 😊

Qual linguagem devo aprender primeiro?

Quando iniciamos na área de TI, ficamos com muitas dúvidas sobre como entrar na área de programação, sobre qual é o primeiro passo etc. É comum esse tipo de dúvida pois temos hoje uma infinidade de opções, seja de desenvolvimento desktop, web e mobile.

Não existe uma linguagem que você tem que aprender primeiro, o que temos são bases que nos auxiliam. É que veremos a seguir, independente da linguagem que formos escolher depois.

1. Lógica de Programação

Esse é o primeiro passo e muitas pessoas não dão o devido valor ao estudar a lógica de programação. A lógica é o primeiro conhecimento que você deve procurar adquirir, funcionando como um pré-requisito para se aprender qualquer linguagem. Aí você pode até pensar que não se tem utilidade em aprender lógica já que todos nós já temos essa habilidade de raciocínio lógico. Mas você deve saber também que devemos aprimorar e desenvolver cada vez mais nossa lógica, ainda mais na programação que devemos passar nossa lógica de uma forma que o computador entenda.

Por ser mais teoria pode parecer muito chato, mas você verá a utilidade dela mais para frente e, se você não tiver conhecimentos básicos nesse quesito, poderá ter dificuldades na hora de colocar a mão na massa com uma linguagem de programação.

2. Lógica Orientada a Objetos

A maioria das linguagens de programação são orientadas a objetos ou implementam orientação a objetos (C#, Java, PHP, Python, Ruby entre outras), portanto se você deseja aprender alguma delas é necessário trabalhar a lógica voltada a orientação a objetos.

Aprender e compreender a orientação a objetos é importante para que seu código fique de acordo com o paradigma orientado a objetos.

Vale lembrar que este estudo é voltado a lógica com foco na orientação a objetos, ele não substitui os conhecimentos adquiridos na lógica de programação.

3. HTML5 e CSS

HTML e CSS são conhecimentos que todo desenvolvedor deve saber. Uma hora ou outra você irá precisar deles. Eles funcionam como uma porta de entrada no desenvolvimento web. O HTML e o CSS são utilizados para criar páginas web e atuam de forma complementar. Todos os sites utilizam HTML e CSS de uma forma ou de outra.

O HTML é uma linguagem muito fácil de se aprender e em pouco tempo você já poderá criar um website com facilidade. Com um pouquinho mais de tempo e dedicação, você poderá estilizar suas páginas utilizando o CSS, conseguindo um resultado mais profissional.

4. Linguagens back-end

Depois de aprender os tópicos anteriores, você já tem conhecimentos suficientes para escolher uma linguagem back-end. Você pode escolher a linguagem que quiser para estudar. Alguns exemplos de linguagens back-end são Java, C++, C#, PHP, Ruby, Python, Go, dentre outras…

Se seu foco for desenvolver aplicativos ou games, saiba que muitas vezes saber uma determinada linguagem é essencial. Por exemplo, se você quer desenvolver aplicativos cross-platform você pode utilizar o Xamarin, mas a base dele é em C#.

Para o desenvolvimento de games, utilizando o Unity, você também deverá saber a linguagem C#. Não são todos que tem alguma linguagem por trás, por isso é importante verificar antes se a sua escolha tem, se tiver se torna essencial aprendê-la.

Você pode ver a relação dos cursos de back-end que ministramos clicando aqui.

5. Banco de dados

Conhecer pelo menos um banco de dados é importante. Assim você pode até fazer com que suas aplicações web se integrem com o banco. O SQL é uma linguagem universal e comum para todos os bancos de dados relacionais. A partir dele podemos ter outras variações do SQL que são específicas de cada banco: o Oracle e o MySQL têm o plSQL, o SQL Server tem o T-SQL e o PostGre tem o pgSQL. Por isso, aprender o SQL se torna um requisito.

Você pode ver a relação dos cursos de bancos de dados que ministramos clicando aqui.

Concluindo

Esses são alguns tópicos que podem te ajudar caso você não saiba por onde começar. Começar direto em uma linguagem pode não ser uma boa experiência, muitas vezes pular etapas pode fazer com que a pessoa que está entrando na área desanime caso não consiga entender coisa nenhuma. Com esses passos esperamos que você possa ter um melhor aproveitamento em cada quesito. Boa sorte!

5 linguagens de programação promissoras para se estudar em 2018

Que tal aproveitar esse início de ano e traçar uma meta de estudos envolvendo as linguagens mais promissoras para esse ano?

Se você é iniciante, é uma ótima maneira de começar para poder estar apto ao que o mercado está pedindo. Para você que já é da área, nunca é demais estudar e se aprimorar nas linguagens que você já conhece ou se aventurar em uma nova, pois sabemos que em nossa área o estudo é constante… então vamos começar?

JavaScript

O JavaScript é uma linguagem que está praticamente em tudo! Esse já é um bom motivo para o qual você não estará perdendo tempo estudando ele. Vai chegar uma hora que você precisará saber nem que seja um pouco. Além disso, ele funciona tanto do lado do cliente como do servidor, assim você também poderá criar aplicativos e até executá-los em dispositivos IoT (Internet das coisas).

O JavaScript é uma linguagem de programação universal e continuará sendo. Caso você já domine ele, pode dar uma olhada no TypeScript, um superset de JavaScript.

Python

O Python sempre foi uma linguagem popular para se aprender a programar, justamente por ter uma sintaxe bem clara e fácil de se aprender. Recentemente lançamos um post sobre ele especialmente para quem quer iniciar: “Como começar com Python“, se você ainda não viu dá uma olhada lá.

Além do Python ser uma ótima linguagem de programação para iniciantes, ela também se aplica para programadores mais experientes, pois é uma linguagem vastamente utilizada no mercado de trabalho.

O Python é uma linguagem que está em expansão principalmente na área de Machine Learning (com R), além de poder ser utilizada com vários propósitos. É possível desenvolver desde scripts até aplicações web e mobile.

C#

O C# é uma das linguagens de programação mais modernas e populares hoje em dia, e esse ano não será diferente. Você pode utilizá-la para desenvolver para plataformas web, dispositivos móveis e aplicações desktop.

Com a praticidade dessa linguagem, você pode, de forma relativamente fácil, desenvolver desde projetos mais simples até projetos complexos e multiplataforma.

Além disso, o C# é usado em Unity, então se você deseja se aprofundar na área de games será realmente valioso, para que assim você possa se aventurar nas experiências de AR (Realidade Aumentada) e VR (Realidade Virtual).

Go

O Go é uma linguagem que vem subindo rapidamente sua popularidade. É uma linguagem simples, mas muito poderosa.Ela foi criada pela Google com o objetivo de ser uma linguagem de programação ideal e você poderá se surpreender do tanto que essa linguagem pode atender as suas expectativas.

Se você já tiver uma base de conhecimentos em programação, se sentirá mais confortável em aprender Go.

Kotlin com Android

O Kotlin é uma linguagem recente, onde você pode desenvolver aplicativos para Android com ela. Agora, a Kotlin é a linguagem oficial suportada na plataforma Android, se tornando uma substituição gradual ao Java.

Com o apoio do Google e JetBrains, não é surpresa que o Kotlin tenha tido um aumento tão grande em popularidade. Então se você deseja criar aplicativos para Android, já pode começar a estudar o Kotlin.

Concluindo

Vale lembrar que essas são as linguagens que julgamos promissoras para este ano. Se você gosta e/ou precisa aprender alguma outra não há problema nenhum, o importante é o estudo constante. 😉

Como começar com C# (C Sharp)?

Atualmente são tantas as opções de linguagens de programação à nossa disposição que ficamos perdidos em qual estudar. Para lhe ajudar nessa escolha, vamos apresentar a linguagem C#.

O C# é uma linguagem de programação muito popular, sendo uma excelente escolha devido a sua baixa curva de aprendizado e simplicidade (mas sem deixar de ser uma linguagem poderosa). Além disso, ela é a linguagem principal do .NET Framework, o framework para desenvolvimento da Microsoft.

Se você não tem nenhum conhecimento sobre programação, não tem problema: o C# é ótimo para você começar seus estudos, pois aprendê-lo é muito mais fácil do que parece. Caso você já tenha uma bagagem em alguma linguagem (como por exemplo Java ou C++), você não encontrará problemas em se ambientar com ele.

O que é C#?

O C# é uma linguagem de programação multiparadigma criada pela Microsoft, sendo a principal da plataforma .NET. Por ser uma linguagem que suporta, entre outros paradigmas, a orientação à objetos, ela suporta conceitos comuns como encapsulamento, herança e polimorfismo. Trata-se também de uma linguagem fortemente tipada e case-sensitive, ou seja, faz diferenciação entre letras minúsculas e maiúsculas.

O C# veio para facilitar o processo de desenvolvimento, tendo inúmeros recursos que proporcionam uma grande produtividade para os desenvolvedores que a utilizam.

O que pode ser feito?

O C# é uma linguagem multiplataforma. Sendo assim, você pode utilizá-la para desenvolver para plataformas web, dispositivos móveis e aplicações desktop. Com a praticidade dessa linguagem, você pode, de forma relativamente fácil, desenvolver desde projetos mais simples até projetos complexos e multiplataforma.

Sintaxe do C#(C Sharp)

A sintaxe do C# é simples. Veja o tradicional “Hello World”:

public class Exemplo
{
    public static void Main()
      {
        System.Console.WriteLine("Hello World!");
      }
 }

Utilizar estruturas de tomada de decisão com C# é muito fácil. Veja o tradicional “if/else”.

int idade = 18;
if ( idade >= 18 )
{
    Console.WriteLine( "Você é maior de idade“ );
}
else
{
    Console.WriteLine( "Você é menor de idade" );
}

Você também pode utilizar estruturas de repetição, como a estrutura “for”, sem problemas… Veja o código abaixo, onde fazemos uma verificação e imprimimos somente os números que forem menores ou iguais a 5:

class Exemplo
{
    static void Main() 
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine(i);
        }
    }
}

Mercado de trabalho

Você pode escolher uma linguagem de programação que mais te agrade, mas também é importante observar como anda o mercado de trabalho. O C# é uma das linguagens mais utilizadas no mundo e o mercado está em alta para essa linguagem.

Segundo o site TIOBE (Programming Community Index Definition), o C# é uma das 5 linguagens mais utilizadas no mundo! Além disso, grandes empresas utilizam o C# em seus produtos, empresas como Microsoft (em uma infinidade de soluções: desde soluções Web até soluções mobile multiplataforma através do Xamarin), Amazon, StackOverflow (toda a stack web do StackOverflow é construída em cima de C# e .NET) e nós aqui no TreinaWeb (algumas de nossas aplicações foram escritas com C# e .NET Framework Full e .NET Core). Você pode até mesmo desenvolver jogos com C# através da Unity.

Então, se você estudá-la e se especializar, certamente não ficará fora do mercado. =D

Como aprender C#?

Aqui no TreinaWeb temos uma trilha voltada para C#. O curso de “C# Básico” é ótimo para você dar os primeiros passos nessa linguagem de fácil compreensão e com recursos poderosos. No curso básico, além de você aprender todos os conceitos básicos dessa linguagem, você acompanhará a construção de um projeto com todo o seu passo a passo.

Conheça nossa metodologia

Nosso ambiente de aprendizagem é 100% online. Nossa metodologia de ensino é baseada em vídeo aulas, apostilas, exercícios aula-a-aula e exemplos completos. Você estuda no seu tempo e ao final pode baixar o seu certificado digital ou solicitar o certificado impresso.

Na parte escrita, fornecemos um material totalmente atualizado e completo para que você possa usufruir do conteúdo, utilizando-se de textos e imagens. Já as vídeo-aulas são bem explicativas e práticas, abordando todo o conteúdo passo-a-passo, para que você entenda tudo da melhor maneira possível.

Além disso, você encontrará exercícios para poder fixar, praticar e aplicar todo o conteúdo aprendido. São exercícios que são propostos em cada aula do curso. Eles podem variar entre alguns formatos, como por exemplo questões de escolha única, questões de múltipla escolha e complemento de trechos de código.

Se ainda assim você tiver alguma dúvida, você poderá pedir ajuda aos nossos professores através de tickets de atendimento. Funciona como um canal direto entre você e o professor, onde você poderá realizar perguntas que serão respondidas muito brevemente!

Além disso, ainda pelo sistema suporte, você também poderá consultar todas as perguntas que já foram respondidas a outros alunos! =)

Quais conhecimentos preciso ter para iniciar este curso?

O curso é recomendado para você iniciar seus estudos na linguagem C#, no entanto, é interessante saber as bases necessárias para aprender qualquer linguagem de programação: “Lógica de Programação” e “Lógica de Programação Orientada a Objetos”.

Também ministramos esses cursos:

Gostou do que viu?

Se entusiasmou com a linguagem? Gostaria de conhecê-la com mais detalhes? Sim, você pode dar uma espiadinha. Acesse o link do curso de C# Básico e veja algumas aulas de exemplo. =D

Bons estudos!

Top 5 das linguagens de programação mais populares de 2017

O ano está acabando e você, sabe quais foram as linguagens de programação mais utilizadas / populares neste ano?

Isso é algo interessante de se saber, pode te ajudar a escolher uma linguagem para estudar. Claro que isso varia da região que você mora, do que a sua empresa geralmente usa, dentre outros fatores.

Vamos tomar como base dois sites que avaliam a popularidade das linguagens, o TIOBE e o IEEE Spectrum, e vamos listar aqui as cinco principais do ranking.

Nos dois sites houveram similaridade nas linguagens, porém, em posições diferentes, como podemos ver mais pra frente.

O primeiro ranking é do site TIOBE Index, mantido por uma empresa de mesmo nome, onde todo mês o ranking é atualizado.

Em quesito de posição, as primeiras linguagens não tiveram muita diferença de colocação nos últimos meses. Podemos ver também uma comparação entre o mês de novembro deste ano em relação a novembro do ano passado, onde somente as linguagens Python e C# trocaram de posição.

Ranking - Linguagens de Programação - TIOBE

O segundo ranking é do site IEEE Spectrum, uma revista de tecnologia, onde os rankings são criados por ponderação e combinação de 12 métricas de 10 fontes. Neste site você pode ver o ranking das linguagens separados por segmentos como web, mobile, enterprise, desktop, entre outros.

Ranking - Linguagens de Programação - IEEE

Agora vamos abordar sobre as cinco linguagens mais utilizadas. Claro que tem muitas outras que também são bem utilizadas, mas para este artigo não ficar extenso, vamos limitar dessa maneira a nossa avaliação.

Como nos rankings as posições estão diferentes, vamos abordar por ordem alfabética.

C

O C é uma linguagem de programação voltada ao desenvolvimento de sistemas embarcados. Por ser muito rápido e poderoso, ele é muito requisitado principalmente no ramo de telecomunicações. Com ele podem ser desenvolvidas várias coisas como sistemas de usuário, sistemas operacionais e até mesmo outras linguagens de programação.

C++

O C++ é um aprimoramento da linguagem C, mas com elementos de orientação a objetos. É recomendada principalmente para desenvolvimento de sistemas para desktop e games. Assim como a linguagem C, ela pode ser utilizada para desenvolvimento de sistemas embarcados, sistemas operacionais etc.

C#

O C# é a principal linguagem de programação da Microsoft, fazendo parte do framework .NET, onde você pode criar desde serviços e plataformas web como também aplicativos para celular.

Java

Não é segredo para ninguém que o Java é a linguagem de programação orientada a objetos mais utilizada, seja para desenvolvimento web ou mobile.

Python

O Python é uma linguagem bastante utilizada por ser orientada a objetos, multiplataforma e de alto nível. Ela pode ser utilizada em aplicações web, inteligência artificial, computação científica. Com o Python você consegue atingir praticamente todo o mercado de programação: web, mineração, controle de máquina, servidor, desktop etc.

Imutabilidade de objetos no PHP

Imutabilidade é uma característica forte nas linguagens funcionais, onde a alteração de estado não é frequente e, quando ela acontece, é controlada. Há de se observar que, o PHP, uma linguagem multi-paradigma e fracamente tipada, não implementa (ainda) nenhum mecanismo padrão para lidar com imutabilidade.

Linguagens de programação são naturalmente opinativas e é difícil fazer com que elas se comportem de uma determinada forma se não foram cultura e tecnicamente desenvolvidas para servir aquele propósito específico. Por exemplo, não adianta eu querer acessar diretamente um endereço da memória usando o PHP, a linguagem não nasceu com essa premissa, não é uma linguagem para se desenvolver sistemas embarcados, por exemplo. Consegue perceber? As linguagens possuem “culturas” e características e, quando escolhemos uma delas, temos que nos “encaixar” nesses aspectos.

Disso, infere-se que, por mais que tentemos, programar em PHP nunca será 100% thread safe, será sempre mutável. No entanto, podemos usar características da linguagem a fim de emular diferentes comportamentos e características, dentre elas, a imutabilidade (mesmo que parcial, se estritamente avaliado). Há de se destacar que, sim, é possível programar usando o paradigma funcional em PHP desde a versão 5.3 com a introdução de Lambda’s e Closure’s.

Imutabilidade

Um objeto imutável é, por definição, aquele que não pode ter o seu estado alterado depois da sua criação.

Abrindo um parênteses aqui, uma constante é a única estrutura realmente imutável no PHP. Tanto as constantes do escopo global quanto as constantes de classe garantem que o valor declarado permanecerá estático durante todo o ciclo de vida de execução do script.

class FooClass
{
    const PI = 3.14159265359;

    public function __construct()
    {
        static::PI = 3.14; // FATAL ERROR syntax error, unexpected '=' on line number 7
    }
}

$foo = new FooClass(); // Error

Mas, constantes só trabalham com valores escalares (int, string, float, boolean), nulos e arrays (um tipo composto).

Objetos mutáveis

A alternância de estados é uma das características mais fortes do paradigma imperativo, logo, essa também é uma característica evidente no paradigma orientado a objetos (que é imperativo). Há muitos benefícios, claro. Os princípios SOLID são conceitualmente incríveis, aumentam a legibilidade e a manutenibilidade dos softwares. Mas, às vezes, lidar com centenas de objetos pode nos levar à perigosas armadilhas.

Um problema que a mutabilidade pode nos trazer é o efeito colateral. Um código mutável fica a mercê de alterações não previstas do seu estado, então, num determinado ciclo da execução ele pode ter o estado A e em outro ciclo o estado B, ele fica suscetível à violações.

Vamos a um exemplo didático? Considere uma classe para trabalhar com simples cálculos monetários:

class Money
{
    /**
     * @var mixed
     */
    private $amount;

    /**
     * Money constructor.
     * @param $amount
     */
    public function __construct($amount)
    {
        $this->amount = $amount;
    }

    /**
     * @param $amount
     * @return $this
     */
    public function plus($amount)
    {
        $this->amount += $amount;

        return $this;
    }

    /**
     * @param $amount
     * @return $this
     */
    public function sub($amount)
    {
        $this->amount -= $amount;

        return $this;
    }

    /**
     * @return string
     */
    public function amount()
    {
        return $this->amount;
    }
}

Suponhamos, então, que temos uma classe Payment que utiliza a Money:

class Payment
{
    /**
     * @param $valor
     * @return array
     */
    public function process($valor)
    {
        $valorBruto = new Money($valor);

        // TODO

        $valorLiquido = $valorBruto->sub(20);

        // TODO

        return [
            'valor_bruto' => $valorBruto->amount(),
            'valor_liquido' => $valorLiquido->amount(),
        ];
    }
}

Integrando e utilizando o exemplo:

$payment = new Payment();
$result = $payment->process(100);

Avaliando a classe Payment subtende-se como senso comum que teremos armazenado na variável $result o seguinte array:

[
    'valor_bruto' => 100,
    'valor_liquido' => 80,
]

Uma vez que a entrada foi 100 e o valor líquido é o valor bruto menos 20. Certo?

Mas não é o que acontece. O resultado é:

[
    'valor_bruto' => 80,
    'valor_liquido' => 80,
]

Se você programa em PHP regularmente sabe que, quando atribuímos um objeto a uma variável, uma referência desse objeto é nos retornada. Isso quer dizer, no nosso exemplo, tanto a variável $valorBruto quanto a $valorLiquido trabalham com exatamente o mesmo endereço de objeto na memória, por isso tivemos esse efeito colateral do valor bruto ser 80 e não 100, como esperado.

Não teríamos tido tal problema se no exemplo tivéssemos explicitamente clonado o objeto $valorBruto usando o operador clone, assim:

$valorLiquido = clone $valorBruto;
$valorLiquido->sub(20);

Uma clonagem de um objeto significa a cópia de toda a estrutura interna dele, mas em outro endereço de memória. É um objeto igual em atributos / características, mas diferente.

Se alterarmos o objeto $valorBruto isso não será refletido no $valorLiquido e vice versa. São objetos distintos, moram em outro “endereço”, mesmo que iguais (no sentido de ser, ambos são do tipo Money).

Mas, que fique claro, isso não tira o fato de que esses objetos continuarão sendo suscetíveis à consecutivas mudanças de estado no ciclo de execução. É agora que entra a parte que “toca” o objetivo desse artigo.

Objetos imutáveis

Não tem como definirmos um objeto essencialmente 100% imutável no PHP, ele pode ser violado por reflexão, métodos mágicos, bindings de funções, truques com referências etc. Por exemplo, um objeto pode ser alterado pelos métodos mágicos __set(), __unset(), no uso das funções serialize() e unserialize().

No entanto, podemos chegar bem próximos disso, seguindo algumas regras:

  • Declare a classe como sendo final (a impede de ser estendida);
  • Declare as propriedades como sendo privadas;
  • Evite métodos setters, no lugar, utilize o construtor da classe para receber o valor.
  • Quando for preciso modificar o valor do objeto, retorne uma cópia (um clone) dele, nunca ele próprio;
  • Evite que esse objeto receba outro objeto e, caso seja preciso, ele também precisa ser imutável;

Vamos transformar a nossa classe Money em uma “classe imutável” usando os recursos que temos disponíveis no PHP?

final class Money
{
    /**
     * @var mixed
     */
    private $amount;

    /**
     * Money constructor.
     * @param $amount
     */
    public function __construct($amount)
    {
        if( ! is_numeric($amount)) {
            throw new \InvalidArgumentException('The amount must be numeric.');
        }

        $this->amount = $amount;
    }

    /**
     * @param $amount
     * @return Money
     */
    public function plus($amount)
    {
        return new self($this->amount + $amount);
    }

    /**
     * @param $amount
     * @return $this
     */
    public function sub($amount)
    {
        return new self($this->amount - $amount);
    }

    /**
     * @return string
     */
    public function amount()
    {
        return $this->amount;
    }
}

O que fizemos:

  • A classe agora é final;
  • Garantimos no construtor receber só o tipo de valor que queremos;
  • Nos métodos plus() e sub(), ao invés de alterarmos o objeto atual, retornamos sempre um novo objeto com o valor da operação em questão. Essa é a parte mais importante.
  • O estado de $amount agora estará protegido, ademais, é um atributo privado.

Observe os métodos plus() e sub():

/**
 * @param $amount
 * @return Money
 */
public function plus($amount)
{
    return new self($this->amount + $amount);
}

/**
 * @param $amount
 * @return $this
 */
public function sub($amount)
{
    return new self($this->amount - $amount);
}

Eles sempre vão retornar uma nova instância de Money e isso faz com os nossos objetos não tenham seus estados alterados durante o ciclo de execução.

Observe que, se queremos um objeto imutável, as alterações realizadas nele precisam criar uma nova estrutura que compartilhe características da original. Em termos gerais, tudo o que for invocado no objeto não pode alterar o estado dele, ao contrário disso, deve-se retornar o resultado dessa transformação em uma nova estrutura.

Vamos testar isso na prática?

$valor1 = new Money(20);
$valor1->sub(10);

echo $valor1->amount();

Qual será o valor da impressão?

Será 20. Estamos subtraindo 10, mas o método sub() nos retorna um novo objeto. Não estamos “tocando” no objeto $valor1. Ele permaneceu intacto.

Isso pode ser constatado se compararmos os dois objetos, veremos que são diferentes:

$valor1 = new Money(20);
$valor2 = $valor1->sub(10);

if($valor1 === $valor2) {
    echo 'São iguais';
} else {
    echo 'São diferentes.';
}

O resultado será:

São diferentes.

Alguns dos benefícios da imutabilidade:

  • A aplicação se torna um pouco mais previsível, já que o estado dos objetos não alteram durante a execução;
  • Fica mais fácil identificar onde determinado problema aconteceu, já que não há variáveis compartilhando a referência para o mesmo objeto;

Com essa alteração, você pode voltar a testar a primeira versão da classe Payment:

class Payment
{
    /**
     * @param $valor
     * @return array
     */
    public function process($valor)
    {
        $valorBruto = new Money($valor);

        // TODO

        $valorLiquido = $valorBruto->sub(20);

        // TODO

        return [
            'valor_bruto' => $valorBruto->amount(),
            'valor_liquido' => $valorLiquido->amount(),
        ];
    }
}

O resultado será:

[
    'valor_bruto' => 100,
    'valor_liquido' => 80,
]

Sem surpresas.

RFC: Immutable classes and properties

Há um RFC aberto para o PHP que discute a inclusão de classes e propriedades imutáveis no PHP. Se aprovado para alguma futura versão, teremos uma sintaxe assim:

immutable class Email
{
  public $email;

  public function __construct ($email)
  {
    // validation

    $this->email = $email;
  }
}

$email = new Email("foo@php.net");
$emailRef = &$email->email;
$emailRef = "bar@php.net" // Call will result in Fatal Error

Observe que, mesmo esse Value Object tendo o atributo $email púbico não é possível, nem fazendo um truque com referência, alterá-lo. Isso torna menos verboso a construção objetos imutáveis e sem a necessidade de terem seus membros protegidos, além de garantir uma maior segurança (tira do desenvolvedor ter que cuidar de tais detalhes de implementação).

Aproveitando a deixa, temos na standard library do PHP uma classe chamada DateTimeImmutable para trabalhar com data e hora. Um objeto dessa classe nunca têm o estado modificado, ao contrário disso, uma nova instância é sempre retornada (como fizemos com a classe Money).

Concluindo

Há situações onde o uso de objetos imutáveis são essenciais para se garantir integridade ou até mesmo um comportamento previsível. Em DDD o uso de Value Objects (que são imutáveis por essência) é bastante encorajado. Naturalmente você se deparará com esse conceito quando lidar com programação reativa com concorrências ou com qualquer outra característica da programação funcional.

Um abraço!

O PHP e o seu ecossistema nunca estiveram tão fortes

Uma das coisas mais destrutivas é o conceito pré-estabelecido sem uma análise razoável de conhecimento de causa. A tecnologia é mutável, ela não é perfeita, ela sempre terá algum ponto de fraqueza e continuamente evoluirá.

Algumas das falácias e más impressões sobre o PHP

Abaixo algumas das falácias e más impressões que são facilmente encontradas na web e em roda de colegas/amigos desenvolvedores e darei a minha opinião sobre cada uma delas.

“O PHP só serve para sites pessoais.”

O PHP, desde sua gênese, nasceu para Web e desde então, nunca a mudou. Ele se reinventou algumas vezes durante as décadas (sim, é uma linguagem nascida nos anos 90) e se estabeleceu com uma completa “plataforma web”. É utilizado pelas principais empresas de tecnologia do mercado e em grandes projetos. Algumas das grandes empresas que usam o PHP: Facebook, Google, Baidu, Wikipedia, Spotify, Uber etc.

Sim, o PHP foi criado despretensiosamente com o nome de “Personal Home Page Tools”. Rasmus Lerdorf, o seu criador, o desenvolveu para cuidar da sua página pessoal. A plataforma foi ficando interessante, recebendo incrementos, até que, depois de algumas versões, Zeev e Andi Gutmans (co-fundadores da Zend Technologies) reescreveram todo o core e lançaram a versão PHP 4. Nessa época que começou uma grande adoção da linguagem. Nos anos seguintes o PHP teve uma completa (nos seus termos e características) adição do paradigma de orientação a objetos, entre outras melhorias estruturais, até chegarmos no ponto em que estamos hoje, na versão PHP 7 e não muito distantes da versão 8.

Leitura recomendada: PHP 7 e novidades do PHP 7.1.

Veja esse relato, o Uber arrecadou as suas primeiras “moedas” utilizando PHP e a versão de um Framework que hoje é legada (a versão):

E vale lembrar que a escalabilidade de uma aplicação vai muito além da linguagem que ela utiliza.

“PHP é inseguro.”

Nenhuma linguagem é estritamente segura. A segurança da informação não se restringe a apenas algumas linhas de código. Ela envolve redes e seus protocolos, sistema operacional, serviços externos que são utilizados e, claro, a parte que nos “toca” (como desenvolvedores), que é a “programação segura” e, na maioria dos casos, a insegurança de uma codificação se dá pela limitação de conhecimento técnico do desenvolvedor e não necessariamente por causa da tecnologia que ele está utilizando.

Alguns dos macro tópicos que deveriam ser de domínio de todo desenvolvedor web (não importando a linguagem utilizada):

  • Conhecer o básico do protocolo HTTP;
  • Validar e sanitizar inputs (nunca confiar no que receber do cliente), isso já previne futuros ataques XSS e também escapar os dados ao imprimir na tela para o cliente;
  • Sempre utilizar queries parametrizadas nas operações com o banco de dados. Isso elimina a possibilidade de SQL Injection;
  • Utilizar um moderno algoritmo de hashing para passwords (como o bcrypt ou, melhor ainda, Argon2 que tem ganhado adeptos na comunidade de segurança);
  • Utilizar https em todos os domínios;
  • Criar cookies seguros, que só funcionem via HTTPS e que não sejam acessados por JavaScript;

Certamente há outros importantes tópicos, inclusive alguns mais relacionados a devOps. É importante buscar por esse tipo de conhecimento. Como desenvolvedores web não precisamos criar soluções para segurança, devemos apenas entender e utilizar as existentes. Não cabe a nós criarmos, por exemplo, uma library para criptografia, não é da nossa alçada, tem gente muito mais preparada para isso. Agora, é muito importante que conheçamos as opções disponíveis e como elas podem nos ajudar em nossos projetos.

Pelo fato de o PHP ser o motor de alguns dos maiores CMS’s do mercado como: WordPress, Drupal, Joomla, Magento etc, é comum ler e notar vulnerabilidades que são encontradas nessas plataformas. E isso não é problema, desde que você se preocupe em sempre a utilizar as últimas versões e desde que elas se mantenham atualizadas (que é o caso). Algumas vulnerabilidades não são especificamente do PHP e sim de algum módulo externo como OpenSSL ou algo relacionado ao sistema operacional. Sim, o PHP, como qualquer outra plataforma, possui vulnerabilidades, sempre teve, sempre vai ter, por isso é sempre importante utilizar as últimas versões estáveis das tecnologias que você trabalha (e isso vale para tudo, desde a linguagem, uma simples library ou até mesmo o seu sistema operacional).

É razoavelmente comum sistemas legados rodando em versões antigas do PHP. Não dá pra cravar que tais sistemas precisam ser reescritos e migrados, tudo depende da criticidade das informações que eles trabalham e como é feita a auditoria de segurança neles.

Vale o destaque: A próxima minor version do PHP, a 7.2, fará dele a primeira linguagem a adicionar criptografia moderna (incluindo as últimas e mais avançadas curvas elípticas) na sua standard library, com a libsodium.

“PHP é uma linguagem defasada.”

Por muitos anos o PHP trabalhou com a ideia de “estabilidade” em detrimento à novas features, no entanto, a partir da versão 5.3 tivemos significativas alterações na linguagem, inclusão de novos recursos e estruturas.

É plausível não gostar do PHP, da sintaxe dele etc, cada qual com seus conhecimentos tácitos, preferências etc. Linguagens são como círculos sociais, elas possuem uma cultura, uma essência, algo que não se “quebra”, intangível. Ou seja, se eu adoro a forma com que Ruby faz alguma coisa, não devo achar que o PHP é defasado por conta disso, ou que ele deveria fazer da mesma forma. São culturas diferentes, formas de aplicar e pensar diferentes. E toda pluralidade é positiva.

“Mas o PHP não é uma linguagem orientada a objetos…”

Realmente, o PHP não é uma linguagem orientada a objetos, ele implementa o paradigma de orientação a objetos. O PHP é multiparadigma. Não existe demérito algum nisso. Não é o fato de uma linguagem ser (em essência) orientada a objetos que a faz ser a solução para todos os problemas. Por exemplo, atualmente é notório um movimento e uma grande adoção por linguagens funcionais.

A implementação de orientação a objetos no PHP é robusta e esse paradigma é o mais utilizado em todos os principais frameworks dele provindos.

Por que aprender PHP é um grande negócio?

Abaixo alguns motivos que eu considero relevantes mas que, claro, devem ser alinhados com os objetivos do seu projeto, a equipe que trabalhará nele etc.

1). É a linguagem mais utilizada para web, cerca de ~82% de todos os sites a utilizam:

2). Ela foi desenvolvida para a Web (isso é um fator de vantagem e competitividade para se manter no topo entre mais utilizadas);

Isso pode ser observado no corpo do anúncio da primeira versão do PHP, postado em Junho de 1995 no repositório Usenet newsgroup:

From: rasmus@io.org (Rasmus Lerdorf) 
Subject: Announce: Personal Home Page Tools
Date: 1995/06/08
Message-ID: <3r7pgp$aal@ionews.io.org>#1/1 
organization: none
newsgroups: comp.infosystems.www.authoring.cgi

Announcing the Personal Home Page Tools (PHP Tools) version 1.0.

These tools are a set of small tight cgi binaries written in C. They perform a number of functions including:

. Logging accesses to your pages in your own private log files
. Real-time viewing of log information
. Providing a nice interface to this log information.
. Displaying last access information right on your pages.
. Full daily and total access counters
. Banning access to users based on their domain
. Password protecting pages based on users' domains
. Tracking accesses ** based on users' e-mail addresses **
. Tracking referring URL' s - HTTP_REFERER support
. Performing server-side includes without needing server support for it
. Ability to not log accesses from certain domains (ie. your own)
. Easily create and display forms
. Ability to use form information in following documents

Here is what you don't need to use these tools:

. You do not need root access - install in your ~/public_html dir
. You do not need server-side includes enabled in your server
. You do not need access to Perl or Tcl or any other script interpreter . You do not need access to the httpd log files

The only requirement for these tools to work is that you have the ability to execute your own cgi programs. Ask your system administrator if you are not sure what this means.

The tools also allow you to implement a guestbook or any other form that needs to write information and display it to users later in about 2 minutes.

The tools are in the public domain distributed under the GNU Public License. Yes, that means they are free!

For a complete demonstration of these tools, point your browser at: http://www.io.org/~rasmus

- -
Rasmus Lerdorf
rasmus@io.org
http://www.io.org/-rasmus

3). O suporte à linguagem é constante. Todo ano teremos uma nova minor version até a chegada de alguma nova major version.

Pode ser que demore um pouco menos ou um pouco mais de um ano, tudo vai depender da estabilidade das alterações. Mas essa é a ideia principal. E para cada nova minor version, têm-se dois anos de suporte (bugs e segurança).

O panorama atual das versões do PHP e o suporte concedido a elas:

4). O PHP possui um maduro e completo ecossistema para gerenciamento de dependências (com Composer e Packagist).

Hoje, isso é requisito de análise para a escolha de uma linguagem. Um gerenciador de dependências é parte fundamental para o desenvolvimento e manutenção dos projetos.

O Composer (o gerenciador de dependências), nascido em 2011, mudou completamente a forma de se desenvolver com PHP. Eu separo a história do PHP em:

  • Pré-Composer
  • Pós-Composer

O Packagist é o repositório oficial do Composer. números dele do dia 13/04/2012 até 03/04/2017:

Pacotes registrados Versões disponíveis Pacotes instalados
134.508 804.269 4.264.652,569

5). O PHP é amplamente documentado na Web

Há documentação, artigos, dicas, discussões, fóruns, recursos etc. O PHP não nasceu “hoje”. Muitos problemas com suas soluções estão disponíveis na Web, muitos deles no Github.

6). O PHP possui excelentes e estabelecidos frameworks.

Alguns dos maiores expoentes do mercado e que estão andando junto com a evolução da linguagem:

  • Laravel 5
  • Symfony 3 (Em breve Symfony 4)
  • Zend Framework 3
  • Zend Expresive 2
  • CakePHP 3
  • Silex 2
  • Slim 3
  • CodeIgniter 3

O Symfony, Laravel e Zend Framework elevaram o nível do desenvolvimento com PHP. Há cases de aplicações com milhares de requisições por segundo e que utilizam algum desses frameworks.

Qual o real objetivo aqui?

O meu interesse não é afirmar que o PHP é a melhor linguagem, muito menos sugerir que você pare tudo e comece a estudá-lo. Essa ideia de “melhor linguagem” cai muito no terreno da “relatividade”. A melhor é que resolve o problema do seu projeto e que a sua equipe consegue trabalhar bem com ela.

Algo muito importante que devemos ter em mente é:

Uma linguagem de programação deve ser tratada como o “meio” para resolver um problema, não o “fim”.

Isso quer dizer que, não importa que linguagem você venha a escolher, desde que ela consiga entregar o valor final do seu produto. A escolha de uma linguagem / plataforma, principalmente em um ambiente corporativo, em um grande projeto, se passa por muitas decisões que vão além da nossa opinião e gosto pessoal.

A ideia aqui foi expor alguns pontos sobre PHP, que por muitas vezes é motivo de brincadeiras (o que é engraçado, eu me divirto às vezes haha) e até mesmo de julgamentos injustos.

Ah, claro, apesar disso tudo, sim, sou um “discípulo” da linguagem e eu fico muito contente quando as pessoas dão uma oportunidade de conhecê-la com mais intimidade.

Quer aprender PHP do “zero”? Os nossos módulos base podem te ajudar com isso:

Um abraço e até a próxima!

Complexidade ciclomática, análise estática e refatoração

Complexidade ciclomática é uma métrica do campo da engenharia de software, desenvolvida por Thomas J. McCabe em 1976, e serve para mensurar a complexidade de um determinado módulo (uma classe, um método, uma função etc), a partir da contagem do número de caminhos independentes que ele pode executar até o seu fim. Um caminho independente é aquele que apresenta pelo menos uma nova condição (possibilidade de desvio de fluxo) ou um novo conjunto de comandos a serem executados.

As métricas de software podem ser definidas como métodos de determinar quantitativamente a extensão em que o projeto, o processo e o produto de software têm certos atributos. Isto inclui a fórmula para determinar o valor da métrica como também sua forma de apresentação e as diretrizes de utilização e interpretação dos resultados obtidos no contexto do ambiente de desenvolvimento de software. FERNANDES, A. A. (1995) – Gerência de Software através de métricas, São Paulo, Editora Atlas.

O resultado da complexidade ciclomática indica quantos testes (pelo menos) precisam ser executados para que se verifique todos os fluxos possíveis que o código pode tomar, a fim de garantir uma completa cobertura de testes.

Calculando a complexidade ciclomática

Existem diferentes formas de se calcular:

  • Usando a notação de um grafo de fluxo;
  • Usando fluxograma;
  • Com análise estática do código, usando uma ferramenta que automatize essa tarefa.

Tendo um grafo de fluxo ou um fluxograma, temos três fórmulas equivalentes para se mensurar a complexidade ciclomática:

  1. V(G) = R – onde R é o número de regiões do grafo de fluxo.
  2. V(G) = E – N + 2 – onde E é o número de arestas (setas) e N é o número de nós do grafo G.
  3. V(G) = P + 1 – onde P é o número de nós-predicados contidos no grafo G (só funciona se os nós-predicado tiverem no máximo duas arestas saindo.)

Ps: Nós-predicado são àqueles que podem desviar o fluxo da execução: if, while, switch etc.

Exemplo usando a notação de grafo de fluxo:

alt

Exemplo retirado do trabalho da professora Bianca Zadrozny (do Instituto de Computação da UFF), que pode ser consultado aqui como excelente referência.

A complexidade ciclomática desse código é 6. Esse resultado pode ser obtido usando uma das três formas acima descritas:

1) V(G) = R – onde R é o número de regiões do grafo de fluxo.

alt

Temos 6 regiões.

2) V(G) = E – N + 2 – onde E é o número de arestas (setas) e N é o número de nós do grafo G.

V(G) = 17 arestas/setas – 13 nós + 2 = 6

3) V(G) = P + 1 – onde P é o número de nós-predicados contidos no grafo G.

V(G) = 5 nós-predicados + 1 = 6

No final temos, então, 6 caminhos independentes. Com isso, sabemos que precisamos ter uma gama de pelo menos 6 testes para garantir uma boa cobertura para esse código.

Os seis caminhos independentes são:

  • 1) 1-2-10-12-13
  • 2) 1-2-10-11-13
  • 3) 1-2-3-10-11-13
  • 4) 1-2-3-4-5-8-9-2-[…]
  • 5) 1-2-3-4-5-6-8-9-2-[…]
  • 6) 1-2-3-4-5-6-7-8-9-2-[…]

Você pode traçar mentalmente um a um. Por exemplo, o primeiro caminho:

  • 1-2-10-12-13

alt

Com os caminhos definidos, você pode planejar os casos de teste para cada um deles.

Ferramentas para análise estática

Essa é, claro, a mais produtiva forma: usar um analisador estático. Dentre as várias vantagens, temos:

  • Precisão;
  • Possibilidade de incluir a análise na integração contínua;
  • Geração de relatórios da evolução das métricas;

Existem várias ferramentas, você pode pesquisar sobre “análise estática” na linguagem que você utiliza em seus projetos, certamente encontrará várias opções (com focos variados).

Uma ferramenta bastante utilizada é a Sonar. Ela suporta mais de 25 linguagens. Tem a premissa de avaliar “débito de código” (o “preço” que se paga no futuro por algo que foi implementado no presente sem se preocupar tanto com a qualidade).

Se você desenvolve em PHP, escrevi um artigo sobre Ferramenta para avaliar a complexidade de código escrito em PHP.

Se você desenvolve em .NET temos:

  • ReSharper (Oferece muito mais que só análise estática)
  • ndepend (Tem um foco maior nas relações entre os objetos, acoplamento etc)

Quais os parâmetros aceitáveis para a complexidade dos meus métodos?

De acordo com o trabalho de McCabe, os valores de referência são:

Complexidade Avaliação
1-10 Método simples. Baixo risco.
11-20 Método razoavelmente complexo. Moderado risco.
21-50 Método muito complexo. Elevado risco.
51-N Método de altíssimo risco e bastante instável.

Esses são apenas valores de referência. O fato de um método ter baixa complexidade não quer dizer que ele não pode ser melhorado ou até mesmo refatorado. Essa é a parte relativa da “coisa”. Caberá a você e a sua equipe identificar esses pontos.

Como posso melhorar os meus códigos?

Um código com baixa complexidade ciclomática não necessariamente já esgotou todas as possibilidades de melhorias. Há um conjunto de fatores envolvidos. Mas, em termos gerais, refatorar é a melhor “ferramenta” para se ter um código melhor autodocumentado e com menos complexidade.

Nem sempre conseguimos de “prima” acertar em cheio naquilo que desenvolvemos. Para preencher essa lacuna, existe a refatoração: melhorar a compreensão do código existente (sem alterar o seu comportamento).

Martin Fowler criou um catálogo com algumas técnicas de refatoração. Elas são focadas em se ter um código autodocumentado (expressivo, de fácil leitura, coeso etc).

Algumas das principais técnicas descritas:

Substituir recursividade por iteração: O código recursivo é difícil de entender e na maioria dos casos pode ser substituído por iteração. A não ser que se tenha um objetivo muito bem definido para a existência da recursão (para se ter algum expressivo ganho em performance; ou se você está trabalhando com uma operação muito complexa com árvores binárias etc).

Exemplo (baseado no do catálogo):

public void countDown(int n) {
    if(n == 0) return;

    System.out.println(n + "...");
    waitASecond();
    countDown(n-1);
}

Poderia ser escrito assim:

public void countDown(int n) {
    while(n > 0) {
        System.out.println(n + "...");
        waitASecond();
        n -= 1;
    }
}

Decompor condicional: Quando se têm uma estrutura condicional muito complicada com diversos if-elseif-else, pode-se extrair métodos dos resultados dessas condições e invocá-los.

Exemplo (baseado no do catálogo):

if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
    charge = quantity * _winterRate + _winterServiceCharge;
} else {
    charge = quantity * _summerRate;
}

Poderia ser decomposto para:

if (notSummer(date)) {
  charge = winterCharge(quantity);
} else {
  charge = summerCharge(quantity);
}

Substituir ninhos de condicionais por cláusulas de proteção: Para tirar a complexidade do entendimento do caminho de execução.

Exemplo (baseado no do catálogo):

double getPayAmount() {
  double result;
  if (_isDead) result = deadAmount();
  else {
    if (_isSeparated) result = separatedAmount();
    else {
      if (_isRetired) result = retiredAmount();
      else result = normalPayAmount();
    };
  }
  return result;
};

Poderia ser escrito assim:

double getPayAmount() {
  if (_isDead) return deadAmount();
  if (_isSeparated) return separatedAmount();
  if (_isRetired) return retiredAmount();
  return normalPayAmount();
};

Substituir condicional por polimorfismo: Tendo um comando condicional que a partir do tipo de objeto escolhe diferentes comportamentos, você pode tornar o método original abstrato e mover essas condicionais para suas próprias subclasses.

Exemplo retirado do catálogo:

class Bird {
  //...
  double getSpeed() {
    switch (type) {
      case EUROPEAN:
        return getBaseSpeed();
      case AFRICAN:
        return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
      case NORWEGIAN_BLUE:
        return (isNailed) ? 0 : getBaseSpeed(voltage);
    }
    throw new RuntimeException("Should be unreachable");
  }
}

Poderia ser descomposto para:

abstract class Bird {
  //...
  abstract double getSpeed();
}

class European extends Bird {
  double getSpeed() {
    return getBaseSpeed();
  }
}

class African extends Bird {
  double getSpeed() {
    return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
  }
}

class NorwegianBlue extends Bird {
  double getSpeed() {
    return (isNailed) ? 0 : getBaseSpeed(voltage);
  }
}

// Somewhere in client code
speed = bird.getSpeed();

Outras técnicas com exemplos aplicados, você pode consultar aqui.

Focar na qualidade do meu software ou na entrega?

Ideologicamente falando, o processo de refatorar é contínuo. O software vai crescer, precisará ser “tocado” e a refatoração andará lado a lado a tudo isso. Não existe código perfeito, não existe código “à prova de bala”, mas é possível ter código coeso, fácil de ser lido e o principal: fácil de ser testado.

Aliar entrega (o resultado final, o que interessa para a empresa) com qualidade de software é uma questão ampla e complexa. Sabemos que, na maioria das vezes, a realidade é essa: pressão para que as entregas aconteçam o mais rápido possível. Quase nunca entra na análise de tempo e custo o que será gasto para cuidar da qualidade/análise do código. O foco é quase sempre nas entregas e, pensando no lado “corporativo”, elas são extremamente importantes para manter a competitividade da empresa e isso não pode ser ignorado, mas também tem o lado negativo, que é o débito de código (o custo e o tempo que será gasto no futuro para implementar algo novo ou corrigir uma implementação).

Não tem “receita de bolo”, não tem manual, a equipe precisa aprender a mensurar todas essas nuances e achar um “meio termo”. Não dá pra julgar essa guerra de interesses, todos têm seus motivos e suas justificativas.

Outro ponto interessante de reflexão: Não, ninguém usa todas as “melhores técnicas” de codificação (e isso é muito relativo). “Código impecável” e que usa as “melhores técnicas” etc, quase sempre é apenas case para palestrantes, professores e artigos (como este aqui). No entanto, isso não tira e nem invalida o fato de que, como desenvolvedores, podemos evoluir, podemos encontrar novas formas e novos conceitos de pensar no “todo” que envolve o desenvolvimento de software. E essa responsabilidade é nossa, não sendo possível delegá-la.

Concluindo

Os temas aqui introduzidos são vastos. A ideia não foi a de esgotar os assuntos (e isso nem seria possível), o objetivo principal foi o de acender àquela “chama” que carregamos em nós: àquela que alimenta o nosso amor e interesse pelo desenvolvimento de software. Temos de mantê-la acesa, estudando coisas novas e buscando um conhecimento multimodal.

Até a próxima!

Ferramenta para avaliar a complexidade de código escrito em PHP

Recentemente o Taylor Otwell (criador do Laravel Framework) publicou um artigo avaliando a complexidade de código dos principais frameworks utilizados em PHP. Ele decidiu simplificar e colocar na análise apenas as seguintes informações/métricas:

  • Quantidade de linhas de código.
  • Método mais longo (em número de linhas).
  • Média da complexidade dos métodos.
  • Máxima complexidade de um método.
  • Porcentagem de métodos não estáticos.

Essa última métrica é importante (especialmente) para Frameworks, pois há uma relação direta entre baixa testabilidade e métodos estáticos (quanto ao uso indiscriminado). Portanto, em teoria, quanto menos métodos estáticos, mais facilmente “testável” é o “todo”.

A ferramenta utilizada por ele para gerar o relatório foi a phploc do Sebastian Bergmann (criador do PHPUnit).

phploc

A instalação da phploc se dá pelo Composer, numa instalação global, de tal forma que o binário da ferramenta fique disponível no caminho de busca do SO.

Como pré-requisitos, você precisa ter o PHP e o Composer instalados (e no caminho de busca global). Se você tiver alguma dúvida sobre como proceder com a instalação do Composer, verifique aqui.

Instalando a ferramenta

No terminal (ou CMD, se você estiver no Windows), execute:

composer global require 'phploc/phploc=*'

Finalizado, tudo o que você precisa fazer é navegar até a pasta do projeto que você quer gerar o relatório e executar:

phploc ./folder

Para que possamos aqui visualizar a saída da execução da ferramenta, vamos clonar o core do Laravel e executá-la na pasta do componente Database.

Para isso, no diretório padrão onde você tem os seus projetos PHP (ou em outro, se preferir), execute:

composer require laravel/framework

Isso vai criar uma pasta chamada framework. Para executar a análise somente no componente Database, primeiro navegue até essa pasta e em seguida execute:

phploc src/Illuminate/Database/

Veja:

alt

Esse foi o relatório gerado:

Directories                                         16
Files                                              107

Size
  Lines of Code (LOC)                            26752
  Comment Lines of Code (CLOC)                   12193 (45.58%)
  Non-Comment Lines of Code (NCLOC)              14559 (54.42%)
  Logical Lines of Code (LLOC)                    3884 (14.52%)
    Classes                                       3450 (88.83%)
      Average Class Length                          32
        Minimum Class Length                         0
        Maximum Class Length                       345
      Average Method Length                          1
        Minimum Method Length                        0
        Maximum Method Length                       12
    Functions                                        0 (0.00%)
      Average Function Length                        0
    Not in classes or functions                    434 (11.17%)

Cyclomatic Complexity
  Average Complexity per LLOC                     0.24
  Average Complexity per Class                    9.88
    Minimum Class Complexity                      1.00
    Maximum Class Complexity                    104.00
  Average Complexity per Method                   1.61
    Minimum Method Complexity                     1.00
    Maximum Method Complexity                    17.00

Dependencies
  Global Accesses                                   10
    Global Constants                                10 (100.00%)
    Global Variables                                 0 (0.00%)
    Super-Global Variables                           0 (0.00%)
  Attribute Accesses                              1374
    Non-Static                                    1317 (95.85%)
    Static                                          57 (4.15%)
  Method Calls                                    2606
    Non-Static                                    2407 (92.36%)
    Static                                         199 (7.64%)

Structure
  Namespaces                                        17
  Interfaces                                         5
  Traits                                            13
  Classes                                           89
    Abstract Classes                                 9 (10.11%)
    Concrete Classes                                80 (89.89%)
  Methods                                         1566
    Scope
      Non-Static Methods                          1496 (95.53%)
      Static Methods                                70 (4.47%)
    Visibility
      Public Methods                              1037 (66.22%)
      Non-Public Methods                           529 (33.78%)
  Functions                                        119
    Named Functions                                  0 (0.00%)
    Anonymous Functions                            119 (100.00%)
  Constants                                          5
    Global Constants                                 3 (60.00%)
    Class Constants                                  2 (40.00%)

Como você pôde observar, avalia-se muito mais do que só o que introduzimos no começo desse post, como a quantidade de:

  • Linhas de código;
  • Diretórios;
  • Classes concretas;
  • Classes abstratas;
  • Interfaces;
  • Traits;
  • Métodos estáticos;
  • Funções;
  • Etc.

A ferramenta também a avalia a complexidade ciclomática média das classes e métodos.

Em futuros artigos veremos sobre teorias de teste de software e métricas para medição da qualidade de código.

Até a próxima!

JUNTE-SE A MAIS DE 150.000 PROGRAMADORES