[Pesquisar este blog]

segunda-feira, 15 de maio de 2017

Os Princípios SOLID::ISP (parte V)

Parte I | Parte II | Parte III | Parte IV  | Parte V | Parte VI
Os princípios de projeto e programação orientada a objetos enunciados por Martin em 1995, depois denominados como SOLID, são um importante guia para orientação tanto a construção de sistemas fáceis de manter, como para reorganizar (refactor) código existente, além de serem consistentes com para desenvolvimento de software.


Os cinco princípios que formam o acrônimo SOLID:
  • Single Responsability Principle
  • Open-Closed Principle
  • Liskov's Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

Nos post anteriores foram tratados os princípios da responsabilidade única (SRP), do aberto-fechado (OCP) e da substituição de Liskov (LSP). Neste artigo falaremos sobre o Princípio da Segregação de Interfaces (ISP).

ISP::Interface Segregation Principle

Não dependa daquilo que você não necessita!
O Princípio da Segregação da Interface ou Interface Segregation Principle, aqui referido apenas como ISP, afirma que é preferível dispor de muitas interfaces de programação de cliente específicas do que uma única interface de programação de cliente de propósito geral.

Entende-se como interface de programação de cliente o conjunto de operações que um interface especifica, as quais deverão ser implementadas (ou realizadas) por uma ou mais classes. Abaixo temos uma interface Java denominada IVeiculo, dotada de três operações, todas implicitamente públicas e abstratas.

public interface IVeiculo {
    int getNumeroMaximoOcupantes();
    int getNumeroAtualOcupantes();
    void setNumeroOcupantes(int ocupantes);
}

Para que esta interface seja útil, a mesma deverá ser implementada por uma classe, isto é, um classe pode optar por realizar esta interface, substituindo todos os métodos presentes na interface, como no outro exemplo que segue:

public classe MeuVeiculo implements IVeiculo {
    public static final int MAX_OCUP = 5;
    public int nOcupantes = 0;
    public int getNumeroMaximoOcupantes() {
        return MAX_OCUP;
    }
    public int getNumeroAtualOcupantes() {
        return nOcupantes;
    }
    public void setNumeroOcupantes(int ocupantes) {
        if (ocupantes<0 || ocupantes>MAX_OCUP) {
            throw new RuntimeException("número ocupantes inválido");
        }
        nOcupantes = ocupantes;
    }
}

Neste caso, a classe concreta MeuVeiculo só necessitou implementar três métodos para realizar aqueles especificados pela interface IVeiculo, “contratada” na sua declaração. Espera-se que todos estes métodos sejam, de fato, úteis nesta implementação.

É este o foco do ISP: os clientes (as classes concretas que implementam interfaces) não devem ser forçados a depender de funcionalidades das quais não necessitam, ou seja, uma classe que realiza uma interface não deveria implementar métodos sem necessidade. Assim, ao invés de classes e interfaces complexas, e com numerosas operações, este princípio direciona para a construção de múltiplos elementos menores e mais coesos.

Esta pode ser a situação de uma interface dotada de muitas operações, que, em geral, criará a necessidade da construção de classes clientes dotadas das implementações de tais métodos. 

Classes complexas, com muitas operações, são inevitáveis em algumas situações, mas é igualmente comum que seus clientes utilizem apenas um subconjunto de suas funcionalidades. Mesmo que indiretamente, tais clientes dependem de funcionalidades que eles não utilizam, assim fica a questão: o que acontece se tais classes complexas mudam?

Considere um caixa eletrônico bancário (Automatic Teller Machine - ATM), em cuja tela são exibidas múltiplas mensagens conforme as operações executadas. A não aplicação de SRP, OCP e LSP podem levar a criação de uma interface como a que segue, com muitas operações!

public interface ATMMessenger {
    void askForCard();
    void tellInvalidCard();
    void askForPin();
    void tellInvalidPin();
    :
    void askForWithdrawAmount();
    void tellInsuficientBalance();
    void tellBalance();
    :
    void tellAmountDeposited();
}

Ao acrescentar uma nova operação nesta interface, muitas classes cliente deverão ser modificadas e recompiladas. Mas isto seria necessário?

A separação de uma interface complexa (de propósito geral) em muitas interfaces específicas simplifica o problema. Esta separação é o que se denomina segregação no ISP. Como no exemplo que segue:

public interface LoginMessenger {
    void askForCard();
    void tellInvalidCard();
    void askForPin();
    void tellInvalidPin();
}
public interface WithDrawMessenger {
    void askForWithdrawAmount();
    void askForFeeConfirmation();
    void tellInsuficientBalance();
    void tellBalance();
}

Nesta nova situação, de interfaces com maior foco e menos operações, a adição de uma operação nova reduz o escopo de alterações às classes que efetivamente implementam tais funcionalidades. Ou seja, somente aquelas que dependem das funcionalidades da interface modificada.

Observe abaixo a comparação entre as implementações hipotéticas de uma única e grande interface geral em relação à realização de interfaces específicas, ainda considerando o exemplo do caixa eletrônico bancário.


Conclusões

O esforço da divisão de uma interface complexa, com muitos métodos, em várias interfaces menores, com grupos melhor correlacionados de operações, simplifica tanto a construção do código como sua manutenção.

Na construção torna-se possível selecionar e implementar apenas as interfaces necessárias, reduzindo-se o esforço de codificação. Se todas as interfaces são necessárias, a divisão não causa qualquer problema (não requer mais código ou qualquer manobra especial). Na manutenção, a alteração de interfaces menores causa menor impacto no código, o que é um grande benefício.

Fica claro que é melhor não depender das coisas das quais não se necessita.

Assim, a garantia do ISP leva a:
  • Baixo acoplamento e alta coesão;
  • Promoção do projeto ortogonal (ortogonalidade do projeto) onde:
    • Módulos centrados em sua necessidade (SRP) e
    • Dependências reduzidas entre eles (LSP e ISP).


Para Saber Mais

  • LARMAN, Craig. Utilizando UML e padrões: uma introdução à análise e ao projeto orientados à objetos e ao Processo Unificado. Porto Alegre: Bookman, 2007.
  • MARTIN, R. C.; et. al. Clean Code: a handbook of agile software craftsmanship. Boston: Pearson Education, 2009.
  • MARTIN, R. C. The Clean Coder. Upper Sadle River: Prentice-Hall, 2011.
  • MARTIN, R. C. Principles of OOD. Disponível em http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod, recuperado em 17/02/2017.
  • MARTIN, R. C. Get a SOLID start. Disponível em http://objectmentor.com, recuperado em 17/02/2017.
  • PAGE-JONES, Meilir. Fundamentos do Desenho Orientado a Objetos. São Paulo: Makron Books, 2001.
  • SOMMERVILLE, I. Software Engineering. 9th. Ed. Boston: Addison-Wesley, 2011.

domingo, 7 de maio de 2017

Os Princípios SOLID::LSP (parte IV)

Parte I | Parte II | Parte III | Parte IV | Parte V | Parte VI
Os princípios SOLID, organizados por Robert C. Martin, constituem um conjunto consistente de diretrizes para o projeto e programação orientada a objetos que pretendem auxiliar os projetistas de software, além dos programadores, na construção de sistemas estruturados para que sejam mais fáceis de manter e de ampliar com o passar do tempo.
O desenvolvimento de software é uma atividade inerentemente complexa, assim os custos relacionados a construção de sistemas grandes são usualmente altos. Torna-se imperativo, então, projetar sistemas que, além de agregar valor, possam ser utilizados por muito tempo, como única forma de compensar o investimento em sua construção. Assim, o projeto de um software deve se preocupar não apenas com as funcionalidades requeridas, mas também na sua manutenção e ampliação, evitando que seu envelhecimento dificulte ou impeça sua utilização.

Os princípios enunciados por Martin contém recomendações importantes que devem ser consideradas na construção; mas também são um guia para refatoração do código, além de se enquadrarem nas estratégias ágeis de construção de software.

Como visto, são cinco os princípios que formam o acrônimo SOLID:
·      Single Responsability Principle
·      Open-Closed Principle
·      Liskov's Substitution Principle
·      Interface Segregation Principle
·      Dependency Inversion Principle

Neste post será abordado o LSP ou Princípio da Substituição de Liskov.

LSP::Liskov's Substitution Principle

Os tipos derivados devem ser completamente substituíveis por seus tipos base.
O Liskov's Substitution Principle ou Princípio da Substituição de Liskov ou apenas LSP foi proposto por Barbara Liskov (e outros) em 1981, preocupando-se com as questões de abstração e manutenabilidade do software. Este princípio é formalmente enunciado como:
"Se para cada objeto o1 do tipo S existe um objeto o2 do tipo T tal que para todos os programas P definidos em termos de T, o comportamento de P é inalterado quando o1 é substituído por o2, então S é um subtipo de T."
Esta definição é mais simples do que parece. Considere um programa que utiliza um objeto o1 de um tipo determinado, por exemplo da classe S. Também considere um outro objeto o2, mas da classe T, sendo que S é uma subclasse de T (portanto T é um supertipo de S). A figura abaixo ilustra esta situação. O LSP significa que o programa deve funcionar corretamente quando o objeto o1 é substituído pelo objeto o2, pois este objeto o2 é um supertipo de o1.
Quando se afirma que o programa continua a funcionar corretamente, ou seja, que seu comportamento não se altera, não está se afirmando que os resultados produzidos por um objeto de um tipo sejam iguais aos produzidos por outros de suas subclasses, mas espera-se que as mesmas operações estejam disponíveis e que os resultados sejam do mesmo tipo.

Por isso o LSP também é conhecido como princípio da conformidade de tipo:
"Se S é um real subtipo de T, então S deve se conformar a T. Em outras palavras, um objeto de tipo S pode ser provido em qualquer contexto no qual um objeto do tipo T seja esperado, e a exatidão ainda será preservada quando qualquer operação de acesso do objeto for executada." (PAGE-JONES, 2001, pg.286)
Assim, num projeto orientado a objeto adequado e consistente, o tipo de cada classe deverá se conformar com o tipo de sua superclasse, de maneira que hierarquias de classes devem seguir este princípio, permitindo que o polimorfismo seja usado com comodidade e precisão. Assim sendo, as dependências do cliente em relação a classe podem ser substituídas por suas subclasses, sem que o cliente saiba da mudança.

O projeto de hierarquias de classes onde é garantido que as subclasses operem da mesma maneira que suas superclasses, isto é, funcionalidade diferente, mas dentro do comportamento esperado, é conhecida também como projeto por contrato (design by contract). Neste sentido a relação típica é um/is a que identifica as relações de herança deve ser repensada como é substituível por/is substitute for.

Um Exemplo

Considere como pode ser modelada a relação existente entre quadrados e retângulos; tal como círculos e elipses. A geometria euclidiana afirma que um todo quadrado é um retângulo; assim como os círculos são elipses. Do ponto de vista da programação orientada a objetos, como a pergunta "é do tipo?" é respondida satisfatoriamente, identificam-se relações típicas de herança entre retângulos (supertipo) e quadrado (subtipo), assim como elipses (supertipo) e círculos (subtipo), como ilustra a figura que segue.
Aqui existe uma situação que merece atenção. Se uma instância de Retangulo for substituída por uma instância de Quadrado, o programa poderá falhar se for esperado que a altura e largura variem livremente, pois no caso do Quadrado, existe uma invariante que altura=largura. A substituição inversa (um objeto Quadrado substituído por outro Retangulo) pode causar problemas pela mesma razão, se esperado que as dimensões sejam mantidas iguais. Nesta situação temos uma violação do LSP, pois o código se comporta diferentemente do que foi estabelecido pela geometria.

Tornar as classes imutáveis, de maneira que novos objetos consistentes sejam "fabricados" por demanda, é uma solução possível, como ilustrado pelas interfaces seguem.

public interface Retangulo {
    double getLargura();
    double getAltura();
    Retangulo comAltura(double a);
    Retangulo comLargura(double l);
}
public interface Quadrado extends Retangulo {
    Quadrado comTamanho(double t);
}

O mesmo problema não ocorreria com uma implementação típica de Elipse e Circulo, pois o comportamento do código permitiria respeitar as definições geométricas.

O exemplo enfatiza que um violação do LSP causa, geralmente, comportamento indefinido, principalmente quando a substituição é dinâmica. A dificuldade reside no fato de funcionar durante o desenvolvimento, mas provocar bugs aleatórios durante a produção.

Conclusões

O Princípio da Substituição de Liskov destaca que a validade de um modelo não é intrínseca e que depende de sua inserção e coerência com o contexto do cliente. Além disso, o comportamento de objetos de uma hierarquia deve ser o mesmo: um quadrado é um retângulo geometricamente, mas não se comporta como um! Já círculos e elipses exibem o mesmo comportamento! Então, concluímos que na orientação a objetos, a relação de herança pertence ao comportamento público dos objetos.

O cumprimento deste princípio requer atenção no projeto de hierarquias de classes usadas como substituições dinâmicas. Seu atendimento ajudar evitar: 
  • Comportamento indefinido decorrente de substituições entre supertipos e subtipos;
  • Esforço desproporcional para detecção e correção dos problemas decorrentes;
  • Problemas de fragilidade e rigidez!

Para Saber Mais


  • LARMAN, Craig. Utilizando UML e padrões: uma introdução à análise e ao projeto orientados à objetos e ao Processo Unificado. Porto Alegre: Bookman, 2007.
  • MARTIN, R. C.; et. al. Clean Code: a handbook of agile software craftsmanship. Boston: Pearson Education, 2009.
  • MARTIN, R. C. The Clean Coder. Upper Sadle River: Prentice-Hall, 2011.
  • MARTIN, R. C. Principles of OOD. Disponível em http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod, recuperado em 17/02/2017.
  • MARTIN, R. C. Get a SOLID start. Disponível em http://objectmentor.com, recuperado em 17/02/2017.
  • PAGE-JONES, Meilir. Fundamentos do Desenho Orientado a Objetos. São Paulo: Makron Books, 2001.
  • SOMMERVILLE, I. Software Engineering. 9th. Ed. Boston: Addison-Wesley, 2011.

terça-feira, 2 de maio de 2017

Os Princípios SOLID::OCP (parte III)

Parte I | Parte II | Parte III | Parte IV | Parte V | Parte VI
Como visto nos post anteriores, os princípios de projeto e programação conhecidos como SOLID têm como objetivo orientar nas atividades de projeto e desenvolvimento de sistemas que possam exibir um longo ciclo de vida, ou seja, além de funcionarem adequadamente tais sistemas devem ser fáceis de manter e de ampliar. Além disso, estes princípios também devem auxiliar nas abordagens ágeis de construção de software.


São cinco os princípios que formam o acrônimo SOLID:
  • Single Responsability Principle
  • Open-Closed Principle
  • Liskov`s Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle
Neste post será abordado o OCP ou Princípio aberto-fechado.

OCP::Open-Closed Principle

Módulos devem ser abertos para extensão, mas fechados para modificação.
O Open-Closed Principle ou Princípio aberto-fechado ou apenas OCP foi inicialmente proposto por Bertrand Meyer, em 1998, e indica que qualquer classe, módulo ou componente de software deveria ser construído de maneira que possa ser usado como base a criação de outros por meio dos mecanismos de extensão disponíveis (p.e., a herança na programação orientada a objetos); ao mesmo tempo restringindo e limitando as possibilidades de sua alteração direta.

A essência do OCP é a capacidade de estender o comportamento ou o funcionamento de um módulo sem que seja necessária sua modificação. Assim o projeto de uma classe é feito de modo que novas funcionalidades possam ser adicionadas, à medida em apareçam novos requisitos, mas exclusivamente por meio da extensão da própria classe (aberto para extensão). Assim, uma vez criada, a classe nunca deve ser modificada, exceto para correções nas funcionalidades existentes, isto é, que estavam presentes na sua origem (fechado para modificação).

As classes devem, portanto, ser projetadas de tal maneira que, quando surgem demandas para a modificação seu funcionamento (fluxo de controle ou comportamento), tudo que é requerido é a criação uma subclasse na qual sejam substituídas as operações adequadas. Para isto se combinam os mecanismos da herança (vista como especialização de um tipo) e de substituição de métodos (method override).

A figura que segue ilustra uma situação não aderente ao OCP, que pode ser denominada de cliente fechado. 


Uma classe é um cliente (Client) quando se utiliza de funcionalidades presentes em outra classe, aqui denominada servidora (Server). Se for necessário trocar o Server, a classe Client também deverá ser alterada, o que é, claramente um inconveniente.

Outra situação, bastante distinta, é ilustrada abaixo.


A classe cliente (Client) utiliza-se de uma classe denominada AbstractServer, que serve de base para a construção de uma classe servidora (Server) específica. Esta situação, denominada cliente aberto é aderente ao OCP, pois: a troca de Server não afeta a classe Client; além do fato de que AbstractServer poderia atender outros clientes distintos de Server.

Uma implementação-conceito de AbstractServer poderia ser como na classe Java de mesmo nome. As operações abstratas poderiam existir em qualquer número e com qualquer assinatura e tipo de retorno.

public abstract class AbstractServer {
  public abstract void operacao1();
  public abstract void operacao2();
}

Uma classe-concreta para Server poderia ser como:

public class Server extends AbstractServer {
  public Server() {
    System.out.println("Server<init>");
  }
  @Override
  public void operacao1() {
    // implementação específica
    System.out.println("Server.operacao1()");
  }
  @Override
  public void operacao2() {
    // implementação específica
    System.out.println("Server.operacao2()");
  }
}

Note que poderiam existir diferentes implementações de AbstractServer, cada uma contendo as especificidades necessárias a cada tipo de cliente ou grupo de clientes.
Uma fábrica, como ServerFactory, poderia prover instâncias de uma implementação selecionada para os clientes.

public final classe ServerFactory {
  public static AbstractServer createServer() {
    System.out.println("AbstractServer.CreateServer()");
    return new Server();
  }
}

Assim, qualquer cliente, como Client, poderia utilizar implementações concretas de AbstractServer, sem conhecer diretamente tais classes, obtendo as instâncias necessárias da fábrica ServerFactory.

public class Client {
  public static void main(String args[]) {
   AbstractServer server = ServerFactory.createServer();
   server.operacao1();
   server.operacao2(); 
}



Este princípio só é, de fato, útil, quando uma mudança se apresenta como necessária. Assim, uma recomendação válida é: num primeiro momento, codifique da maneira mais simples possível; e, quando surgir a necessidade de modificação, construa uma abstração que o proteja de modificações similares no futuro.

Segundo R. Martin, devemos manter as coisas que mudam com frequência separadas daquelas que não mudam. Além disso, se existirem dependências entre elas, as coisas que mudam com frequência devem depender das que não mudam! (E não o contrário!)

Como, em geral, as mudanças são comuns e frequentes do que desejamos, o OCP agrega muito valor. Novamente o trabalho de dividir a abstração de classe em partes é compensado pelas facilidades em evoluir.

Para Saber Mais

  • LARMAN, Craig. Utilizando UML e padrões: uma introdução à análise e ao projeto orientados à objetos e ao Processo Unificado. Porto Alegre: Bookman, 2007.
  • MARTIN, R. C.; et. al. Clean Code: a handbook of agile software craftsmanship. Boston: Pearson Education, 2009.
  • MARTIN, R. C. The Clean Coder. Upper Sadle River: Prentice-Hall, 2011.
  • MARTIN, R. C. Principles of OOD. Disponível em http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod, recuperado em 17/02/2017.
  • MARTIN, R. C. Get a SOLID start. Disponível em http://objectmentor.com, recuperado em 17/02/2017.
  • PAGE-JONES, Meilir. Fundamentos do Desenho Orientado a Objetos. São Paulo: Makron Books, 2001.
  • SOMMERVILLE, I. Software Engineering. 9th. Ed. Boston: Addison-Wesley, 2011.

segunda-feira, 24 de abril de 2017

Os Princípios SOLID::SRP (parte II)

Parte I | Parte II | Parte III | Parte IV | Parte V | Parte VI
Os princípios de projeto e programação propostos em 1995 por Robert C. Martin, tornaram-se conhecidos como SOLID e tem como objetivo orientar a construção de sistemas que no futuro se mostrem mais fáceis de ampliar e manter. Estes princípios constituem um guia para refatorar código e, também, auxiliar nas abordagens ágeis de construção de software.

O acrônimo SOLID é formado por:
  • Single Responsability Principle
  • Open-Closed Principle
  • Liskov`s Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle
Neste post será abordado o SRP ou princípio da responsabilidade única.

SRP::Single Responsability Principle

Um módulo, classe ou componente de software deve ter uma e apenas uma responsabilidade.
O Single Responsability Principle ou Princípio da Responsabilidade Única ou apenas SRP afirma que cada classe, módulo ou componente de software deve possuir uma, e apenas uma, responsabilidade, o que se traduz como a existência de uma única razão que possa levar a sua mudança.

Isto significa que cada classe deve representar apenas um ator ou entidade de um sistema, devendo ser escrita, modificada e mantida para atender apenas um propósito específico e bem determinado. Um módulo, classe ou componente de software não deve ser um canivete suíço que, por mais que tenha muitas utilidades, nenhuma permite realizar profissionalmente qualquer tipo de serviço.

Na verdade, deveria ser difícil visualizar e entender diferentes responsabilidades em uma mesma classe, mas acaba sendo frequente observar classes que somam mais de uma responsabilidade, criando muitas motivações para sua alteração, o que não é produtivo.
Um sistema composto por classes que atendam ao SRP é, substancialmente, mais simples de se manter, pois somente uma razão específica levará a modificação de cada módulo, classe ou componente. Além disso, propicia flexibilidade para realização de mudanças no futuro sem criar impactos em outras entidades.

Este princípio se traduz diretamente em alta coesão!

No exemplo que segue observa-se uma interface Java denominada IFuncionario que estabelece três operações distintas: calcularSalario(), salvar() e gerarRelatorio(Writer). Também segue uma classe que ilustra a implementação desta interface.

public interface IFuncionario {
    public Salario calcularSalario();
    public void salvar();
    public void gerarRelatorio(Writer w);
}
public class Funcionario implements IFuncionario {

    public Salario calcularSalario() { ... }
    public void salvar() { ... }
    public void gerarRelatorio(Writer w) { ... }
}

Se por uma lado esta interface e sua implementação podem parecer adequadas, não é difícil perceber que a interface IFuncionario define três responsabilidades diferentes, o que é uma clara violação do SRP! A interface IFuncionario indica a necessidade de lógicas voltadas para: (1) cálculo do salário; (2) persistência do objeto; e (3) funcionalidade de autodescrição (produção de relatório). Tudo isso além da própria representação do Funcionario.

Nesta situação é necessário identificar e avaliar funcionalidades para: separar aquelas modificadas por razões diferentes; agrupar aquelas modificadas pelas mesmas razões. Estas ações (provavelmente) darão origem a classes denominadas como *Manager, *Controller, *Handler, *DAO, *Service.

Note que o SRP requer nomes precisos e, principalmente, classes bem focadas (coesas).

No caso, ao dividir as responsabilidades identificadas teremos classes separadas para: o cálculo do salário; a persistência dos objetos; e a geração de relatório.

Conclusões

Deve ser enfatizado que o trabalho decorrente da separação das classes será largamente compensado pelas facilidades em evoluir este design.
Outra consequência do SRP é que se torna um pouco mais simples localizar a duplicação de código, algo que é obviamente ruim, pois ao invés de realizar uma modificação ou correção num único local do código, torna-se necessário localizar todas as cópias para efetuar a alteração desejada.

Para Saber Mais

  • LARMAN, Craig. Utilizando UML e padrões: uma introdução à análise e ao projeto orientados à objetos e ao Processo Unificado. Porto Alegre: Bookman, 2007.
  • MARTIN, R. C.; et. al. Clean Code: a handbook of agile software craftsmanship. Boston: Pearson Education, 2009.
  • MARTIN, R. C. The Clean Coder. Upper Sadle River: Prentice-Hall, 2011.
  • MARTIN, R. C. Principles of OOD. Disponível emhttp://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod, recuperado em 17/02/2017.
  • MARTIN, R. C. Get a SOLID start. Disponível em http://objectmentor.com, recuperado em 17/02/2017.
  • PAGE-JONES, Meilir. Fundamentos do Desenho Orientado a Objetos. São Paulo: Makron Books, 2001.
  • SOMMERVILLE, I. Software Engineering. 9th. Ed. Boston: Addison-Wesley, 2011.

terça-feira, 18 de abril de 2017

C++ em 200 minutos

A veterana linguagem de programação C++ continua surpreendendo. É (ainda) uma das mais utilizadas, mesmo mais de 20 anos após sua proposta e padronização. Pelo menos é o aponta o TIOBE Index de abril de 2017.

Então, pode ser uma boa ideia conhecer os fundamentos desta linguagem. Esta é a proposta do minicurso C++200 (algo como C++ em 200 minutos) que fez parte da programação da  III Jornada de Pesquisa, Extensão e Cultura, realizada na FATEC Jundiaí  no período de 17 a 20 de abril de 2017.
Os slides da apresentação estão abaixo!
Aproveitem!