sexta-feira, 24 de março de 2017

Lançamento do Angular v4.0!

Ontem (23/02/2017), foi anunciado o lançamento da tão esperada versão 4 do Angular.

Se do AngularJS ("Angular 1") pro "Angular 2" (ou, simplesmente "Angular") houve uma total reescrita do framework (com arquitetura e conceitos completamente novos, sem contar com o uso do Typescript), do "Angular 2" pro "Angular 4" não foram feitas alterações tão impactantes assim - inclusive, foi mantida a compatibilidade do código escrito com a versão 2 (com pequenas exceções, como a relacionada ao pacote de animações, que será apresentada mais adiante).

CURIOSIDADE: Você sabe o porquê da versão do Angular ter passado da 2 diretamente para a 4?

A partir da versão 2, o Angular passou a adotar como convenção de versionamento a "Semantic Versioning" ("SEMVER"). Além disso, todas as bibliotecas "core" do Angular, que estão no mesmo repositório no GitHub, são versionadas dessa mesma forma, apesar de serem distribuídas em diferentes pacotes NPM:

Como a biblioteca de roteamento/navegação ("@angular/router") acabou sendo bastante alterada, inserindo "breaking changes", o seu pacote acabou tendo o primeiro número ("major") incrementado para versão 3, enquanto os outros permaneceram na versão 2, por não terem alterações tão significantes.

Por causa disso, para deixar as versões dos pacotes alinhados, causando menos confusão e facilitando a manutenção, a equipe do Angular resolveu padronizar tudo como versão 4.

Saiba mais:

Mas isso não significa que não foram feitas mudanças importantes nessa nova versão. Embora não tão aparentes para os desenvolvedores, foram feitas alterações significativas "por baixo dos panos" - implicando, principalmente, em melhorias de performance e em redução do tamanho final da aplicação (que, em alguns casos, pode chegar a 60%!). Pelo "changelog" do Angular, dá para ter uma ideia do que foi alterado desde a versão 2.

Mas o que muda para o desenvolvedor?

De fato, pouca coisa mudou (aparentemente), mas algumas delas podem ser destacadas:
  1. Melhorias no *ngIf e no *ngFor
  2. Adicionado o "email validator"
  3. Renderer2
  4. Animations package
  5. Typescript 2.2


1. Melhorias no *ngIf e no *ngFor

Nas versões anteriores do Angular, era comum usar a técnica exemplificada no código abaixo para mostrar/esconder elementos de forma alternada:
<p *ngIf="show">Você pode ver esse parágrafo...</p>
<p *ngIf="!show">Ou você pode ver esse outro parágrafo!</p>

Apesar disso ainda funcionar, com a melhoria do *ngIf, foi adicionado o "else", e pode-se fazer o mesmo código de maneira bem mais elegante:
<p *ngIf="show; else alternativa">Você pode ver esse parágrafo...</p>
<ng-template #alternativa>
  <p>Ou você pode ver esse outro parágrafo!</p>
</ng-template>

Além disso, agora também pode-se fazer atribuições locais conforme o exemplo abaixo (utilizando um Observable):
<div *ngIf="userList | async as users; else loading">
  <user-profile *ngFor="let user of users; count as count" [user]="user">
  </user-profile>
 <div>{{count}} total users</div>
</div>
<ng-template #loading>Loading...</ng-template>

2. Adicionado o "email validator"

Nas versões anteriores do Angular, era necessário usar um "pattern" para fazer a validação de um campo do tipo "email" em um formulário:
<form #f="ngForm">
    <input name="email" type="email" ngmodel required 
      pattern="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])+">
    <button [disabled]="!f.valid">Enviar</button>
</form>  

Na versão 4 do Angular, basta fazer isso:
<form #f="ngForm">
    <input name="email" type="email" ngmodel required email>
    <button [disabled]="!f.valid">Enviar</button>
</form>  


3. Renderer2

O "Renderer" agora é "deprecated" e foi incluído o "Renderer2", que pode (e deve) ser utilizado nos projetos com Angular v4 - o que não significa que o Renderer antigo deixou de funcionar.

Nas próximas versões do Angular, é provável que o Renderer seja retirado; mas, se a versão do Angular da aplicação não for atualizada para as versões futuras do Angular (por exemplo, pro Angular v5), ele continuará funcionando normalmente ("#noBreakingChangesForNow").

Exemplo de uso do Renderer2:

import { Component, Renderer2 } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

constructor(private renderer: Renderer2) {}
// ...


4. Animations package

Na versão 2 do Angular, os elementos de animações ficam no "core" do framework e têm que ser importados do pacote "@angular/core", conforme exemplo abaixo:

import {
  Component,
  trigger,
  state,
  style,
  transition,
  animate
} from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  animations: [
    trigger('divState', [
      state('normal', style({
        'background-color': 'red',
        transform: 'translateX(0)'
      })),
      state('highlighted', style({
        'background-color': 'blue',
        transform: 'translateX(100px)'
      })),
      transition('normal <=> highlighted', animate(300))
    ])
  ]
})
export class AppComponent {
    //...

Já na versão 4, foi criado um pacote separado ("@angular/animations"), de onde esses elementos devem ser importados:

import { Component } from '@angular/core';
import {
  trigger,
  state,
  style,
  transition,
  animate
} from '@angular/animations';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  animations: [
    trigger('divState', [
      state('normal', style({
        'background-color': 'red',
        transform: 'translateX(0)'
      })),
      state('highlighted', style({
        'background-color': 'blue',
        transform: 'translateX(100px)'
      })),
      transition('normal <=> highlighted', animate(300))
    ])
  ]
})
export class AppComponent {
  //...

Além disso, é necessário importar o módulo "BrowserAnimationsModule" do pacote "@angular/platform-browser/animations":

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    BrowserAnimationsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


5. Suporte ao Typescript 2.2

Na versão anterior, apenas o Typescript 1.8 era suportado. A versão 4 suporta o Typescript 2.1 e o 2.2 e, com isso, o ngc ("compiler-cli") fica mais rápido e se consegue melhorias na checagem de tipos da aplicação, sem contar os novos recursos do Typescript que poderão ser utilizados pelos desenvolvedores.

E como atualizar a versão do Angular no projeto?

A atualização para nova versão do Angular é muito simples, basta rodar o comando abaixo no console e conferir as alterações dos pacotes no arquivo "package.json":

$ npm install @angular/common@latest @angular/compiler@latest @angular/compiler-cli@latest @angular/core@latest @angular/forms@latest @angular/http@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/platform-server@latest @angular/router@latest @angular/animations@latest typescript@latest --save

Alterações no "package.json"
Alterações no "package.json"

Depois, basta rodar a aplicação (geralmente através do comando "ng serve", se estiver sendo utilizado o "angular-cli" no projeto) e verificar no console do navegador se tudo está funcionando corretamente .

Observação: Se o projeto utiliza animações, é provável que no console apareça uma mensagem indicando que o módulo "BrowserAnimationsModule" deve ser importado na aplicação.

É isso! Agora é esperar a versão 5, que deve sair lá por Setembro ou Outubro de 2017!


quinta-feira, 7 de agosto de 2014

Hospedando um Website estático na Amazon


Como muita gente já sabe, a Amazon oferece serviços de ótima qualidade na "nuvem", através de uma iniciativa chamada de Amazon Web Services (ou, simplesmente, Amazon AWS).

Dentre os serviços disponíveis, estão alguns que - quando combinados - permitem a hospedagem de websites de uma forma muito fácil e com um custo relativamente baixo (e escalável).

Hoje então vou falar um pouco de hospedagem de websites, mais precisamente os estáticos, utilizando essa infra-estrutura da Amazon. Mais precisamente, vou abordar os serviços abaixo:
Além disso, pro exemplo, vou utilizar um domínio registrado no registro.br e já mostrar como fazer as configurações por lá (mas sem utilizar seu serviço de DNS).

De maneira geral, os serviços da Amazon podem ser acessados pelo "console", através do endereço https://console.aws.amazon.com, sendo necessários um cadastro prévio (gratuito) e a posterior autenticação para acesso à área pessoal de gerenciamento de serviços.



Hospedando o site no Amazon S3

O Amazon S3 (Simple Storage Service), como o próprio nome já diz, é o serviço de storage da Amazon. Através desse serviço, podemos armazenar os arquivos dos nossos sites de forma muito simples (a própria Amazon utiliza essa serviço para hospedar seus sites globais).

O painel de controle do S3 pode ser acessado diretamente pela URL "https://console.aws.amazon.com/s3".

Para hospedar o site Let's Boxe! (um website estático, bem simples), foram criados dois "buckets": a) "letsboxe.com.br" (principal); e b) "www.letsboxe.com.br".




Vamos primeiro à criação e configuração do bucket principal (sem o "www").

1. No menu "Actions", clicar em "Create Bucket...".



2. Digitar o nome do bucket (nome do domínio) e a região física onde os arquivos serão armazenados - o que influencia na latência nos acessos.


3. Pode-se configurar o serviço de log dos acessos clicando em "Set Up Logging".


4. Após clicar em "Create", o conteúdo do bucket e suas propriedades serão exibidos.

*É claro que, no momento da criação, o conteúdo do bucket estará vazio (na imagem existe conteúdo por se tratar de um bucket previamente criado).

5. Na aba "Permissions", observar as permissões definidas para o usuário utilizado na Amazon AWS e, se for o caso, pro serviço de log.


6. Nessa mesma aba, clicar no botão "Add bucket policy" e adicionar a política acesso abaixo (trocando apenas o nome do bucket).


*Para facilitar, o texto abaixo pode ser copiado:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AddPerm", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::letsboxe.com.br/*" } ] }

Obs.: Quando configuramos um bucket como um website, temos que configurar todos os objetos que queremos servir para serem publicamente legíveis. A política acima garante acesso para todos aos objetos presentes no diretório indicado (nesse caso, o diretório raiz do bucket). Claro que poderíamos melhorar essa regra, excluindo possíveis diretórios privados (sendo retornado um erro 403, "Access Denied", para qualquer arquivo solicitado que não tiver essa permissão de leitura atribuída).

*Para mais informações sobre políticas de segurança envolvendo os buckets, consulte a documentação: "Using Bucket Policies and User Policies".


7. Na aba "Static Website Hosting", selecionar a opção "Enable website hosting" e digitar o nome do arquivo de index e do arquivo de erro (ambos devem estar presentes na raiz no bucket) e clicar em "Save".



Vamos agora à criação e configuração do segundo bucket (com o "www").

1. Repita os passos de 1 a 4, utilizados na criação do bucket principal, colocando o "www." na frente do nome do bucket (nome do domínio).

2. Na aba "Static Website Hosting", selecionar a opção "Redirect all requests to another host name", digitar o nome do bucket principal no campo "Redirect all requests to" e Salvar.


Pronto, já estão configurados os dois buckets. Agora podemos fazer o upload dos arquivos do site para o bucket principal.


Carregando os arquivos do Website no bucket principal

Esse procedimento pode ser utilizado tanto para o primeiro carregamento dos arquivos, quanto para as futuras atualizações do site. Lembrando que os arquivos do website só serão carregados para o bucket principal (sem o "www"), sendo que o outro bucket (com o "www") só apontará pra ele.

1. Com o bucket selecionado, no menu "Actions", clicar em "Upload".


2. Na janela aberta, pode-se selecionar os arquivos para upload.


*Se clicar em "Add files", só será possível fazer upload de arquivos, ficando de fora os diretórios. A melhor maneira de selecionar todos os arquivos do website de uma vez é arrastando o conteúdo da pasta de deploy para a área em cinza "Drag and drop files and folders to upload here".

3. Selecionados os arquivos, pode-se fazer algumas configurações adicionais, como encriptação dos arquivos no servidor (clicando em "Set details"), ou, simplesmente, já clicar em "Start Upload".


4. Após o upload dos arquivos, para garantir o acesso público aos mesmos, pode-se selecioná-los e, no menu "Actions", clicar em "Make Public". 


Com isso, vai ser adicionada uma permissão de leitura para todos ("Everyone"), que pode ser conferida selecionando um dos arquivos e, na seção "Properties", abrindo a aba "Permissions".


5. Outra questão importante, para evitar cache de arquivos nos navegadores, é selecionar esses arquivos e, na seção "Properties", na aba "Metadata", definir um "max-age" (em segundos) pro "Cache-Control".



Bom, o próximo passo agora é configurar o servidor DNS, para apontar para os endpoints dos nossos buckets.


Configurando o Servidor DNS (Route 53)

O Route 53 é o serviço de Domain Name System (DNS) da Amazon. O interessante de se utilizar esse serviço de DNS (ao invés do serviço do registro.br, por exemplo) é que ele "casa" muito bem com outros serviços da Amazon, como o que acabamos de utilizar: o Amazon S3.

O painel de controle do Route 53 pode ser acessado diretamente pela URL "https://console.aws.amazon.com/route53".

1. No menu "Hosted Zones", clicar em "Create Hosted Zone" e preencher o campo "Domain Name" com o nome de domínio.



2. A hosted zone criada será listada na tabela e, clicando nela, serão apresentadas informações sobre a mesma.


Obs.: Para uma hosted zone recém criada, inicialmente só existirão 2 "Record Sets".

3. Clicar em "Go to Record Sets".



4. Os dois primeiros (tipos SOA e NS) já estarão criados e configurados. Deve-se então criar os outros dois (tipo A), um relativo ao bucket principal (sem o "www") e o outro ao segundo bucket (com o"www").

5. Para criar o Record Set do bucket principal, clicar em "Create Record Set" e preencher o formulário da seguinte forma: a) deixar o prefixo do campo "Name" em branco; b) manter o campo "Type" como "A - IPv4 address"; c) Marcar a opção "Alias" como "Yes"; d) clicar no campo "Alias Target" e selecionar o endpoint correspondente ao bucket criado no Amazon S3; e) Clicar em "Create".


6. Para criar o Record Set do segundo bucket, proceder da mesma forma que o primeiro, mas no item (a), preencher o prefixo do campo "Name" com "www.".



7. Ao final, devem ser observados os "Record Sets"apresentados na imagem do item 3.


Configurando o registro.br

Se você adquiriu seu domínio através do registro.br, como já estamos utilizando o serviço de DNS da própria Amazon, vamos precisar apenas fazer uma pequena configuração, informando os servidores "Master" e "Slave" da Amazon que iremos utilizar.


Esses valores podem ser obtidos dentre os 4 disponíveis no serviço Route 53, no Record Set do tipo "NS".

A dica aqui é fazer um "ping" nos 4 e utilizar o mais rápido como Master e o segundo mais rápido como Slave. Exemplo:

$ ping ns-1478.awsdns-56.org
PING ns-1478.awsdns-56.org (205.251.197.198): 56 data bytes
64 bytes from 205.251.197.198: icmp_seq=0 ttl=56 time=29.196 ms
64 bytes from 205.251.197.198: icmp_seq=1 ttl=56 time=29.974 ms
64 bytes from 205.251.197.198: icmp_seq=2 ttl=56 time=29.408 ms
64 bytes from 205.251.197.198: icmp_seq=3 ttl=56 time=30.176 ms

Pronto! Agora é só esperar (algumas horas) e observar a propagação do DNSwww.whatsmydns.net/#NS/letsboxe.com.br


E onde entra o Cloud Front então?

O Cloud Front é um serviço da Amazon para entrega de conteúdo na Web, que também poderia ser utilizado em conjunto com o Amazon S3, para disponibilização de websites.

De fato, o Cloud Front é um serviço de CDN (Content Delivery Network), replicando conteúdo em vários data-centers pelo mundo, sendo bastante indicado para casos de websites com maior número de arquivos de mídia (imagens, vídeos, etc) e/ou que tenham como requisito alta disponibilidade e performance.

Por outro lado, o custo de hospedagem ficaria um pouco mais alto; além do tempo de atualização de arquivos do site ser maior (pela necessidade de replicação em diferentes servidores).

O painel de controle do Cloud Front pode ser acessado diretamente pela URL "https://console.aws.amazon.com/cloudfront". Mas deixarei os detalhes de sua configuração para um post futuro.

No caso da configuração de DNS para um domínio no registro.br, ela ficaria algo assim:



Bom pessoal, com esse post tentei passar um pouco da experiência que tive para hospedar um site simples e estático na estrutura de cloud da Amazon. Como não sou especialista no assunto, sendo que o meu foco é mais a programação em si, pode ser que algum detalhe tenha ficado de fora. Além disso, procurei utilizar configurações mais básicas, para fins didáticos. De qualquer forma, fico aberto a sugestões de alterações!



quarta-feira, 12 de março de 2014

Panorama geral do mercado mobile

No dia 12 de Fevereiro foi apresentado mais um relatório do IDC que mostra o panorama do mercado mobile em cada trimestre: "Worldwide Quarterly Mobile Phone Tracker".

De acordo com o relatório, as plataformas Android e iOS continuam a dominar o mercado de smartphones globalmente, representando juntas 95.7% do mercado no último trimestre de 2013 (93.8%, considerando todo o ano).


O destaque total continua sendo o Android, que teve 78.6% do mercado em 2013 (sendo embarcado em quase 800 milhões de novos devices).


No contexto dos smartphones Android, a Samsung foi o destaque como fabricante, representando 39,5% desses aparelhos. Em segundo lugar ficou a Huawei, seguida de perto por outros fabricantes, como LG, Lenovo, Coolpad e Sony. Contudo, se considerarmos a compra da Motorola pela chinesa Lenovo, esse fabricante passará a ocupar o segundo lugar no ranking.

Com relação ao custo dos smartphones, no gráfico abaixo, pode-se notar que o preço médio dos aparelhos Android, que já estavam entre os mais acessíveis em 2010, caíram ainda mais - tendo o menor preço médio entre as principais plataformas.


Neste mesmo gráfico, pode-se observar que os aparelhos com Windows Phone também tiveram uma queda de preço. Além desse fato, com a incorporação da divisão de telefones da Nokia pela Microsoft e com o suporte de de outros fabricantes, a previsão do IDC é que essa plataforma tenha o maior crescimento do mercado até 2018.

Operating System2014 Shipment Volumes*2014 Market Share2018 Shipment Volumes*2018 Market Share2014-2018 CAGR
Android950.578.9%1,321.176.0%10.7%
iOS179.914.9%249.614.4%10.2%
Windows Phone47.03.9%121.87.0%29.5%
BlackBerry11.91.0%5.30.3%-22.6%
Others15.11.3%40.72.3%32.7%
Total1,204.4100.0%1,738.5100.0%11.5%
Fonte: IDC Worldwide Mobile Phone Tracker, February 12, 2014


quarta-feira, 2 de outubro de 2013

Palestra online sobre MEAN (MongoDB, ExpressJS, AngularJS e Node.js) - amanhã (03/10), às 13:00h (BRT)

Amanhã (03/10) será transmitida uma palestra online sobre MEAN - um acrônimo que representa uma pilha de tecnologias para desenvolvimento Web (MongoDB, ExpressJS, AngularJS e Node.js).

O primeiro palestrante será Valeri Karpov (do MongoDB), que cunhou o termo "MEAN". Ele explicará porque selecionou essas tecnologias e porque outros desenvolvedores deveriam fazer o mesmo. Depois, Ward Bell (da IdeaBlade) falará um pouco sobre a utilização do BreezeJS para lidar, de maneira simples, com os dados de aplicações de grande porte. Por fim, palestrantes da StrongLoop falarão sobre como aplicar o MEAN em ambientes mobile empresariais.

Acompanhe a palestra abaixo:



Perguntas poderão ser feitas após o evento nesse link.


"MEAN is a full app development stack including MongoDB, ExpressJS, AngularJS and node.js.  In this hour we'll visit with Valeri Karpov of MongoDB who first coined the term.  He'll cover background on why he selected these components and why other developers might choose the same stack.  From there, we'll chat with Ward Bell from IdeaBlade discussing how BreezeJS makes managing data simpler in large applications.  Our last speakers are from StrongLoop.  They'll present on how MEAN can work for mobile enterprise environments.  We'll end with a short Q&A."


sexta-feira, 16 de agosto de 2013

Sass - Indo Além do CSS

Sass é uma meta-linguagem do CSS (construída sobre o CSS) que é utilizada para descrever o estilo de um documento de maneira estruturada e legível, provendo mais poder que um CSS tradicional. 

O Sass provê uma sintaxe mais simples e elegante para o CSS e implementa diversas funcionalidades que são úteis para se criar estilos mais fáceis de serem mantidos e adaptados.

Bom, mas a melhor forma de entender o que é o Sass é vendo seu funcionamento na prática, então vamos ao que interessa!


Instalando o Sass

Antes de mais nada, a primeira coisa a se fazer é instalar o Sass na máquina de desenvolvimento e, para isso, é necessário ter o Ruby já instalado (o Sass é uma "gema", ou seja, uma aplicação feita em Ruby).

Obs.: No Mac OS, o Ruby já vem instalado por padrão. Já no Windows e no Linux, é necessário fazer a sua instalação - no caso do Linux, usar o package manager; no caso do Windows, o instalador pode ser baixado aqui (marcar a opção para incluir o diretório "bin" no PATH do sistema).

Para verificar se o Ruby está corretamente instalado, execute o comando "ruby -v", que retornará no console a versão que está rodando.

Para instalar o Sass, basta executar o comando abaixo no console.
gem install sass

Criando o primeiro arquivo SCSS

O Sass trabalha com arquivos com a extensão "scss". Esses arquivos, se estiverem sendo "monitorados" pelo Sass, serão - sempre que alterados e salvos - convertidos automaticamente em arquivos ".css" correspondentes. Os arquivos ".css" é que serão interpretados pelo navegador, como de costume.

Dessa forma, o desenvolvedor vai criar e alterar apenas os arquivos ".scss", deixar com que o Sass converta esses arquivos e vai então fazer o deploy da aplicação usando apenas os arquivos ".css" que forem gerados.

Para fazer o primeiro teste, crie um arquivo "estilos.scss" com um bloco de notas e execute o comando abaixo para que o Sass comece a fazer o seu monitoramento.
sass --watch estilos.scss:estilos.css

O arquivo "estilos.css" será então automaticamente criado e, daqui pra frente, sempre que o arquivo "estilos.scss" for alterado, o arquivo "estilos.css" será imediatamente atualizado.

Para fazer o teste, inclua o conteúdo abaixo no "estilos.scss", salve o arquivo e abra o "estilos.css" para observar seu conteúdo.
#navbar {
  width: 80%;
  height: 23px;
}

Como o que foi inserido é CSS padrão, o arquivo "estilos.css" vai ficar com o mesmo conteúdo (com exceção do fechamento do colchete, que ficará logo após o último ";" - mas isso é configurável no Sass).

Obs.: Para se trabalhar com múltiplos arquivos ao mesmo tempo, pode-se fazer o Sass monitorar um diretório inteiro de arquivos ".scss", sendo gerados os arquivos ".css" em outro diretório, conforme o exemplo abaixo:
sass --watch diretorio_base/sass:diretorio_base/compiled


Conhecendo as funcionalidades do Sass

Bom, até agora geramos um arquivo ".css" utilizando um arquivo ".scss", mas com o conteúdo de um CSS tradicional. Agora, vamos ao que interessa: as funcionalidades que são o diferencial do Sass e fazem com que ele se torne uma ferramenta poderosíssima no apoio ao desenvolvimento de páginas ou sistemas Web.

1. Aninhamento ("Nesting")

Ao escrevermos um CSS, com frequência acabamos tendo que repetir muitos seletores pais. Por exemplo, podemos ter "#navbar ul", "#navbar li" e "#navbar li a", conforme o exemplo abaixo.
#navbar {
  width: 80%;
  height: 23px; 
}
  #navbar ul {
    list-style-type: none; 
  }
  #navbar li {
    float: left; 
  }
    #navbar li a {
      font-weight: bold; 
    }

Para declarar esse conteúdo em um arquivo Sass, sem ter que ficar repetindo os seletores, podemos fazer uso do recurso de aninhamento, conforme pode ser visto abaixo.
#navbar {
  width: 80%;
  height: 23px;
  ul { list-style-type: none; }
  li {
    float: left;
    a { font-weight: bold; }
  }
}

Obs.: Também é possível aninhar propriedades. Por exemplo, com o Sass não é preciso ficar repetindo o "border-", "border-left" e "border-right", como no exemplo abaixo.
.fakeshadow {
  border-style: solid;
  border-left-width: 4px;
  border-left-color: #888;
  border-right-width: 2px;
  border-right-color: #ccc;
}
Ao invés disso, pode-se utilizar o aninhamento, facilitando a leitura e manutenção desse conteúdo:
.fakeshadow {
  border: {
    style: solid;
    left: {
      width: 4px;
      color: #888;
    }
    right: {
      width: 2px;
      color: #ccc;
    }
  }
}

1.1. Pseudo-classes e referência ao pai

Outra coisa comum de ser feita no CSS é utilizar seletores contendo pseudo-classes como ":hover" e ":visited", conforme pode ser visto abaixo.
a {
  color: #ce4dd6;
}
  a:hover {
    color: #ffb3ff;
  }
  a:visited {
    color: #c458cb;
  }

No CSS, cada seletor desses deve fazer referência ao elemento "pai" (o "a", no exemplo acima). Já no Sass, a referência ao seletor pai pode ser substituída pelo caractere especial "&", fazendo-se o aninhamento dos seletores filhos (contendo as pseudo-classes) conforme abaixo.
a {
  color: #ce4dd6;
  &:hover { color: #ffb3ff; }
  &:visited { color: #c458cb; }
}

2. Variáveis

Um recurso interessante do Sass é a possibilidade de declaração de variáveis, que poderão ser reutilizadas muitas vezes na folha de estilos. Uma variável inicia com o caractere "$" e é declarada como se fosse uma propriedade normal do CSS, usando valores de atributos convencionais, conforme o exemplo abaixo.

Arquivo SCSS:
$cor-principal: #ce4dd6;
$estilo: solid;

#navbar {
  border-bottom: {
    color: $cor-principal;
    style: $estilo;
  }
}

a {
  color: $cor-principal;
  &:hover { border-bottom: $estilo 1px; }
}

Arquivo CSS gerado:
#navbar {
  border-bottom-color: #ce4dd6;
  border-bottom-style: solid;
}

a {
  color: #ce4dd6;
}
  a:hover {
    border-bottom: solid 1px;
  }

A grande vantagem de se utilizar variáveis é poder fazer uma alteração (por exemplo, de cor, tamanho ou característica) em um só lugar, e essa alteração se refletir em vários pontos da folha de estilos.

2.1. Operações e Funções

Além da utilização direta de variáveis, é possível utilizar operações matemáticas (+, -, *, / e %) e funções pré-definidas (para cores, números, strings, listas, fazer introspecção, etc) para cálculos dinâmicos de valores de propriedades, conforme o exemplo abaixo.

Arquivo SCSS:
#navbar {
  $navbar-width: 800px;
  $items: 5;
  $navbar-color: #ce4dd6;

  width: $navbar-width;
  border-bottom: 2px solid $navbar-color;

  li {
    float: left;
    width: $navbar-width/$items - 10px;
    background-color: lighten($navbar-color, 20%);
    &:hover {
      background-color: lighten($navbar-color, 10%);
    }
  }
}

Arquivo CSS gerado:
#navbar {
  width: 800px;
  border-bottom: 2px solid #ce4dd6; }
  #navbar li {
    float: left;
    width: 150px;
    background-color: #e5a0e9; }
    #navbar li:hover {
      background-color: #d976e0; }

2.2. Interpolação

Além de serem utilizadas para atribuição de valores de propriedades, as variáveis podem compor o nome de propriedades e seletores, através do uso de "#{}", conforme pode ser observado abaixo.

Arquivo SCSS:
$vert: top;
$horz: left;
$radius: 10px;
.rounded-#{$vert}-#{$horz} {
  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}

Arquivo CSS gerado:
.rounded-top-left {
  border-top-radius: 10px;
  -moz-border-radius-top: 10px;
  -webkit-border-top-radius: 10px; }

3. Mixins

O mixin é um dos recursos mais poderosos do Sass - ele permite o reuso de estilos, ao invés de ficar copiando e colando trechos de código.

Para se criar um mixin, basta usar a diretiva "@mixin", dar um nome para ele, e criar um bloco com os estilos que serão reutilizados. E, para utilizar um mixin, basta usar a diretiva "@include".

Arquivo SCSS:
@mixin rounded-top-left {
  $vert: top;
  $horz: left;
  $radius: 10px;

  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}

#navbar li { @include rounded-top-left; }
#footer { @include rounded-top-left; }

Arquivo CSS gerado:
#navbar li {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }

#footer {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }

3.1. Utilizando argumentos nos Mixins

O grande poder no uso dos mixins é a possibilidade de criar argumentos para eles. Dessa forma, pode-se passar parâmetros diferentes cada vez que um mixin for utilizado. Além disso, as variáveis declaradas como argumentos podem ter valores padrões, para o caso de não serem passados nenhum valor pra elas.

Arquivo SCSS:
@mixin rounded($vert, $horz, $radius: 10px) {
  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}
#navbar li { @include rounded(top, left); }
#footer { @include rounded(top, left, 5px); }
#sidebar { @include rounded(top, left, 8px); }

Arquivo CSS gerado:
#navbar li {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }
#footer {
  border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  -webkit-border-top-left-radius: 5px; }
#sidebar {
  border-top-left-radius: 8px;
  -moz-border-radius-topleft: 8px;
  -webkit-border-top-left-radius: 8px; }

4. A diretiva @import e os arquivos "partials"

O CSS tradicional já possui a diretiva "@import" para que seja possível quebrar um arquivo de folha de estilos grande em arquivos menores e facilitar a organização e manutenção do código. O problema é que para cada arquivo referenciado em um @import dentro de um CSS é feita uma requisição HTTP separada, o que pode deixar o carregamento da página mais lento.

Dessa forma, no Sass, a diretiva "@import" faz com que as folhas de estilos referenciadas no arquivo SCSS sejam automaticamente injetadas no arquivo CSS gerado. Assim, mantêm-se a organização das folhas de estilo, sem se ter esse overhead a mais no carregamento das páginas.

Esses arquivos importados são chamados de "partials" e, por convenção do Sass, sempre têm seus nomes iniciados por "_".

No exemplo abaixo, o arquivo "estilos.scss" importa o arquivo "_rounded.scss" e o arquivo css correspondente (gerado pelo Sass) vai ser o "estilos.css".

_rounded.scss
@mixin rounded($vert, $horz, $radius: 10px) {
  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}

estilos.scss
@import "rounded";
#navbar li { @include rounded(top, left); }
#footer { @include rounded(top, left, 5px); }
#sidebar { @include rounded(top, left, 8px); }

estilos.css
#navbar li {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }

#footer {
  border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  -webkit-border-top-left-radius: 5px; }

#sidebar {
  border-top-left-radius: 8px;
  -moz-border-radius-topleft: 8px;
  -webkit-border-top-left-radius: 8px; }


Considerações finais

Bom, o que foi apresentado até agora foi apenas um apanhado geral do funcionamento e das principais funcionalidades do Sass. É interessante também dar uma olhada na documentação de referência do Sass para conhecer detalhes do que foi apresentado e mais algumas funcionalidades não citadas nesse post.


Referências utilizadas: grande parte dessas informações foram tiradas do site oficial do Sass, sendo feita uma seleção, tradução, interpretação, organização e complementação com outras informações.