Construíndo um bot assistente virtual utilizando o Textc

Os bots de mensagem – ou chatbots – são programas que permitem a interação através de mensagens para oferecer algum tipo de serviço. Apesar de não ser uma tecnologia nova, vem ganhando destaque nas notícias desde que o Facebook, Microsoft e outras empresas anunciaram investimentos em plataformas para construção deste tipo de aplicação.

Um dos principais argumentos para o uso dos bots é que o modelo de distribuição de serviços através de aplicativos móveis está saturado. Existe uma resistência por parte dos usuários de instalar novos aplicativos para uso de serviços simples. Por exemplo, imagine que se cada pizzaria de sua cidade oferecesse um aplicativo para realizar o pedido de pizza, você precisaria ter aplicativos diferentes para pedir pizza em lugares variados. Mas e se você não precisasse instalar nenhum aplicativo novo e utilizar os próprios aplicativos de mensagem que você (provavelmente) já possui para este fim? É esta oportunidade que Facebook, Microsoft, Google, Slack e outras grandes empresas estão tentando explorar.

bots1

Oferecer uma interface amigável aos usuários de bots é um grande desafio, já que a forma de entrada padrão disponível é o texto – uma interface sem estrutura. Afinal, não há garantia do que o usuário vai escrever, nem da forma, gramática, sintaxe, etc. Existem soluções para tentar contornar esta limitação – como o uso de botões nos canais de mensagem (como Telegram e Messenger) que conduzem a navegação do usuário ou inteligência artificial para tentar “adivinhar” o que o usuário está querendo dizer. Cada uma tem seus prós e contras e neste artigo iremos demonstrar como fazer isso utilizando a biblioteca de processamento de linguagem natural Textc. A biblioteca está disponível para C# e pode ser instalada através do Nuget.

De maneira resumida, a Textc permite definir de sintaxes de texto e associá-las a chamadas de métodos de uma classe. Uma sintaxe define uma estrutura de texto, com tokens e seus tipos, sendo cada token mapeado a parâmetros de um método. Para ilustrar iremos construir um assistente virtual que permite o armazenamento de lembretes, de forma semelhante ao que o Google Now oferece.

Desenhando a conversa

O primeiro passo é enumerar as diferentes formas que o usuário poderá interagir com seu bot. Alguns exemplos:

  1. Lembrar de ir ao médico
  2. Lembre me amanhã de pagar a conta de luz
  3. Me lembre de fazer compras hoje a tarde

São estruturas de texto diferentes mas que possuem informações parecidas:
– O comando para adicionar um lembrete: Lembrar de, Lembre me, Me lembre de
– O texto do lembrete: ir ao médico, pagar a conta de luz, fazer compras
– A data do lembrete: amanhã, hoje
– A hora do lembrete: a tarde

No Textc, estas informações são mapeadas em um ou mais tokens, sendo que o conjunto de tokens em uma sentença é chamado de sintaxe.

Isolando as informações presentes nos exemplos acima, temos:
1. (lembrar de) (ir ao médico)
2. (Lembre me) (amanhã de) (pagar a conta de luz)
3. (Me lembre de) (fazer compras) (hoje) (a tarde)

Para atendermos a estas sintaxes, precisaremos de implementar em nosso calendário três comandos diferentes:
1. Adicionar novo lembrete
2. Adicionar novo lembrete para uma data
3. Adicionar novo lembrete para um data e uma hora

Cada comando deverá ser mapeado a um método diferente em uma classe, como veremos mais a frente. Em nosso exemplo, teremos apenas uma sintaxe associada por comando, mas é possível ter várias sintaxes diferentes para cada um.

Para representarmos as sintaxes e seus tokens, utilizaremos a CSDL – Command Syntax Definition Language – uma notação simples oferecida pela biblioteca. Uma declaração CSDL é constituída de uma ou mais definições de tokens, sendo cada uma representada da seguinte forma:

name:Type(initializer)

Onde:
name – O nome do token que será extraido da entrada. Este valor pode ser utilizado no mapeamento com os parâmetros do método de uma classe. Opcional.
type – O tipo do token no texto. A biblioteca define alguns tipos como Word (uma palavra), Text (uma ou mais palavras) e Integer (número inteiro). Obrigatório.
initializer – Valor de inicialização, sendo utilizado para limitar os valores válidos para o tipo. Por exemplo, no tipo Word, determina quais são as palavras válidas para serem consideradas na entrada do usuário. Opcional.

Sendo assim, podemos representar a primeira sintaxe da seguinte forma:

:Word(lembrar) :Word?(de) reminder:Text

Não é necessário nomear tokens que não carreguem informações relevantes para o processamento do comando, como os dois primeiros desta sintaxe. O importante aqui é só o valor de reminder, que é o texto do lembrete. Além disso, alguns tokens podem ser marcados como opcionais em uma sintaxe, bastando incluir um ponto-de-interrogação depois da declaração do tipo – como fizemos na preposição “de” acima. Neste caso, a sintaxe é válida para entradas como lembrar de ir ao médico ou lembrar médico.

A sintaxe do segundo comando é semelhante a primeira, com uma informação adicional – a data do lembrete. Ela também inclui outros tokens que não estão presentes na primeira mas que apenas constituem a estrutura do texto. Representando-a com CSDL, temos:

:Word(lembre) :Word?(me) date:Word?(hoje,amanha,eventualmente) :Word?(de) reminder:Text

Por fim, precisamos configurar a terceira sintaxe, que a princípio parece simples:

:Word?(me) :Word(lembre) :Word(de) reminder:Text date:Word?(hoje,amanha,eventualmente) :Word?(a) time:Word?(manha,tarde,noite)

Só que existe uma pegadinha: por padrão, o processamento ocorre da esquerda para a direita e quando alcançado, o token reminder do tipo Text irá capturar todo o restante da entrada do usuário, e nunca teríamos match dos demais tokens à direita do mesmo (date e time). Isso acontece porque o tipo de token Text é guloso ou seja, consome todo o restante da entrada do usuário. Por este motivo, ele deve ser o último token a ser processado em uma sintaxe. Para isso, podemos alterar a direção de parse em qualquer ponto da sintaxe ao incluirmos o modificador ~ (til) após o tipo de um token.

Como precisamos que o token reminder seja o último a ser processado, a direção de parse deve mudar após o processamento do token imediatamente a esquerda deste – no caso a palavra de. Neste caso, teríamos:

:Word?(me) :Word(lembre) :Word~(de) reminder:Text date:Word?(hoje,amanha,eventualmente) :Word?(a) time:Word?(manha,tarde,noite)

Assim, logo após o match da palavra de, o parse continuará a partir do final da sintaxe, buscando no final da entrada o valor do token time.

Fazendo funcionar

Para atendermos aos comandos definidos acima, criaremos uma classe Calendar com três métodos – uma para cada comando – como a seguir:

public class Calendar
{
    public Task AddReminderAsync(string reminder)
        => AddReminderForDateAsync(reminder, "eventualmente");

    public Task AddReminderForDateAsync(string reminder, string date)
        => AddReminderForDateAndTimeAsync(reminder, date, "manhã");

    public async Task AddReminderForDateAndTimeAsync(string reminder, string date, string time)
    {
        // TODO: Store the reminder for the specified date/time
        return $"O lembrete '{reminder}' foi adicionado para {date} no período da {time}";
    }
}

Por último, precisamos realizar o bind das sintaxes com os comandos, que pode ser feito da seguinte forma:

// Initializamos e realizamos o parse das sintaxes
var syntax1 = CsdlParser.Parse(
    ":Word(lembrar) :Word?(de) reminder:Text");
var syntax2 = CsdlParser.Parse(
    ":Word(lembre) :Word?(me) date:Word?(hoje,amanha,eventualmente) :Word?(de) reminder:Text");
var syntax3 = CsdlParser.Parse(
    ":Word?(me) :Word(lembre) :Word~(de) reminder:Text date:Word?(hoje,amanha,eventualmente) :Word?(a) time:Word?(manha,tarde,noite)");

// Incluimos um OutputProcessor para dar saída à resposta dos métodos no Console
var addReminderOutputProcessor = new DelegateOutputProcessor(
    (text, context) => Console.WriteLine(text));

// Instanciamos a nossa classe
var calendar = new Calendar();

// Definimos os CommandProcessors, um para cada método
var commandProcessor1 = new ReflectionCommandProcessor(
    calendar,
    nameof(AddReminderAsync),
    true,
    addReminderOutputProcessor,
    syntax1);
var commandProcessor2 = new ReflectionCommandProcessor(
    calendar,
    nameof(AddReminderForDateAsync),
    true,
    addReminderOutputProcessor,
    syntax2);
var commandProcessor3 = new ReflectionCommandProcessor(
    calendar,
    nameof(AddReminderForDateAndTimeAsync),
    true,
    addReminderOutputProcessor,
    syntax3);

// Criamos o TextProcessor onde os CommandProcessors estarão registrados
var textProcessor = new TextProcessor();
textProcessor.CommandProcessors.Add(commandProcessor1);
textProcessor.CommandProcessors.Add(commandProcessor2);
textProcessor.CommandProcessors.Add(commandProcessor3);

// Por último, incluímos alguns PreProcessors para normalizar a entrada
textProcessor.TextPreprocessors.Add(new TextNormalizerPreprocessor());
textProcessor.TextPreprocessors.Add(new ToLowerCasePreprocessor());

E é isso, seu bot já esta pronto para funcionar como um assistente virtual básico:

try
{
    var inputText = Console.ReadLine();
    await textProcessor.ProcessAsync(inputText, new RequestContext(), CancellationToken.None);
}
catch (MatchNotFoundException)
{
    Console.WriteLine("Não entendi o que você quis dizer.");
}

textc.png

No próximo post, iremos mostrar como otimizar este bot utilizando algoritmos de aproximação e o contexto da conversa.

O código do Textc e deste e outros exemplos estão no Github. E você pode conversar com este bot no Telegram.

Anúncios

Doze passos para se ter um código melhor (Parte 1)

Joel Spolsky é ex-funcionário da Microsoft, um dos fundadores do utilíssimo Stack Overflow e é, além disso, um evangelizador de boas práticas do processo de desenvolvimento de software e tópicos relacionados. No seu blog pessoal, ele mantém uma série de artigos que expõe sua opinião sobre o assunto, sendo vários deles bem conhecidos no meio e são considerados clássicos, sendo utilizados como referência por vários outros bloggers.

Um destes artigos é o The Joel Test: 12 Steps to better code, onde o autor propõe um teste com doze perguntas que serviriam para avaliar a qualidade de uma equipe de desenvolvimento de software. O artigo foi escrito há mais de 12 anos (que é uma eternidade no mundo de TI) e é interessante analisar se as preocupações do autor na época ainda são válidas e verificar o quanto avançamos de modo geral levando em consideração não apenas o tempo que o artigo foi escrito, mas as práticas ágeis de desenvolvimento difundidas hoje em dia.

Nesta primeira parte, iremos analisar as seis primeiras questões.

1 – Você (ou sua equipe) utiliza controle de versão?

Hoje é impossível acreditar que exista alguma empresa séria que desenvolva software e que não use um sistema de controle de versão. Nem mesmo para “equipes” de duas pessoas pode ser considerado viável deixar de utilizar um sistema de controle de versão. Existem várias soluções gratuitas e excelentes baseadas em Mercurial e Git, por exemplo, ou comerciais como o TFS. Mas nenhuma dessas soluções existiam quando Joel escreveu o artigo, nem mesmo o SVN. O sistema mais popular na época era o CVS, que ele inclusive cita no texto. Compartilhar código-fonte via rede ou outra solução semelhante leva ao caos absoluto pois exige extrema disciplina dos desenvolvedores de times de desenvolvimento. Sem um sistema de controle de versão a perda e a necessidade de reescrever código deviam ser problemas comuns.

O que se poderia perguntar hoje em dia é: Você/sua equipe utiliza o controle de versão de forma eficiente?  Realiza branches/merges quando necessário? Utiliza uma estrutura hierárquica organizada? Consegue rastrear as mudanças no código-fonte e associá-las a bugs ou tarefas? Utiliza uma solução centralizada ou distribuída?

2 – Você consegue gerar um build em um passo?

Você consegue gerar os binários de suas aplicações com apenas “um clique” a partir do código-fonte no sistema de controle de versão?  No caso de softwares “de prateleira”, os binários devem estar empacotados em  instaladores .EXE ou .MSI e no caso de websites ou plataformas, devem estar publicados em servidores de desenvolvimento ou staging. Esta pergunta, portanto, está relacionada à automatização do processo de construção do software.

No artigo, o autor sugere que a construção dos binários pode ser feita através de scripts que automatizem o processo. Hoje em dia, o mais comum é que hajam servidores dedicados para esta atividade, os chamados build servers. Estes servidores devem ser neutros (não utilizados por desenvolvedores) e além de gerar os binários, podem executar testes de forma automática e descartar um build gerado se algum dos testes não passar, notificando os desenvolvedores nestes casos. Entre os serviços que provêm estas funcionalidades, pode-se citar o Microsoft Team Foundation Server, TeamCity, CruiseControl, dentre outros.

Apesar da existência deste recurso, ainda é comum que os desenvolvedores gerem os binários diretamente de sua máquina de desenvolvimento e publiquem em produção desta forma. Esta prática gera problemas como o software se comportar diferente quando publicado de máquinas diferentes, pois um desenvolvedor esqueceu de realizar o check-in de uma mudança que foi para produção ou o código só compila na máquina de fulano, dentre outras situações.

Neste ponto, é possível observar que houveram avanços desde quando o artigo foi escrito. Hoje se houve muito falar em “integração contínua” que tem relação com a preocupação por trás dessa pergunta (e mais ainda com a próxima), mas ainda não é algo presente em todas as empresas de tecnologia.

3 – Você realiza builds diários?

Ao se automatizar o processo de construção do software, torna-se possível práticas como builds diários. Esta prática determina que diariamente, em um horário fixo, seja feito um build a partir do código no sistema de controle de versão para validar os check-ins (commits) realizados entre o build anterior e o atual. Caso aconteça algum problema, os desenvolvedores devem trabalhar para corrigir o problema o mais rápido possível. Estes builds podem ocorrer durante a noite (os chamados nightly builds) ou como sugerido pelo artigo, durante o almoço. A sugestão deste horário é para que todos os desenvolvedores adquiram uma rotina de realizar o check-in das mudanças antes de irem almoçar e, ao voltar, possam tomar as ações pertinentes ao status do build: em caso de sucesso, obter a versão mais atualizada do código-fonte no servidor e continuar trabalhando; em caso de falha, o responsável por “quebrar” o build possa corrigir o problema enquanto os demais desenvolvedores continuem trabalhando com a versão pré-build, sem serem afetados.

Esta é uma prática interessante e ajuda a equipe de desenvolvimento a descobrir alguns dos bugs que foram gerados nas últimas 24 horas. Mas para alguns autores, não é suficiente para se ter integração contínua (Continuous Integration – CI). Segundo Martin Fowler, o maior propósito de se ter integração contínua é encontrar os bugs o mais cedo possível e com builds diários existirão problemas que não serão descobertos por um dia inteiro, o que torna a correção dos mesmos mais difícil (quanto mais tarde se descobre um bug, mais díficil e caro é corrigí-lo – mais a frente Joel fala sobre isso). O ideal segundo Fowler é que os builds ocorram sempre que um desenvolvedor realizar um check-in, condicionando o aceite deste ao sucesso do build. E por sucesso ele quer dizer que, além do build não “quebrar”, todos os testes automatizados devem ser executados com sucesso.

Times ágeis devem obrigatoriamente automatizar os builds e ter alguma forma de integração contínua. Hoje é uma prática bem difundida entre as equipes de desenvolvimento de software, mas não necessariamente adotada por todas.

4 – Você tem um banco de dados de bugs?

Ter uma base dos bugs da aplicação é essencial para se ter código de qualidade. Segundo o artigo, muitos desenvolvedores acham que conseguem guardar “de cabeça” os bugs existentes, mas isso é impossível a partir do momento que o número aumenta, o que torna necessário estes bugs estarem registrados em algum lugar. Ele sugere que seja utilizado algum software para bugtracking mas se existir alguma resistência em adotar esse tipo de software pela complexidade, basta ter uma tabela com informações básicas dos bugs, como passos para reprodução, comportamento esperado, comportamento atual, para quem está atribuído e seu status.

A utilização de soluções de bugtracking como Bugzilla , JIRA, TFS e Mantis são comuns hoje em dia e esta pode ser considerada uma prática bem difundida.

5 – Você corrige os bugs existentes antes de escrever um novo código?

Corrigir um bug assim que descoberto diminui o custo da correção, pelo fato do desenvolvedor ainda ter o código “fresco” na sua memória, o que torna a correção mais rápida. Os gerentes de projeto devem considerar em seus cronogramas o tempo para correção de bugs. Caso contrário, pode ocorrer o que ele chama de “método de infinitos defeitos”, onde os desenvolvedores se preocupam apenas em cumprir o cronograma de entregas em detrimento à  qualidade do código. Além disso, o cronograma de um software com poucos bugs é mais preciso do que um com vários bugs em aberto, pelo fato de ser difícil estimar o tempo de correção de determinadas falhas. Por estes motivos, o artigo sugere que os bugs existentes devem ser corrigidos antes de se escrever novas funcionalidades.

Técnicas ágeis como lean development, kanban e DoD (Definition of Done) adotadas hoje em dia por algumas equipes ajudam a resolver este problema. Um desenvolvedor só pode começar a trabalhar em uma nova tarefa se as anteriores estiverem prontas, e por prontas pode-se entender que esteja devidamente testada. Esta definição de pronto (DoD) é a garantia que o processo funcionará e que as entregas têm uma qualidade mínima.

6 – Você tem um cronograma atualizado?

Ter um cronograma atualizado é importante para o planejamento estratégico da empresa em relação ao produto em desenvolvimento. Desenvolvedores, segundo o artigo, tendem a dizer que estará pronto “quando estiver pronto” à equipe de negócios, o que não é aceitável devido às muitas decisões importantes que estão associadas ao cronograma do projeto.

O objetivo de um cronograma é tentar prever o que estará pronto até determinada data. Levando esta necessidade para o mundo ágil, esta informação pode ser obtida através do cruzamento do backlog e da velocidade do time. Portanto, é importante ter um backlog atualizado e devidamente priorizado, além do histórico do que foi feito nas últimas iterações para se calcular a velocidade do time e assim forma, ser possível estimar quais serão as entregas dos próximos sprints.

Os Resign Patterns

Muito se ouve falar dos Design Patterns da Gang of Four, mas sem dúvida os Resign Patterns aqui descritos por Michael Duell estão presentes no dia-a-dia de muitos desenvolvedores…

Resign Patterns
Ailments of Unsuitable Project-Disoriented Software
by
Michael Duell
mitework@yercompany.com

Abstract

Anyone familiar with the book of patterns by the Gang of Four [1] knows that the patterns presented in the book represent elegant solutions that have evolved over time. Unfortunately, extracting these patterns from legacy code is impossible, because nobody knew that they were supposed to be using these patterns when they wrote the legacy code. Hence, this work is a catalog of patterns for the masses. The patterns presented here represent abundant solutions that have endured over time. Enjoy reading the patterns, but please don’t use them!

1 Cremational Patterns

Below is a list of five cremational patterns.

1.1 Abject Poverty

The Abject Poverty Pattern is evident in software that is so difficult to test and maintain that doing so results in massive budget overruns.

1.2 Blinder

The Blinder Pattern is an expedient solution to a problem without regard for future changes in requirements. It is unclear as to whether the Blinder is named for the blinders worn by the software designer during the coding phase, or the desire to gouge his eyes out during the maintenance phase.

1.3 Fallacy Method

The Fallacy method is evident in handling corner cases. The logic looks correct, but if anyone actually bothers to test it, or if a corner case occurs, the Fallacy of the logic will become known.

1.4 ProtoTry

The ProtoTry Pattern is a quick and dirty attempt to develop a working model of software. The original intent is to rewrite the ProtoTry, using lessons learned, but schedules never permit. The ProtoTry is
also known as legacy code.

1.5 Simpleton

The Simpleton Pattern is an extremely complex pattern used for the most trivial of tasks. The Simpleton is an accurate indicator of the skill level of its creator.

2 Destructural Patterns

Below is a list of seven destructural patterns.

2.1 Adopter

The Adopter Pattern provides a home for orphaned functions. The result is a large family of functions that don’t look anything alike, whose only relation to one another is through the Adopter.

2.2 Brig

The Brig Pattern is a container class for bad software. Also known as module.

2.3 Compromise

The Compromise Pattern is used to balance the forces of schedule vs. quality. The result is software of inferior quality that is still late.

2.4 Detonator

The Detonator is extremely common, but often undetected. A common example is the calculations based on a 2 digit year field. This bomb is out there, and waiting to explode!

2.5 Fromage

The Fromage Pattern is often full of holes. Fromage consists of cheesy little software tricks that make portability impossible. The older this pattern gets, the riper it smells.

2.6 Flypaper

The Flypaper Pattern is written by one designer and maintained by another. The designer maintaining the Flypaper Pattern finds herself stuck, and will likely perish before getting loose.

2.7 ePoxy

The ePoxy Pattern is evident in tightly coupled software modules. As coupling between modules increases, there appears to be an epoxy bond between them.

3 Misbehavioral Patterns

Below is a list of eleven misbehavioral patterns.

3.1 Chain of Possibilities

The Chain of Possibilities Pattern is evident in big, poorly documented modules. Nobody is sure of the full extent of its functionality, but the possibilities seem endless. Also known as Non-Deterministic.

3.2 Commando

The Commando Pattern is used to get in and out quick, and get the job done. This pattern can break any encapsulation to accomplish its mission. It takes no prisoners.

3.3 Intersperser

The Intersperser Pattern scatters pieces of functionality throughout a system, making a function impossible to test, modify, or understand.

3.4 Instigator

The Instigator Pattern is seemingly benign, but wreaks havoc on other parts of the software system.

3.5 Momentum

The Momentum Pattern grows exponentially, increasing size, memory requirements, complexity, and processing time.

3.6 Medicator

The Medicator Pattern is a real time hog that makes the rest of the system appear to be medicated with strong sedatives.

3.7 Absolver

The Absolver Pattern is evident in problem ridden code developed by former employees. So many historical problems have been traced to this software that current employees can absolve their software of blame by claiming that the absolver is responsible for any problem reported. Also known as It’s-not-in-my-code.

3.8 Stake

The Stake Pattern is evident in problem ridden software written by designers who have since chosen the management ladder. Although fraught with problems, the manager’s stake in this software is too
high to allow anyone to rewrite it, as it represents the pinnacle of the manager’s technical achievement.

3.9 Eulogy

The Eulogy Pattern is eventually used on all projects employing the other 22 Resign Patterns. Also known as Post Mortem.

3.10 Tempest Method

The Tempest Method is used in the last few days before software delivery. The Tempest Method is characterized by lack of comments, and introduction of several Detonator Patterns.

3.11 Visitor From Hell

The Visitor From Hell Pattern is coincident with the absence of run time bounds checking on arrays. Inevitably, at least one control loop per system will have a Visitor From Hell Pattern that will overwrite
critical data.

4 References

Gamma, E., Helm, R., Johnson, R., Vlissides, J., Design Patterns –
Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995.

—–
Michael Duell is an Engineer at AG Communication Systems, where his
Resign Patterns have been rejected in favor of the Gang
of Four Design Patterns.

“Resign Patterns: Ailments of Unsuitable Project-Disoriented Software,”
The Software Practitioner, Vol. 7, No. 3, May-June 1997, p. 14.

Fonte: http://www.lsd.ic.unicamp.br/~oliva/fun/prog/resign-patterns

REST e APIs Hipermídia

Muito se fala sobre REST e as práticas “corretas” que devem ser adotadas ao construir um sistema baseado neste estilo arquitetural. Mas o que acontece na verdade é uma grande confusão de conceitos que não tem relação com a proposta original do que seria uma aplicação RESTful.

REST é um acrônimo para Representational State Transfer (Transferência representacional de estado) e termo surgiu na dissertação de doutorado de Roy Fielding, que também colaborou (não coincidentemente) com a especificação do protocolo HTTP. Ele definiu alguns pré-requisitos deve devem ser cumpridos para que uma arquitetura possa ser chamada de RESTful, que resumidamente são:

  • Ser cliente-servidor – Deve sempre haver um cliente que realiza as requisições e um servidor que as responde;
  • Sem estado – As requisições feitas pelo cliente devem conter todas as informações necessárias para que o servidor consiga processar o pedido. Ou seja, o servidor não tem seu estado alterado e não trata requisições semelhantes de formas diferentes devido a isso. Note que os recursos que o servidor provê podem ser alterados, e que isso é completamente diferente do estado da aplicação;
  • Cache – As respostas às requisições feitas pelo cliente podem ser marcadas como “cacheáveis” ou “não-cacheáveis” pelo servidor, indicando se podem ou não ser armazenadas em cache pelo cliente;
  • Interface uniforme – Um dos pontos centrais do REST é a ênfase na interface uniforme entre os componentes da arquitetura. As informações devem ser transferidas de forma padronizada. Este pré-requisito define outros quatro pré-requisitos de interface:
    • Identificação dos recursos – Cada recurso deve possuir um identificador universal (URI – Universal Resource Identifier);
    • Representação de recursos – Os recursos são manipulados a partir de suas representações, que podem ser em diversos formatos, como XML, JSON, TEXT, etc. Um detalhe importante que uma aplicação REST não transmite o recurso efetivamente, mas sempre uma representação do mesmo, em um formato pré-acordado entre o cliente e o servidor;
    • Mensagem auto descritivas – Os pedidos e respostas devem conter meta-dados que indicam como o conteúdo transmitido deve ser tratado (cabeçalhos para formato, autenticação, etc.);
    • Utilização de hipermídia para estado da aplicação – Este pré-requisito é o menos cumprido por aplicações autointituladas RESTful: As representações de recursos obtidas em uma aplicação REST devem possuir hiperlinks que permitam a navegação do cliente pelos recursos. Ou seja, diferentemente de arquiteturas baseadas em RPC (Remote Procedure Call), o cliente não deve conhecer previamente as URIs para os recursos da aplicação (apenas a raiz do serviço), sendo que o servidor deve prover links que permita a descoberta dos recursos pelo cliente; não há contrato do serviço e não há garantia que um recurso em uma determinada URI possa estar disponível no futuro;
    • Sistema em camadas – A aplicação deve ser construída em camadas sendo que uma camada só pode ver a camada imediatamente abaixo. O objetivo principal deste pré-requisito é garantir que as aplicações sejam escaláveis;
    • Executar código sob demanda – O cliente deve ser capaz de executar scripts armazenados no servidor de forma a estender as funcionalidades do cliente. Um exemplo disso é a habilidade dos browsers HTTP executarem JavaScripts. Este é o único pré-requisito opcional para arquiteturas REST.

Na teoria, o estilo não depende de nenhum protocolo, mas na prática é sempre implementado utilizando o protocolo HTTP. Portanto, preocupações relacionadas ao formato das URIs (http://servidor.com/lista_de_recursos/chave/), métodos (GET, POST, DELETE, PUT) e códigos de resposta estão relacionadas a utilização do protocolo HTTP de forma correta e não diretamente ao estilo REST. O que leva isso é que o pré-requisito de interface uniforme do REST foi pensado levando em consideração as capacidades do protocolo HTTP.

A World-Wide Web é considerada uma implementação do estilo arquitetural REST. Os browsers são os clientes que requisitam as representações de recursos, retornada no formatos HTML, JPEG, etc. O HTML suporta hipermídia de forma que um cliente não é obrigado a conhecer o caminho de todos os recursos (páginas) da aplicação, mas estes são normalmente apresentados na sua raiz (página inicial). A ideia da transferência representacional de estado está diretamente ligada à hipermídia retornada na junto aos recursos e por isso, uma aplicação não é RESTful se o formato utilizado na representação do recurso não suportar hipermídia.

Pensando na confusão gerada pelo uso do termo REST e suas pré-condições, alguns desenvolvedores estão propondo o uso de um novo termo, chamado Hypermedia API, que pode ser aplicado a APIs que cumprem apenas dois pré-requisitos, que são:

  • Uso correto do protocolo HTTP – Uso dos métodos, códigos de erro, cabeçalhos e formato de URLs definidos na especificação do protocolo HTTP;
  • Formato de retorno com suporte a hipermídia – Existência de hiperlinks que permitam a navegação pelo cliente pelas representações dos recursos, não existência de contrato da API, etc. Um formato que contempla este requisito e está cada vez mais utilizado por APIs hipermídia é o HAL que utiliza como base o JSON e XML.

Com a simplificação dos pré-requisitos, espera-se a diminuição da confusão em torno do termo REST, além da disseminação do conceito de hipermídia, ainda pouco utilizado pelos desenvolvedores de APIs.

Referências:

http://blog.steveklabnik.com/posts/2012-02-23-rest-is-over

http://2beards.net/2012/03/what-the-hell-is-a-hypermedia-api-and-why-should-i-care/

http://kellabyte.com/2011/09/04/clarifying-rest/

http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

MEF como IoC/DI Container

O .NET 4 vem com uma biblioteca chamada MEF – Managed Extensibility Framework que, de acordo com sua definição, ajuda os desenvolvedores a construir aplicações que suas partes são descobertas e construídas em tempo de execução. Na prática, são aplicações com partes “plugáveis”, através (obviamente) de plugins.

Só que é possível, sem muitas dificuldades, utilizar o MEF como um IoC/DI container, com o diferencial que não existe a obrigação de haver um artefato estático que faça o mapeamento dos tipos (por exemplo, um arquivo XML ou uma classe) como a maioria dos outros containers. Além disso, para utilizá-lo, basta importar o assembly System.ComponentModel.Composition do .NET, sem a necessidade de instalar uma biblioteca externa.

Para utilizar o MEF, você precisa basicamente de quatro elementos: Um contrato, um import, um export e um catálogo.

– O contrato é o ponto comum entre um import e um export, e indica a funcionalidade esperada de uma parte. Normalmente é definido através de uma interface, mas pode ser um tipo abstrato, por exemplo.
– O import é onde a parte será plugada, que pode ser uma propriedade, uma coleção (no caso de se esperar várias implementações do mesmo contrato) ou construtor de uma classe. É definido através do atributo [Import] ou [ImportMany]
– O export é o plugin (a parte que será plugada) que contém a implementação da funcionalidade definida pelo contrato. É definido pelo atributo [Export].
– O catálogo contém os tipos exportados e que podem ser utilizados para satisfazer Imports de cada contrato. O MEF vem com quatro tipos de catálogos: DirectoryCatalog (busca os tipos exportados nos assemblies em um determinado diretório – p.e. d:\app\plugins\), AssemblyCatalog (todos os tipos de um assembly), TypeCatalog (você especifica explicitamente quais tipos compoem o catálogo) e AggregateCatalog (permite combinar vários catálogos). Existem diversos outros tipos de catálogos que podem ser encontrados na internet, inclusive alguns que usam mapeamento XML. Os catálogos são utilizados pelo container no MEF (CompositionContainer) para criação dos tipos.

Para quem se interessar, o link abaixo leva a uma série de posts detalhando melhor como utilizar a biblioteca:
http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-toc.aspx

O MEF também tem uma mecânica interessante para lidar com o tempo de vida os objetos. Resumidamente, você pode especificar se a instância é compartilhada (singleton) ou exclusiva no momento da importação ou na exportação dos tipos. Neste link, um dos desenvolvedores da biblioteca (que por sinal é o criador do Castle) explica como trabalhar com esta questão.

Erro 401 com NuGet e Team Foundation Server

Ao trabalhar com o NuGet em um projeto controlado pelo Team Foundation Server (TFS), poderão ocorrer ocasionalmente erros HTTP 401 (TF30063: You are not authorized to access Collection). Isso ocorre por algum problema do Visual Studio para armazenar as credenciais de acesso ao TFS, quando está trabalhando com a extensão do NuGet.

Para resolver isso, basta acessar o endereço do “Team Web Access” do seu Team Foundation pelo Internet Explorer e, ao entrar com as credenciais, marcar que deseja o navegador as armazene. Isso ocorre porque provavelmente o cliente web do Visual Studio utiliza o engine do Internet Explorer, então estes compartilham algumas preferências e configurações. Se mesmo assim o IE não esteja guardando as credenciais, pode ser necessário diminuir o nível de segurança do navegador em sites da intranet, além de adicionar o endereço base do TFS na lista de sites confiáveis.

Produtos e Plataformas

O engenheiro do Google Steve Yegge postou acidentalmente de forma pública no Google+ um texto que critica alguns produtos do Google que não construídos pensando em plataformas, ou seja, não são construídos sobre APIs públicas. A crítica dele está relacionada principalmente ao próprio Google+, mas inclui outros produtos como o Maps e Gmail.

Depois de ver que o texto não estava restrito a apenas os funcionários do Google (ele esqueceu de utilizar o principal recurso do Google+, os tais círculos…), o autor apagou o texto. Mas já era tarde, pois vários usuários já haviam copiado o conteúdo.

O texto é bem interessante e vale a pena a leitura, já que expõe de forma até engraçada conceitos de arquiteturas orientadas a serviço e algumas decisões que os arquitetos de software devem considerar ao construir produtos e plataformas.

Abaixo segue o texto original, em inglês.

Stevey’s Google Platforms Rant

I was at Amazon for about six and a half years, and now I’ve been at Google for that long. One thing that struck me immediately about the two companies — an impression that has been reinforced almost daily — is that Amazon does everything wrong, and Google does everything right. Sure, it’s a sweeping generalization, but a surprisingly accurate one. It’s pretty crazy. There are probably a hundred or even two hundred different ways you can compare the two companies, and Google is superior in all but three of them, if I recall correctly. I actually did a spreadsheet at one point but Legal wouldn’t let me show it to anyone, even though recruiting loved it.

I mean, just to give you a very brief taste: Amazon’s recruiting process is fundamentally flawed by having teams hire for themselves, so their hiring bar is incredibly inconsistent across teams, despite various efforts they’ve made to level it out. And their operations are a mess; they don’t really have SREs and they make engineers pretty much do everything, which leaves almost no time for coding – though again this varies by group, so it’s luck of the draw. They don’t give a single shit about charity or helping the needy or community contributions or anything like that. Never comes up there, except maybe to laugh about it. Their facilities are dirt-smeared cube farms without a dime spent on decor or common meeting areas. Their pay and benefits suck, although much less so lately due to local competition from Google and Facebook. But they don’t have any of our perks or extras — they just try to match the offer-letter numbers, and that’s the end of it. Their code base is a disaster, with no engineering standards whatsoever except what individual teams choose to put in place.

To be fair, they do have a nice versioned-library system that we really ought to emulate, and a nice publish-subscribe system that we also have no equivalent for. But for the most part they just have a bunch of crappy tools that read and write state machine information into relational databases. We wouldn’t take most of it even if it were free.

I think the pubsub system and their library-shelf system were two out of the grand total of three things Amazon does better than google.

I guess you could make an argument that their bias for launching early and iterating like mad is also something they do well, but you can argue it either way. They prioritize launching early over everything else, including retention and engineering discipline and a bunch of other stuff that turns out to matter in the long run. So even though it’s given them some competitive advantages in the marketplace, it’s created enough other problems to make it something less than a slam-dunk.

But there’s one thing they do really really well that pretty much makes up for ALL of their political, philosophical and technical screw-ups.

Jeff Bezos is an infamous micro-manager. He micro-manages every single pixel of Amazon’s retail site. He hired Larry Tesler, Apple’s Chief Scientist and probably the very most famous and respected human-computer interaction expert in the entire world, and then ignored every goddamn thing Larry said for three years until Larry finally — wisely — left the company. Larry would do these big usability studies and demonstrate beyond any shred of doubt that nobody can understand that frigging website, but Bezos just couldn’t let go of those pixels, all those millions of semantics-packed pixels on the landing page. They were like millions of his own precious children. So they’re all still there, and Larry is not.

Micro-managing isn’t that third thing that Amazon does better than us, by the way. I mean, yeah, they micro-manage really well, but I wouldn’t list it as a strength or anything. I’m just trying to set the context here, to help you understand what happened. We’re talking about a guy who in all seriousness has said on many public occasions that people should be paying him to work at Amazon. He hands out little yellow stickies with his name on them, reminding people “who runs the company” when they disagree with him. The guy is a regular… well, Steve Jobs, I guess. Except without the fashion or design sense. Bezos is super smart; don’t get me wrong. He just makes ordinary control freaks look like stoned hippies.

So one day Jeff Bezos issued a mandate. He’s doing that all the time, of course, and people scramble like ants being pounded with a rubber mallet whenever it happens. But on one occasion — back around 2002 I think, plus or minus a year — he issued a mandate that was so out there, so huge and eye-bulgingly ponderous, that it made all of his other mandates look like unsolicited peer bonuses.

His Big Mandate went something along these lines:

1) All teams will henceforth expose their data and functionality through service interfaces.

2) Teams must communicate with each other through these interfaces.

3) There will be no other form of interprocess communication allowed: no direct linking, no direct reads of another team’s data store, no shared-memory model, no back-doors whatsoever. The only communication allowed is via service interface calls over the network.

4) It doesn’t matter what technology they use. HTTP, Corba, Pubsub, custom protocols — doesn’t matter. Bezos doesn’t care.

5) All service interfaces, without exception, must be designed from the ground up to be externalizable. That is to say, the team must plan and design to be able to expose the interface to developers in the outside world. No exceptions.

6) Anyone who doesn’t do this will be fired.

7) Thank you; have a nice day!

Ha, ha! You 150-odd ex-Amazon folks here will of course realize immediately that #7 was a little joke I threw in, because Bezos most definitely does not give a shit about your day.

#6, however, was quite real, so people went to work. Bezos assigned a couple of Chief Bulldogs to oversee the effort and ensure forward progress, headed up by Uber-Chief Bear Bulldog Rick Dalzell. Rick is an ex-Armgy Ranger, West Point Academy graduate, ex-boxer, ex-Chief Torturer slash CIO at Wal*Mart, and is a big genial scary man who used the word “hardened interface” a lot. Rick was a walking, talking hardened interface himself, so needless to say, everyone made LOTS of forward progress and made sure Rick knew about it.

Over the next couple of years, Amazon transformed internally into a service-oriented architecture. They learned a tremendous amount while effecting this transformation. There was lots of existing documentation and lore about SOAs, but at Amazon’s vast scale it was about as useful as telling Indiana Jones to look both ways before crossing the street. Amazon’s dev staff made a lot of discoveries along the way. A teeny tiny sampling of these discoveries included:

– pager escalation gets way harder, because a ticket might bounce through 20 service calls before the real owner is identified. If each bounce goes through a team with a 15-minute response time, it can be hours before the right team finally finds out, unless you build a lot of scaffolding and metrics and reporting.

– every single one of your peer teams suddenly becomes a potential DOS attacker. Nobody can make any real forward progress until very serious quotas and throttling are put in place in every single service.

– monitoring and QA are the same thing. You’d never think so until you try doing a big SOA. But when your service says “oh yes, I’m fine”, it may well be the case that the only thing still functioning in the server is the little component that knows how to say “I’m fine, roger roger, over and out” in a cheery droid voice. In order to tell whether the service is actually responding, you have to make individual calls. The problem continues recursively until your monitoring is doing comprehensive semantics checking of your entire range of services and data, at which point it’s indistinguishable from automated QA. So they’re a continuum.

– if you have hundreds of services, and your code MUST communicate with other groups’ code via these services, then you won’t be able to find any of them without a service-discovery mechanism. And you can’t have that without a service registration mechanism, which itself is another service. So Amazon has a universal service registry where you can find out reflectively (programmatically) about every service, what its APIs are, and also whether it is currently up, and where.

– debugging problems with someone else’s code gets a LOT harder, and is basically impossible unless there is a universal standard way to run every service in a debuggable sandbox.

That’s just a very small sample. There are dozens, maybe hundreds of individual learnings like these that Amazon had to discover organically. There were a lot of wacky ones around externalizing services, but not as many as you might think. Organizing into services taught teams not to trust each other in most of the same ways they’re not supposed to trust external developers.

This effort was still underway when I left to join Google in mid-2005, but it was pretty far advanced. From the time Bezos issued his edict through the time I left, Amazon had transformed culturally into a company that thinks about everything in a services-first fashion. It is now fundamental to how they approach all designs, including internal designs for stuff that might never see the light of day externally.

At this point they don’t even do it out of fear of being fired. I mean, they’re still afraid of that; it’s pretty much part of daily life there, working for the Dread Pirate Bezos and all. But they do services because they’ve come to understand that it’s the Right Thing. There are without question pros and cons to the SOA approach, and some of the cons are pretty long. But overall it’s the right thing because SOA-driven design enables Platforms.

That’s what Bezos was up to with his edict, of course. He didn’t (and doesn’t) care even a tiny bit about the well-being of the teams, nor about what technologies they use, nor in fact any detail whatsoever about how they go about their business unless they happen to be screwing up. But Bezos realized long before the vast majority of Amazonians that Amazon needs to be a platform.

You wouldn’t really think that an online bookstore needs to be an extensible, programmable platform. Would you?

Well, the first big thing Bezos realized is that the infrastructure they’d built for selling and shipping books and sundry could be transformed an excellent repurposable computing platform. So now they have the Amazon Elastic Compute Cloud, and the Amazon Elastic MapReduce, and the Amazon Relational Database Service, and a whole passel’ o’ other services browsable at aws.amazon.com. These services host the backends for some pretty successful companies, reddit being my personal favorite of the bunch.

The other big realization he had was that he can’t always build the right thing. I think Larry Tesler might have struck some kind of chord in Bezos when he said his mom couldn’t use the goddamn website. It’s not even super clear whose mom he was talking about, and doesn’t really matter, because nobody’s mom can use the goddamn website. In fact I myself find the website disturbingly daunting, and I worked there for over half a decade. I’ve just learned to kinda defocus my eyes and concentrate on the million or so pixels near the center of the page above the fold.

I’m not really sure how Bezos came to this realization — the insight that he can’t build one product and have it be right for everyone. But it doesn’t matter, because he gets it. There’s actually a formal name for this phenomenon. It’s called Accessibility, and it’s the most important thing in the computing world.

The. Most. Important. Thing.

If you’re sorta thinking, “huh? You mean like, blind and deaf people Accessibility?” then you’re not alone, because I’ve come to understand that there are lots and LOTS of people just like you: people for whom this idea does not have the right Accessibility, so it hasn’t been able to get through to you yet. It’s not your fault for not understanding, any more than it would be your fault for being blind or deaf or motion-restricted or living with any other disability. When software — or idea-ware for that matter — fails to be accessible to anyone for any reason, it is the fault of the software or of the messaging of the idea. It is an Accessibility failure.

Like anything else big and important in life, Accessibility has an evil twin who, jilted by the unbalanced affection displayed by their parents in their youth, has grown into an equally powerful Arch-Nemesis (yes, there’s more than one nemesis to accessibility) named Security. And boy howdy are the two ever at odds.

But I’ll argue that Accessibility is actually more important than Security because dialing Accessibility to zero means you have no product at all, whereas dialing Security to zero can still get you a reasonably successful product such as the Playstation Network.

So yeah. In case you hadn’t noticed, I could actually write a book on this topic. A fat one, filled with amusing anecdotes about ants and rubber mallets at companies I’ve worked at. But I will never get this little rant published, and you’ll never get it read, unless I start to wrap up.

That one last thing that Google doesn’t do well is Platforms. We don’t understand platforms. We don’t “get” platforms. Some of you do, but you are the minority. This has become painfully clear to me over the past six years. I was kind of hoping that competitive pressure from Microsoft and Amazon and more recently Facebook would make us wake up collectively and start doing universal services. Not in some sort of ad-hoc, half-assed way, but in more or less the same way Amazon did it: all at once, for real, no cheating, and treating it as our top priority from now on.

But no. No, it’s like our tenth or eleventh priority. Or fifteenth, I don’t know. It’s pretty low. There are a few teams who treat the idea very seriously, but most teams either don’t think about it all, ever, or only a small percentage of them think about it in a very small way.

It’s a big stretch even to get most teams to offer a stubby service to get programmatic access to their data and computations. Most of them think they’re building products. And a stubby service is a pretty pathetic service. Go back and look at that partial list of learnings from Amazon, and tell me which ones Stubby gives you out of the box. As far as I’m concerned, it’s none of them. Stubby’s great, but it’s like parts when you need a car.

A product is useless without a platform, or more precisely and accurately, a platform-less product will always be replaced by an equivalent platform-ized product.

Google+ is a prime example of our complete failure to understand platforms from the very highest levels of executive leadership (hi Larry, Sergey, Eric, Vic, howdy howdy) down to the very lowest leaf workers (hey yo). We all don’t get it. The Golden Rule of platforms is that you Eat Your Own Dogfood. The Google+ platform is a pathetic afterthought. We had no API at all at launch, and last I checked, we had one measly API call. One of the team members marched in and told me about it when they launched, and I asked: “So is it the Stalker API?” She got all glum and said “Yeah.” I mean, I was joking, but no… the only API call we offer is to get someone’s stream. So I guess the joke was on me.

Microsoft has known about the Dogfood rule for at least twenty years. It’s been part of their culture for a whole generation now. You don’t eat People Food and give your developers Dog Food. Doing that is simply robbing your long-term platform value for short-term successes. Platforms are all about long-term thinking.

Google+ is a knee-jerk reaction, a study in short-term thinking, predicated on the incorrect notion that Facebook is successful because they built a great product. But that’s not why they are successful. Facebook is successful because they built an entire constellation of products by allowing other people to do the work. So Facebook is different for everyone. Some people spend all their time on Mafia Wars. Some spend all their time on Farmville. There are hundreds or maybe thousands of different high-quality time sinks available, so there’s something there for everyone.

Our Google+ team took a look at the aftermarket and said: “Gosh, it looks like we need some games. Let’s go contract someone to, um, write some games for us.” Do you begin to see how incredibly wrong that thinking is now? The problem is that we are trying to predict what people want and deliver it for them.

You can’t do that. Not really. Not reliably. There have been precious few people in the world, over the entire history of computing, who have been able to do it reliably. Steve Jobs was one of them. We don’t have a Steve Jobs here. I’m sorry, but we don’t.

Larry Tesler may have convinced Bezos that he was no Steve Jobs, but Bezos realized that he didn’t need to be a Steve Jobs in order to provide everyone with the right products: interfaces and workflows that they liked and felt at ease with. He just needed to enable third-party developers to do it, and it would happen automatically.

I apologize to those (many) of you for whom all this stuff I’m saying is incredibly obvious, because yeah. It’s incredibly frigging obvious. Except we’re not doing it. We don’t get Platforms, and we don’t get Accessibility. The two are basically the same thing, because platforms solve accessibility. A platform is accessibility.

So yeah, Microsoft gets it. And you know as well as I do how surprising that is, because they don’t “get” much of anything, really. But they understand platforms as a purely accidental outgrowth of having started life in the business of providing platforms. So they have thirty-plus years of learning in this space. And if you go to msdn.com, and spend some time browsing, and you’ve never seen it before, prepare to be amazed. Because it’s staggeringly huge. They have thousands, and thousands, and THOUSANDS of API calls. They have a HUGE platform. Too big in fact, because they can’t design for squat, but at least they’re doing it.

Amazon gets it. Amazon’s AWS (aws.amazon.com) is incredible. Just go look at it. Click around. It’s embarrassing. We don’t have any of that stuff.

Apple gets it, obviously. They’ve made some fundamentally non-open choices, particularly around their mobile platform. But they understand accessibility and they understand the power of third-party development and they eat their dogfood. And you know what? They make pretty good dogfood. Their APIs are a hell of a lot cleaner than Microsoft’s, and have been since time immemorial.

Facebook gets it. That’s what really worries me. That’s what got me off my lazy butt to write this thing. I hate blogging. I hate… plussing, or whatever it’s called when you do a massive rant in Google+ even though it’s a terrible venue for it but you do it anyway because in the end you really do want Google to be successful. And I do! I mean, Facebook wants me there, and it’d be pretty easy to just go. But Google is home, so I’m insisting that we have this little family intervention, uncomfortable as it might be.

After you’ve marveled at the platform offerings of Microsoft and Amazon, and Facebook I guess (I didn’t look because I didn’t want to get too depressed), head over to developers.google.com and browse a little. Pretty big difference, eh? It’s like what your fifth-grade nephew might mock up if he were doing an assignment to demonstrate what a big powerful platform company might be building if all they had, resource-wise, was one fifth grader.

Please don’t get me wrong here — I know for a fact that the dev-rel team has had to FIGHT to get even this much available externally. They’re kicking ass as far as I’m concerned, because they DO get platforms, and they are struggling heroically to try to create one in an environment that is at best platform-apathetic, and at worst often openly hostile to the idea.

I’m just frankly describing what developers.google.com looks like to an outsider. It looks childish. Where’s the Maps APIs in there for Christ’s sake? Some of the things in there are labs projects. And the APIs for everything I clicked were… they were paltry. They were obviously dog food. Not even good organic stuff. Compared to our internal APIs it’s all snouts and horse hooves.

And also don’t get me wrong about Google+. They’re far from the only offenders. This is a cultural thing. What we have going on internally is basically a war, with the underdog minority Platformers fighting a more or less losing battle against the Mighty Funded Confident Producters.

Any teams that have successfully internalized the notion that they should be externally programmable platforms from the ground up are underdogs — Maps and Docs come to mind, and I know GMail is making overtures in that direction. But it’s hard for them to get funding for it because it’s not part of our culture. Maestro’s funding is a feeble thing compared to the gargantuan Microsoft Office programming platform: it’s a fluffy rabbit versus a T-Rex. The Docs team knows they’ll never be competitive with Office until they can match its scripting facilities, but they’re not getting any resource love. I mean, I assume they’re not, given that Apps Script only works in Spreadsheet right now, and it doesn’t even have keyboard shortcuts as part of its API. That team looks pretty unloved to me.

Ironically enough, Wave was a great platform, may they rest in peace. But making something a platform is not going to make you an instant success. A platform needs a killer app. Facebook — that is, the stock service they offer with walls and friends and such — is the killer app for the Facebook Platform. And it is a very serious mistake to conclude that the Facebook App could have been anywhere near as successful without the Facebook Platform.

You know how people are always saying Google is arrogant? I’m a Googler, so I get as irritated as you do when people say that. We’re not arrogant, by and large. We’re, like, 99% Arrogance-Free. I did start this post — if you’ll reach back into distant memory — by describing Google as “doing everything right”. We do mean well, and for the most part when people say we’re arrogant it’s because we didn’t hire them, or they’re unhappy with our policies, or something along those lines. They’re inferring arrogance because it makes them feel better.

But when we take the stance that we know how to design the perfect product for everyone, and believe you me, I hear that a lot, then we’re being fools. You can attribute it to arrogance, or naivete, or whatever — it doesn’t matter in the end, because it’s foolishness. There IS no perfect product for everyone.

And so we wind up with a browser that doesn’t let you set the default font size. Talk about an affront to Accessibility. I mean, as I get older I’m actually going blind. For real. I’ve been nearsighted all my life, and once you hit 40 years old you stop being able to see things up close. So font selection becomes this life-or-death thing: it can lock you out of the product completely. But the Chrome team is flat-out arrogant here: they want to build a zero-configuration product, and they’re quite brazen about it, and Fuck You if you’re blind or deaf or whatever. Hit Ctrl-+ on every single page visit for the rest of your life.

It’s not just them. It’s everyone. The problem is that we’re a Product Company through and through. We built a successful product with broad appeal — our search, that is — and that wild success has biased us.

Amazon was a product company too, so it took an out-of-band force to make Bezos understand the need for a platform. That force was their evaporating margins; he was cornered and had to think of a way out. But all he had was a bunch of engineers and all these computers… if only they could be monetized somehow… you can see how he arrived at AWS, in hindsight.

Microsoft started out as a platform, so they’ve just had lots of practice at it.

Facebook, though: they worry me. I’m no expert, but I’m pretty sure they started off as a Product and they rode that success pretty far. So I’m not sure exactly how they made the transition to a platform. It was a relatively long time ago, since they had to be a platform before (now very old) things like Mafia Wars could come along.

Maybe they just looked at us and asked: “How can we beat Google? What are they missing?”

The problem we face is pretty huge, because it will take a dramatic cultural change in order for us to start catching up. We don’t do internal service-oriented platforms, and we just as equally don’t do external ones. This means that the “not getting it” is endemic across the company: the PMs don’t get it, the engineers don’t get it, the product teams don’t get it, nobody gets it. Even if individuals do, even if YOU do, it doesn’t matter one bit unless we’re treating it as an all-hands-on-deck emergency. We can’t keep launching products and pretending we’ll turn them into magical beautiful extensible platforms later. We’ve tried that and it’s not working.

The Golden Rule of Platforms, “Eat Your Own Dogfood”, can be rephrased as “Start with a Platform, and Then Use it for Everything.” You can’t just bolt it on later. Certainly not easily at any rate — ask anyone who worked on platformizing MS Office. Or anyone who worked on platformizing Amazon. If you delay it, it’ll be ten times as much work as just doing it correctly up front. You can’t cheat. You can’t have secret back doors for internal apps to get special priority access, not for ANY reason. You need to solve the hard problems up front.

I’m not saying it’s too late for us, but the longer we wait, the closer we get to being Too Late.

I honestly don’t know how to wrap this up. I’ve said pretty much everything I came here to say today. This post has been six years in the making. I’m sorry if I wasn’t gentle enough, or if I misrepresented some product or team or person, or if we’re actually doing LOTS of platform stuff and it just so happens that I and everyone I ever talk to has just never heard about it. I’m sorry.

But we’ve gotta start doing this right.