frameworks

O que é ORM?

Object-Relational Mapping (ORM), em português, mapeamento objeto-relacional, é uma técnica para aproximar o paradigma de desenvolvimento de aplicações orientadas a objetos ao paradigma do banco de dados relacional. O uso da técnica de mapeamento objeto-relacional é realizado através de um mapeador objeto-relacional que geralmente é a biblioteca ou framework que ajuda no mapeamento e uso do banco de dados.

Problema da impedância de dados

Quando estamos trabalhando com aplicações orientadas a objetos que utilizam banco de dados relacionais para armazenamento de informações, temos um problema chamado impedância objeto-relacional devido às diferenças entre os 2 paradigmas.

O banco de dados relacional trabalha com tabelas e relações entre elas para representar modelos da vida real. Dentro das tabelas temos várias colunas e a unidade que temos para representação no modelo relacional é uma linha:

O paradigma orientado a objetos possui um modo um pouco diferente de trabalhar. Nele nós temos diversos elementos como classes, propriedades, visibilidade, herança e interfaces. A unidade quando falamos de orientação a objetos é o objeto que representa algo do mundo real, seja abstrato ou concreto:

As principais dificuldades que essas diferenças entre paradigmas causa:

  • Representação dos dados e do modelo, já que as estruturas são distintas;
  • Mapeamento entre os tipos de dados da linguagem de programação e do banco de dados;
  • Modelo de integridade relacional do banco relacional;

O ORM

Pensando nos problemas descritos acima, o ORM define uma técnica para realizar a conciliação entre os 2 modelos. Uma das partes centrais é através do mapeamento de linhas para objetos:

As bibliotecas ou frameworks ORM definem o modo como os dados serão mapeados entre os ambientes, como serão acessados e gravados. Isso diminui o tempo de desenvolvimento, uma vez que não é necessário desenvolver toda essa parte. Outra vantagem está na adaptação de novos membros na equipe, como muitos projetos comerciais utilizam a mesma ferramenta, é possível encontrar membros que já estão acostumados com o padrão de trabalho.

Padrões utilizados no mercado

Independente da linguagem de programação que o ORM é implementado, geralmente ele segue um padrão bem definido. No mercado existem dois padrões que são amplamente utilizados, o Data Mapper e o Active Record. Ambos os padrões foram definidos por Martin Fowler em seu livro Padrões de Arquitetura de Aplicações Corporativas.

Data Mapper

Nesse padrão a classe que representa a tabela do banco de dados não deve conhecer os recursos necessário para realizar as transações com banco de dados: inserir, atualizar e apagar informações. Esses recursos ficam em uma classe própria do ORM, garantindo que as classes que representam a tabela tenha uma única responsabilidade:

(Imagem do livro “Padrões de Arquitetura de Aplicações Corporativas”)

Na prática, para a maioria dos ORMs do mercado que implementam o padrão Data Mapper, independente da linguagem, vamos ter um código muito parecido com abaixo:

EntityManager entityManager = Persistence.createEntityManagerFactory("persistente-unit");

entityManager.getTransaction().begin();

Pessoa pessoa = new Pessoa();
pessoa.setId(1);
pessoa.setSobrenome("Silva");
pessoa.setPrenome("João");
pessoa.setNumeroDeDependentes(2);

entityManager.persist(pessoa);
entityManager.getTransaction().commit();

O código acima é um exemplo do Hibernate para Java.

Active Record

Nesse padrão, diferentemente do anterior, a classe que representa a tabela conhece os recursos necessários para realizar as transações no banco de dados, geralmente ela herda uma classe com todos esses comportamentos. Veja abaixo um diagrama retirado do livro “Padrões de Arquitetura de Aplicações Corporativa”:

Na maioria dos ORM que implementam o padrão Active Record teremos um código muito parecido com esse:


pessoa = pessoa.new pessoa.sobrenome = "Silva" pessoa.prenome = "João" pessoa.numeroDeDependentes = 2 pessoa.save()

O código é válido para o ORM do Ruby On Rails.

Principais ORMs do mercado

Java

  • Hibernate
  • EclipseLink
  • ActiveJPA

Kotlin

  • Exposed

C#

  • Entity Framework
  • Nhibernate
  • Dapper

Node

  • Sequelize

PHP

  • Doctrine
  • Eloquent

Ruby

  • Ruby On Rails ActiveRecord
  • Datamapper

Python

  • DjangoORM
  • SqlAlchemy

Considerações finais

Existem muitas discussões entre usar um ORM que implementa Data Mapper ou Active Record. Muitos desenvolvedores defendem um ou outro com unhas e dentes, porém, na realidade, como quase tudo na nossa área, não existe bala de prata. Se tiver a oportunidade aconselho estudar ORMs da sua linguagem que trabalha em ambos os padrões, assim você terá um conhecimento maior para escolher entre um ou outro dependendo dos requisitos do seu projeto.

Autowiring em Container de Injeção de Dependência

No artigo Entendendo Injeção de Dependência vimos sobre o que é injeção de dependência, seu funcionamento e como se dá a sua aplicação. No artigo Container De Injeção De Dependência (DI Container) vimos como funciona um container para gerenciar o mapa de dependências.

Nesse artigo veremos uma funcionalidade relativamente comum nos containers de dependência de frameworks que é a habilidade de resolver as dependências de um construtor (principalmente) automaticamente, chamada de autowiring.

No artigo Container De Injeção De Dependência (DI Container) implementamos um protótipo (simples, porém funcional) de um container e, em determinado momento, chegamos nesse tipo de caso de uso:

$indexController = new IndexController(
    $container->get('user.repository')
);

$userController = new UserController(
    $container->get('user.repository')
);

$registerController = new RegisterController(
    $container->get('user.repository')
);

Alguns controladores precisavam receber a instância de UserRepository e tivemos que manualmente passá-la para cada um deles. Agora, imagine se cada um desses controladores tivesse que receber outras dependências? Nenhum problema, só que ficaria meio chato e improdutivo ter que ficar repetindo essas construções na instanciação deles, concorda?

E se desenvolvermos uma forma do nosso container automaticamente resolver essas dependências? Desse modo, tudo o que faríamos seria pedir para o Container uma instância desses controladores, sem a necessidade de nos preocuparmos em passar manualmente para o construtor de cada um deles as suas dependências. Teríamos como resultado um código assim:

$indexController = $container->get(IndexController::class);

$userController = $container->get(UserController::class);

$registerController = $container->get(RegisterController::class);

Estamos pedindo as instâncias desses controladores sem nos preocuparmos em alimentá-los de suas dependências, deixamos esse trabalho para o Container.

Symfony - Fundamentos
Curso de Symfony - Fundamentos
CONHEÇA O CURSO

Estrutura inicial do projeto

Vamos criar o protótipo de uma aplicação para que possamos testar a nossa implementação de Container. A nossa aplicação terá essa estrutura:

- [blog-artigo-di]
- - - [app]
- - - - [Http]
- - - - - - [Controller]
- - - - - - - UserController.php
- - - - [Repositories]
- - - - - LeadRepository.php
- - - - - TagRepository.php
- - - - - UserRepository.php
- - - Container.php
- index.php

O repositório dessa estrutura no GitHub você encontra clicando aqui. Se desejar, você pode fazer download direto dela clicando nesse link: sem-autowiring.zip

Depois de baixar e colocar no local onde normalmente você executa seus projetos, basta que você execute composer install pois o projeto faz uso da PSR-4 para autoloading:

$ ~/D/w/blog-artigo-di> composer install

O nosso Container atualmente possui uma implementação simples e que ainda não suporta a resolução automática de dependências. Abra app/Container.php:

<?php
declare(strict_types=1);

namespace App;

use Closure;

final class Container
{
    private $instances = [];

    public function set(string $id, Closure $closure) : void
    {
        $this->instances[$id] = $closure;
    }

    public function get(string $id) : object
    {
        return $this->instances[$id]($this);
    }

    public function singleton(string $id, Closure $closure) : void
    {
        $this->instances[$id] = function () use ($closure) {
            static $resolvedInstance;

            if (null !== $resolvedInstance) {
                $resolvedInstance = $closure($this);
            }

            return $resolvedInstance;
        };
    }
}

Esse container já foi explicado na indicação de leitura no início desse artigo. Portanto, não vamos entrar novamente em seus pormenores.

O arquivo index.php na raiz do projeto é o responsável pelo bootstrap da nossa aplicação protótipo:

<?php

// Carrega o autoload do Composer
require './vendor/autoload.php';

use App\Repositories\TagRepository;
use App\Repositories\LeadRepository;
use App\Repositories\UserRepository;
use App\Http\Controller\UserController;

// Instancia o container
$container = new App\Container();

// Adiciona referências ao container
$container->set(TagRepository::class, function() {
    return new TagRepository();
});

$container->set(LeadRepository::class, function() {
    return new LeadRepository();
});

$container->set(UserRepository::class, function() {
    return new UserRepository();
});

// Instancia o UserController passando para ele as dependências necessárias
$userController = new UserController(
    $container->get(TagRepository::class),
    $container->get(UserRepository::class),
    $container->get(LeadRepository::class)
);

$userController->index();

Para testar o exemplo, na raiz do projeto execute:

$ ~/D/w/blog-artigo-di> php -S localhost:8000

Isso executará o servidor embutido do PHP em cima da raiz do nosso projeto, permitindo que o acessemos pelo navegador através da URL: http://localhost:8000/

O resultado será:

/Users/kennedytedesco/Documents/www/blog-artigo-di/app/Http/Controller/UserController.php:31:
array (size=2)
  'id' => int 1
  'name' => string 'tag' (length=3)

/Users/kennedytedesco/Documents/www/blog-artigo-di/app/Http/Controller/UserController.php:31:
array (size=2)
  'id' => int 2
  'name' => string 'user' (length=4)

/Users/kennedytedesco/Documents/www/blog-artigo-di/app/Http/Controller/UserController.php:31:
array (size=2)
  'id' => int 3
  'name' => string 'lead' (length=4)

Indica que o método index() do UserController foi executado com sucesso. Ou seja, as dependências, os repositórios necessários para o funcionamento dessa classe foram injetados com sucesso. Até aqui tudo bem, ademais, injetamos tais dependências manualmente:

$userController = new UserController(
    $container->get(TagRepository::class),
    $container->get(UserRepository::class),
    $container->get(LeadRepository::class)
);

Implementando a resolução automática de dependências

Para que possamos implementar a resolução automática das dependências utilizaremos a API de reflexão do PHP. Essa API nos fornece meios para que façamos engenharia reversa nas classes, extraindo muitas de suas informações internas como quantos métodos possui, quais são públicos, protegidos ou privados, se implementa um construtor, quais são os parâmetros do construtor, se são opcionais ou exigidos, entre outras informações.

Dessa forma, se o usuário pedir para o Container a instanciação do UserController:

$userController = $container->get(UserController::class);

Que tal a gente usar reflexão para obter quais dependências (classes) ele necessita para ser instanciado e então resolver essas dependências automaticamente usando o próprio Container e retornar a instância dele?

É exatamente isso que a nossa implementação de autowiring fará. Para tanto, começaremos alterando o código do nosso container app\Container.php para:

<?php
declare(strict_types=1);

namespace App;

use Closure;
use ReflectionClass;
use ReflectionParameter;

final class Container
{
    private $instances = [];

    public function set(string $id, Closure $closure) : void
    {
        $this->instances[$id] = $closure;
    }

    public function get(string $id) : object
    {
        // Se essa referência existe no mapa do container, então a retorna diretamente.
        if ($this->has($id)) {
            return $this->instances[$id]($this);
        }

        // Se a referência não existe no container, então foi passado uma classe para ser instanciada
        // Façamos então a reflexão dela para obter os parâmetros do método construtor
        $reflector = new ReflectionClass($id);
        $constructor = $reflector->getConstructor();

        // Se a classe não implementa um método construtor, então vamos apenas retornar uma instância dela.
        if (null === $constructor) {
            return new $id();
        }

        // Itera sobre os parâmetros do construtor para realizar a resolução das dependências que ele exige.
        // O método "newInstanceArgs()" cria uma nova instância da classe usando os novos argumentos passados.
        // Usamos "array_map()" para iterar os parâmetros atuais, resolvê-los junto ao container e retornar um array das instâncias já resolvidas pelo container.
        return $reflector->newInstanceArgs(array_map(
            function (ReflectionParameter $dependency) {
                // Busca no container a referência da classe desse parâmetro
                return $this->get(
                    $dependency->getClass()->getName()
                );
            },
            $constructor->getParameters()
        ));
    }

    public function singleton(string $id, Closure $closure) : void
    {
        $this->instances[$id] = function () use ($closure) {
            static $resolvedInstance;

            if (null !== $resolvedInstance) {
                $resolvedInstance = $closure($this);
            }

            return $resolvedInstance;
        };
    }

    public function has(string $id) : bool
    {
        return isset($this->instances[$id]);
    }
}

(Através do GitHub você pode visualizar o que foi adicionado/removido. Basta visualizar esse commit aqui).

A partir do momento que o nosso Container consegue resolver as dependências automaticamente, podemos alterar no index.php a forma de instanciar, que era uma instanciação direta da classe usando new UserController:

$userController = new UserController(
    $container->get(TagRepository::class),
    $container->get(UserRepository::class),
    $container->get(LeadRepository::class)
);

Para uma instanciação que usa o Container (para que ele possa resolver as dependências para nós):

$userController = $container->get(UserController::class);
$userController->index();

(O código completo do exemplo com autowiring encontra-se no branch master do repositório desse exemplo).

Você pode testar o exemplo e terá o mesmo resultado obtido anteriormente quando não usávamos autowiring. O UserController continuará sendo instanciado com sucesso.

Laravel - Framework PHP (Parte 3/3)
Curso de Laravel - Framework PHP (Parte 3/3)
CONHEÇA O CURSO

Concluindo

Vimos nesse artigo a fundação sobre como a resolução automática de dependências é feita nos containers de injeção de dependência. É por esse caminho que Symfony, Laravel entre outros frameworks (inclusive de outras linguagens) fazem. Obviamente o nosso Container é simples, didático e bem direto ao ponto, não estando 100% pronto para uso em projetos reais. Algumas verificações de segurança (se a classe existe, senão lançar uma exceção etc) precisariam ser implementadas. Na realidade, existem boas implementações de containers por aí e, se você usa um Web Framework, não vai precisar criar a sua própria. No entanto, saber como funciona, é essencial. Essa foi a intenção desse artigo.

Até a próxima!

Tendências de TI para 2019

O ano já começou a todo vapor! Por isso, nada melhor do que estar por dentro das tendências na área de TI para 2019. Além das coisas mudarem muito rápido, sempre aparece alguma novidade. Então, vamos começar o ano nos atualizando com as novidades e quais tecnologias continuam em alta neste ano que se inicia.

DevOps

Hoje em dia, quem conhece a cultura e as ferramentas DevOps conquista um bom destaque no mercado. Neste ano, a previsão é que este segmento da área de TI fique mais aquecido ainda.

Relembrando: DevOps é um modelo que combina práticas e ferramentas com a intenção de aumentar a capacidade de uma empresa distribuir seus serviços de forma muito mais rápida. Ela visa também a integração da área de desenvolvimento com a área de operação, pois assim conseguimos alcançar uma maior qualidade nas entregas, além de evitar falhas de comunicação entre as áreas, bem como atrasos e retrabalhamos nos projetos.

Essa é uma prática que vem ganhando muito destaque por causa dos processos de integração contínua e entrega contínua. As entregas são menores, visando as liberações de versões mais seguras, além dos ciclos de desenvolvimento menores, fazendo com que a qualidade aumente.

Outro ponto muito importante é o auxílio que ele traz no gerenciamento e controle sobre o ambiente e infraestrutura. Como a infraestrutura é gerenciada através de técnicas de desenvolvimento de software, tanto ela quanto os servidores são implantados muito rapidamente.

Docker DevOps - Para desenvolvedores
Curso de Docker DevOps - Para desenvolvedores
CONHEÇA O CURSO

Mas, como podemos implementar a cultura e as ferramentas DevOps?

Existem diversas ferramentas para nos ajudar. Possivelmente, você já deve ter ouvido falar sobre Docker. O Docker é um exemplo, assim como o Kubernetes, o Openshift, o Jenkins e outras ferramentas. Essas ferramentas facilitam a criação e manutenção desses ambientes, geralmente baseados em containers. Com elas, você consegue criar, implantar, migrar e muito mais, de um ambiente para outro, de maneira muito eficiente, rápida e segura.

Inteligência Artificial

A Inteligência Artificial continuará em alta, pois cada vez mais empresas estão utilizando ferramentas de IA para melhorar suas operações.

Hoje, podemos dar vários exemplos do uso de ferramentas de IA que impactam em nosso dia a dia. Um exemplo bem palpável é a popularização do uso de chatbots de atendimento ao cliente, que está sendo inserida para melhorar o suporte e rapidez nas informações. Outro exemplo é o algoritmo de reconhecimento facial que o Facebook utiliza para identificar pessoas em uma foto.

Entre as ferramentas de IA que vêm ficando mais populares e que continuarão em alta em 2019, nós podemos citar o TensorFlow. O TensorFlow é uma biblioteca de software muito poderosa para computação numérica usando grafos computacionais, sendo o principal software para desenvolvimento em Deep Learning e aplicações de Inteligência Artificial.

Outra ferramenta de IA que podemos citar e que vêm ganhando cada vez mais demanda pelo mercado de trabalho é o Azure Cognitive Services, da Microsoft. O Cognitive Services amplia o acesso de APIs de aprendizado de máquina.

Esses serviços permitem a criação de aplicativos inteligentes com algoritmos e funcionalidades avançadas (como reconhecimento de objetos em fotos, visão computacional, reconhecimento de fala e outras), podendo ser utilizados em apps, sites e bots para que eles entendam as necessidades do usuário, tudo isso sem precisar de conhecimentos específicos em IA. Todos estes serviços são oferecidos através de APIs e aplicações hospedadas no ambiente do Microsoft Azure, ou seja, através de Cloud Computing.

Frameworks de gestão

Apesar de não ser uma novidade, os frameworks de gestão sempre estarão em alta, pois o mercado em geral vem ficando cada vez mais alinhado com as boas práticas de gestão alinhadas com os processos de desenvolvimento.

Hoje, é imprescindível saber pelo menos um pouco sobre os principais frameworks como ITIL, SCRUM, Kanban e outros. Esses frameworks são importantes por estabelecerem boas práticas de TI no mundo corporativo, fazendo com que a gestão de projetos seja simples, dinâmica e com foco na melhoria geral dos resultados.

O ITIL é um dos frameworks mais adotados atualmente, tendo como foco o alinhamento dos serviços de TI aos objetivos do negócio. Após a sua adoção, os processos de TI tendem a ficar mais consistentes, além da maior eficácia na entrega dos serviços.

Visando ajudar o gerenciamento desses serviços, um outro framework também muito utilizado hoje em dia é o Scrum. Ele é muito aplicado a projetos de desenvolvimento de software, dividindo o trabalho em tarefas menores e incrementais, sempre monitoradas por meio de reuniões diárias. Tudo isso para que os objetivos sejam alcançados da melhor maneira possível.

Outro framework de gestão que vem se destacando cada vez mais é o Kanban. Ele é um quadro onde você sinaliza através de cartões ou post-its o andamento da sua tarefa, com a intenção de que todos os envolvidos do projeto saibam o que está acontecendo. É uma ótima ferramenta, pois além de ser bem visual, você consegue se manter atualizado rapidamente com relação ao andamento do projeto.

ITIL - Fundamentos - Parte 1
Curso de ITIL - Fundamentos - Parte 1
CONHEÇA O CURSO

Concluindo

Essas são algumas das tendências que continuam em alta nesse ano. Certamente, as melhores vagas na área de TI em 2019 exigirão que você conheça alguns dos tópicos que foram abordados. Aqui na TreinaWeb, além de cursos das tendências que abordamos neste artigo, também existem diversos cursos de desenvolvimento de software e muitos outros que vão fazer você alavancar sua carreira na área de TI.

© 2004 - 2019 TreinaWeb Tecnologia LTDA - CNPJ: 06.156.637/0001-58 Av. Paulista, 1765, Conj 71 e 72 - Bela Vista - São Paulo - SP - 01311-200