Nada como começar um ano novo com uma
linguagem de programação também nova. O Bom programador traz para
você a nova linguagem criada pela Google, para desenvolvimento de
aplicações Web: Dart.
Neste artigo, vamos fazer um breve
"tour" pela linguagem Dart, desenvolvendo uma aplicação
que já fizemos com MEAN Stack. Minha intenção não é ensinar a
linguagem Dart, mas mostrar suas principais características, com um
belo exemplo de uso.
Mais uma linguagem de
programação?
Sim. Mais uma linguagem de programação. E, antes que se revolte,
deixe-me contar dois "causos": um sobre o incrédulo e
outro sobre o visionário.
O incrédulo
Nos idos dos anos 80, eu tinha um amigo que era bem cético quanto
aos micro computadores. Ele acreditava que eram apenas "brinquedos"
e que nada iria mudar, pois as empresas precisavam mesmo é de
computadores "mainframe".
Mesmo com o surgimento das redes locais, e das BBS, ele continuou
mantendo sua postura reacionária. Quanto a Internet surgiu, e todos
nós começamos a trabalhar com ela, meu amigo continuava com sua
postura.
Resultado: Ficou desempregado! E, com muito custo, teve que correr
atrás do prejuízo.
O visionário
Nos idos de 2004, eu estava conversando com um grande amigo meu, que
era realmente visionário. Falávamos sobre o crescimento da Google,
que havia desbancado grandes players do mercado, como: Altavista e
Yahoo. Ele me disse a seguinte frase: "Em 5 anos, você estará
programando em Google".
Dito e feito! Em 2009, eu estava programando aplicações para
Smartphones Android, da Google.
Moral da história
NUNCA DUVIDE DA GOOGLE!
Quando se trata de tecnologia oriunda da Google, ninguém deve
subestimar!
Dart: Uma nova plataforma de desenvolvimento
Segundo a Wikipedia
, o objetivo da linguagem Dart
(https://www.dartlang.org/) é substituir o Javascript como linguagem
de desenvolvimento Web, na plataforma da Web Aberta. Ela foi
apresentada na conferência GOTO,
em 2011.
A plataforma Dart é composta por: Interpretador (Dart VM),
transpiller para Javascript, Editor (Dart Editor) e bibiotecas
servidoras, de I/O não bloqueante (dart:io).
É uma nova linguagem de programação, que pode ser traduzida (pelo
transpiller) para Javascript, rodando nos navegadores mais modernos.
Em breve, os navegadores darão suporte direto à Dart VM.
Quem usa essa isso?
Muita gente! O site da linguagem tem uma página
dedicada a mostrar quem está usando Dart. Além da própria Google,
o que já é muita coisa, temos: SAP, CodeShip, Netflix e Adobe, que
estão usando de alguma forma a linguagem Dart.
Qual é o jeitão dela?
Eu diria que Dart é uma deliciosa mistura de Java com Javascript,
que procura manter o que há de melhor em cada uma dessas linguagens.
Ela tem a estrutura e a orientação por classes do Java, mas sem as
"frescuras", enquanto mantém boa parte da flexibilidade e
informalidade do Javascript, mas de maneira organizada.
Eis algumas das características da linguagem Dart, de acordo com a
Wikipedia:
- Baseada em classes;
- Herança simples;
- Orientada a objetos;
- Sintaxe estilo "C";
- Optional typing;
- Suporta: interfaces, classes abstratas, generics e anotações;
Na verdade, o Dart apresenta muitas das características que o
Javascript 6 (ECMAScript
6) terá, como:
- Arrow functions;
- Classes;
- Escopo de bloco;
- Promises ("Future", no Dart).
Você pode programar de maneira muito parecida com Javascript, por
exemplo:
db = new Db("mongodb://127.0.0.1/banco");
db.open()
.then((ok) {
var pathToBuild = join("./build/web");
print(pathToBuild);
staticFiles = new VirtualDirectory(pathToBuild);
staticFiles.allowDirectoryListing = true;
staticFiles.directoryHandler = (dir, request) {
var indexUri = new Uri.file(dir.path).resolve('index.html');
staticFiles.serveFile(new File(indexUri.toFilePath()), request);
};
HttpServer
.bind(InternetAddress.ANY_IP_V4, PORT)
.then((server) {
server.listen((HttpRequest request) {
print(">> " + request.uri.path);
switch (request.method) {
case "GET":
process(request);
break;
default: methodNotAllowed(request);
}
},
onError: msgErro);
});
});
Ou pode criar e utilizar tipos e estruturas parecidas com as do Java
(ou C++):
library estilos;
import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
import 'package:TesteMongoDB/component/estilocomponent.dart';
class MyAppModule extends Module {
MyAppModule() {
bind(Estilocomp);
}
}
void main() {
applicationFactory()
.addModule(new MyAppModule())
.run();
}
Um arquivo-fonte em
Dart
Um programa Dart é armazenado em um arquivo, com extensão ".dart",
e pode conter:
- Comando "import": Permite importar classes e elementos criados em bibliotecas Dart;
- Função "main": Ponto de entrada de todo programa Dart. Você pode pensar nele como um "constutor" da aplicação;
- Variáveis globais (top level): Declaradas fora de qualquer função ou classe;
- Funções globais (top level): idem;
- Classes;
import
O comando "import" permite importarmos bibliotecas para uso
em nosso código. Essas bibliotecas podem ser nativas da linguagem
Dart (usam o prefixo: "dart:") ou podem ser pacotes
desenvolvidos por nós ou importados pelo gerenciador de pacotes
"pub". Eis alguns exemplos:
- import 'dart:io';
- Importa a bilioteca "io", que faz parte da linguagem Dart;
- import 'package:http_server/http_server.dart';
- Importa o pacote "http_server", indicando qual é o arquivo a ser importado;
- import 'package:path/path.dart';
- Importa outro pacote, indicando o arquivo a ser importado;
- import 'dart:convert' show UTF8, JSON;
- Importa apenas os objetos "UTF8" e "JSON", do pacote "dart:convert";
- import 'package:mongo_dart/mongo_dart.dart';
- Importa um pacote baixado usando o "pub";
Função "main"
É o ponto de entrada do código, agindo como um iniciador ou
construtor da aplicação. Se for uma aplicação console, por
exemplo, é o que será executado pela Dart.VM. Um exemplo de função
"main":
class MyAppModule extends Module {
MyAppModule() {
bind(Estilocomp);
}
}
void main() {
applicationFactory()
.addModule(new MyAppModule())
.run();
}
variáveis globais
São definidas fora de qualquer função ou classe:
final PORT = 3000;
Db db;
var staticFiles;
Note que Dart aceita declarações com ou sem tipo, e que possui
alguns dos modificadores da linguagem Java, como o "final",
que indica que o valor da varíavel não será alterado.
Funções globais
São funções declaradas fora de classes e que podem ser utilizadas
por qualquer código dentro do arquivo:
void msgErro(erro) {
print("ERRO: " +
erro);
}
As funções podem retornar um valor ou não.
Classes
Classes são declaradas de forma simples:
class MyAppModule extends
Module {
MyAppModule() {
bind(Estilocomp);
}
}
Não existe o modificador "private". Se você quiser
declarar um membro privado, então deve prefixar seu nome com "_"
(underscore).
Instalando a plataforma Dart
É bem simples e prático. Basta você ir ao site principal:
https://www.dartlang.org/,
baixar e descompactar.
Se você usa Linux (Ubuntu ou outro), então tem um site especifico
ensinando a baixar os pacotes:
https://www.dartlang.org/tools/debian.html
Se você usa Mac OSX, pode instalar com o Homebrew.
Dart Editor
O Dart Editor é a IDE da linguagem Dart, criada com base em
componentes do Eclipse:
O Dart Editor é o Eclipse sem "frescuras". É muito mais
simples e fácil de usar, e, ainda por cima, permite depurar seu
código independentemente de onde esteja sendo executado, seja dentro
de um Browser ou como servidor independente.
Para iniciar o Dart editor basta rodar o executável, que fica na
pasta da instalação do Dart.
Conhecendo a plataforma Dart
Dart permite desenvolver aplicações que rodam:
- Em um Navegador;
- Standalone (console);
- Como um servidor Web;
Com Dart, podemos criar aplicações modernas, codificando tanto a
parte cliente Web, como o Servidor REST usando a mesma linguagem.
Para aplicações cliente, o pacote: "dart:html" permite
criar requests HTTP, e para aplicações Servidoras, o pacote:
"dart:io" permite criar servidores assíncronos, de thread
único, muito semelhante ao Node.js.
As comparações com o MEAN stack são inevitáveis. Para camada
cliente temos:
- Angular Dart: A implementação do framework MVW Angular, da Google, para a linguagem Dart. Aliás, é mais avançado que a versão Javascript, sendo a base para o Angular 2.0;
- Scripts Web Dart: Podem ser invocados diretamente pelas páginas HTML. Atualmente, só o navegador "Dartium" (um porte do Chrome que inclui a Dart.VM) podem rodar diretamente;
- Scritps Servidores Dart: Usando a biblioteca "dart:io", podem criar sockets passivos e tratar requisições usando um único Thread e um "loop" de eventos, como o Node.js.
Supote à programação
assíncrona
A maioria das funções de I/O do Dart já operam de forma
assíncrona, logo, você enfilera os pedidos de I/O, aguardando a
resposta. Para facilitar a vida, a maioria das operações de I/O
retorna "Futures".
Future é um ADT (Abstract Data Type) da Dart, semelhante à Promise,
usada no Node.js e a ser implementada no ECMAScript 6.
Um exemplo de uso de Future:
HttpServer
.bind(InternetAddress.ANY_IP_V4, PORT)
.then((server) {
server.listen((HttpRequest request) {
print(">> " + request.uri.path);
switch (request.method) {
case "GET":
process(request);
break;
default: methodNotAllowed(request);
}
},
onError: msgErro);
});
O método "bind()", do objeto "HttpServer",
retorna uma Future. Logo, nós usamos o seu método "then()"
para colocar o código a ser executado assim que a operação
assíncrona "bind" seja executada.
Um exemplo turbo
Para exemplificar bem o uso da linguagem Dart, nada melhor do que
compará-la com algo conhecido, como o MEAN Stack.
No meu curso de MEAN
Stack, tem uma aplicação feita na sessão
4 (Angular.js), que é bem simples e interessante:
Se você baixou o curso de MEAN Stack, então já tem o banco criado.
Se não, então baixe o MongoDB (veja
aqui como fazer) e crie um banco chamado "banco",
com uma coleção:
{
"nome" : "<
nome do estilo musical >",
"pais" : "<
País do estilo musical >"
}
O projeto Dart está em https://github.com/cleuton/DartDemo e você pode
baixá-lo clonando o repositório Git ou baixando um arquivo Zip.
No Dart Editor, selecione o menu "File / Open Existing
Folder..." e indique o caminho do diretório baixado.
Temos algumas pastas e arquivos no projeto:
- TesteMongoDB: Pasta principal;
- packages: Pasta dos pacotes baixados pelo "pub";
- pubspec.yaml: Descritor da aplicação, com a lista de bibliotecas das quais ela depende;
- pubspec.lock: Associa as versões baixadas à sua aplicação;
- lib: Onde ficam as bibliotecas públicas, criadas na sua aplicação;
- web: Onde ficam os arquivos que podem ser baixados pelo Cliente Web;
O arquivo "pubspec.yaml" parece muito com o "package.json",
das aplicações Node.js. A grande diferença é o "pubspec.lock".
Para declarar dependências, escrevemos no arquivo "pubspec.yaml"
e depois rodamos "pub get", ou então o Dart Editor fará
isso automaticamente para nós.
Assim que uma dependência é baixada, ela é declarada com sua
versão no arquivo "pubspec.lock". Toda vez que
atualizarmos o arquivo, o "pub" verificará se ela existe
no "pubspec.lock", garantindo que a mesma versão seja
sempre baixada. Isso evita incompatibilidades com versões futuras.
Servidor REST
Nossa aplicação usa um servidor REST, criado em Dart. O código
dele está no arquivo: "EstiloRestServer.dart". Ele trata
as seguintes rotas:
- Estáticos: Tudo o que vier com um nome de arquivo na URI. Ele vai servir os arquivos estáticos que estiverem dentro da pasta "/web";
- "/estilos": Ele vai gerar um objeto JSON com a lista de estilos encontrada no MongoDB.
O código do servidor:
import 'dart:io';
import 'package:http_server/http_server.dart';
import 'package:path/path.dart';
import 'dart:convert' show UTF8, JSON;
import 'package:mongo_dart/mongo_dart.dart';
final PORT = 3000;
Db db;
var staticFiles;
main() {
db = new Db("mongodb://127.0.0.1/banco");
db.open()
.then((ok) {
var pathToBuild = join("./build/web");
print(pathToBuild);
staticFiles = new VirtualDirectory(pathToBuild);
staticFiles.allowDirectoryListing = true;
staticFiles.directoryHandler = (dir, request) {
var indexUri = new Uri.file(dir.path).resolve('index.html');
staticFiles.serveFile(new File(indexUri.toFilePath()), request);
};
HttpServer
.bind(InternetAddress.ANY_IP_V4, PORT)
.then((server) {
server.listen((HttpRequest request) {
print(">> " + request.uri.path);
switch (request.method) {
case "GET":
process(request);
break;
default: methodNotAllowed(request);
}
},
onError: msgErro);
});
});
}
void process(request) {
if(request.uri.path == '/estilos') {
// Request para a lista de estilos
DbCollection dbEstilos = new DbCollection(db, 'estilo');
List estilos = new List();
dbEstilos.find().forEach((Map mEstilo) {
estilos.add(mEstilo);
}).then((v) {
request.response.headers.set("Access-Control-Allow-Origin",
'*');
request.response.headers.contentType
= new ContentType("application", "json", charset: "utf-8");
request.response.write(JSON.encode(estilos));
request.response.close();
});
}
else {
staticFiles.serveRequest(request);
}
}
void methodNotAllowed(request) {
request.response.statusCode = HttpStatus.METHOD_NOT_ALLOWED;
request.response.write("Unsupported request: ${request.method}.");
request.response.close();
}
void msgErro(erro) {
print("ERRO: " + erro);
}
Antes de rodar o projeto, selecione o menu "Tools / Pub Build",
para gerar a versão Javascript do site. Isto vai compilar todo o
código Dart, gerando uma pasta "build" com o código
cliente totalmente em Javascript. Desta forma, o projeto rodará em
qualquer navegador. Você pode copiar essa pasta "build"
para um Servidor, colocando o arquivo "EstiloRestServer.dart"
nela.
Para subir o Servidor é só usar o Dart SDK e executar o programa
"EstiloRestServer.dart". Ele se encarregará de servir os
arquivos estáticos.
Se estiver usando o Dart Editor, basta selecionar o arquivo
"EstiloRestServer.dart" e, no menu de contexto (botão
direito), selecionar "run".
Abra um navegador e digite a url: "http://localhost:3000".
Tudo começa na função "main". De início, abrimos uma
conexão com o Banco MongoDB, o que retorna uma Future. Então, nós
preparamos o nosso diretório virtual, para servir arquivos
estáticos:
var pathToBuild = join("./build/web");
staticFiles = new VirtualDirectory(pathToBuild);
staticFiles.allowDirectoryListing = true;
staticFiles.directoryHandler = (dir, request) {
var indexUri = new Uri.file(dir.path).resolve('index.html');
staticFiles.serveFile(new File(indexUri.toFilePath()), request);
};
Apontamos para a pasta "./build/web", que é onde estarão
os arquivos cliente, já convertidos para Javascript. Especificamos
que, se o request for para um diretório ("/") o arquivo
"index.html" será retornado.
Até agora, não abrimos o socket passivo, coisa que fazemos com:
HttpServer
.bind(InternetAddress.ANY_IP_V4, PORT)
.then((server) {
server.listen((HttpRequest request) {
print(">> " + request.uri.path);
switch (request.method) {
case "GET":
process(request);
break;
default: methodNotAllowed(request);
}
},
onError: msgErro);
});
Abrimos um socket passivo, associando-o a todos os endereços IP V 4
do servidor, e à porta declarada na variável "PORT"
(3000). O método "listen" permite associarmos um
"callback", que será invocado sempre que chegar um novo
request HTTP.
Então, testamos se o método foi "GET" e processamos o
request. O processamento é simples:
void process(request) {
if(request.uri.path == '/estilos') {
// Request para a lista de estilos
DbCollection dbEstilos = new DbCollection(db, 'estilo');
List estilos = new List();
dbEstilos.find().forEach((Map mEstilo) {
estilos.add(mEstilo);
}).then((v) {
request.response.headers.set("Access-Control-Allow-Origin",
'*');
request.response.headers.contentType
= new ContentType("application", "json", charset: "utf-8");
request.response.write(JSON.encode(estilos));
request.response.close();
});
}
else {
staticFiles.serveRequest(request);
}
}
Se for para o caminho "/estilos", então fazemos uma
consulta à coleção de estilos no MongoDB, montando uma Lista de
estilos. Ao final, fechamos a resposta do tipo "application/json",
enviando a lista codificada como objeto JSON.
Caso contrário, mandamos servir como arquivo estático.
Cliente AngularDart
Eu simplesmente adoro o Angular! Na versão Dart, ele é o máximo!
Então, eu usei o AngularDart para criar a parte cliente do site.
Para começar, temos um arquivo HTML simples ("/web/index.html"):
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
<lista-estilos></lista-estilos>
</div>
<script type="application/dart" src="main.dart"></script>
<script data-pub-inline src="packages/browser/dart.js"></script>
</body>
</html>
Se é uma aplicação Angular, cadê o "ng-app"? O gato
comeu! Não preciso mais disso! Note que eu criei um tag especial:
"<lista-estilos>" e vou associá-lo a um Componente
Angular.
No final, eu carrego o programa "main.dart", que é o "code
behind" da página, e o arquivo de conversão "dart.js",
para compatibilidade com outros navegadores (diferentes do Dartium).
Componente Angular
Um componente Angular é uma mistura de código e HTML, que é
injetado dentro de um TAG específico. Quando a página for
renderizada, o tag "<lista-estilos>" será
substituído pelo HTML gerado pelo meu componente. Esse componente
está dentro de "/lib/component", e é composto por um
arquivo Dart e um trecho de código HTML (um template). Eis o arquivo
Dart:
library estilocomponent;
import 'package:angular/angular.dart';
import 'dart:html';
import 'dart:convert' show UTF8, JSON;
@Component(
selector: 'lista-estilos',
templateUrl: 'estilo.html',
exportExpressions: const["estilos"])
class Estilocomp {
List<String> estilos = new List<String>();
Estilocomp() {
_loadData();
}
void _loadData() {
var url = "http://127.0.0.1:3000/estilos";
var request = HttpRequest.getString(url).then((String texto) {
List data = JSON.decode(texto);
data.forEach(pegaNome);
});
}
void pegaNome(estilo) {
estilos.add(estilo['nome']);
}
}
A anotação "@Component" transforma a classe "Estilocomp"
em um componente AngularDart. Isso faz com que ele seja instanciado e
injetado no escopo da aplicação Web. Note que informei na anotação:
- selector: O Tag que está associado a este componente;
- templateUrl: O template html para este componente utilizar;
- exportExpressions: O que este componente exportará para o escopo da página HTML;
O construtor da classe Estilocomp invoca a função "_loadData()",
que faz um request HTTP para o caminho "/estilos", do nosso
servidor. Como eu coloquei o endereço fixo, isso só rodará se for
no Localhost. Você pode passar o endereço IP por parâmetro ou
mesmo através de variável de ambiente.
O construtor preenche a Lista "estilos" com o nome de cada
estilo encontrado.
O template
O template desse componente é "estilo.html":
<h3>Estilos</h3>
<ul>
<li ng-repeat="estilo in estilos">
{{estilo}}
</li>
</ul>
Se você já conhece Angular.js, está familiarizado com o
"ng-repeat". Eu monto uma lista de "<li>"
com o nome de cada estilo. Lembre-se que a coleção "estilos"
foi exportada dentro do componente, logo, ela contém o nome de cada
estilo.
Resultado
O resultado é muito parecido com o da versão original, feita em
MEAN Stack:
Análise preliminar da plataforma Dart
Dart é uma promessa interessante. Só o fato de ter sido criada pela
Google já merece a minha atenção, embora eu tenha algumas
ressalvas, gostei muito da experiência com ela.
Pontos positivos
- A linguagem Dart é simples, fácil, versátil e poderosa. Uma mistura deliciosa de Java e Javascript, sem os pontos negativos de cada uma;
- A plataforma integrada funciona muito bem, e o Dart Editor é bem agradável de usar;
- A biblioteca de I/O não bloqueante e de servidor Web é muito rápida, permitindo a criação de aplicações preparadas para o problema C10k, sem necessidade de "Containers" ou servidores "beberrões";
- Dart se integra muito bem com o Angular, dispensando vários outros frameworks, como o próprio jQuery;
- Atende ao meu requisito de "uma só linguagem", de ponta a ponta, pois você só precisa programar em Dart;
- Tem um ecossistema crescente, com um poderoso gerenciador de bibliotecas (o "pub");
- É utilizada pela Google.
Pontos negativos
- O suporte à Dart pelos navegadores ainda não é uma realidade. A tradução em Javascript ainda deve continuar por muito tempo;
- Toda a cultura Javascript deve ser substituída por Dart, o que exige um alto comprometimento com o futuro dessa linguagem;
- O ecossistema Dart ainda é pequeno, se comparado com o ecossistema Javascript;
- Dart ainda não é um padrão da Web Aberta.
Eu acho que Dart é um boa alternativa, se comparado com soluções
de alta complexidade acidental, como o Java EE. Porém, perde, se
comparado com o MEAN Stack.
De qualquer forma, é uma plataforma completa e com suporte da
Google, logo, vale a pena conhecer e experimentar, apesar do
Technology Radar de Outubro de 2012 tenha classificado como: "Hold"
(esperar), ainda vale a pena conhecer a linguagem.
Se você tem medo dos frameworks Open source Javascript, que passam
por mudanças "loucas" a cada nova versão, a Dart pode ser
uma alternativa mais confiável.
Nenhum comentário:
Postar um comentário