quarta-feira, 30 de março de 2011

Redes Sociais no Ambiente Corporativo

Quando você leu o título o que lhe veio a cabeça? Twitter? Facebook?

Hum, se sua resposta for sim, sinto em lhe dizer, mas você está confundindo MÍDIA SOCIAL com REDE SOCIAL.

“Qualquer pessoa ficaria chateado, qualquer um de nós ficaria abatido, desmotivado, mas não Joseph Klimber” e você também não precisa.

Então, o que é uma rede social?

Rede social é uma estrutura composta por pessoas conectadas que compartilham valores e objetivos comuns. Isso quer dizer que o grupo que se reúne todos os domingos para jogar bola, as pessoas que participam do Campus Party ou o grupo de voluntários da GRAAC são todos redes sociais (só que em diferentes níveis).

Com a aparição de novas tecnologias como a internet a interação entre as pessoas cresce com rapidamente. Então, com a criação de mídias sociais como o Youtube, o Twitter ou Facebook essa velocidade aumentou ainda mais. São milhões de pessoas colaborando, compartilhando, co-criando, presentes em todos os lugares e em busca de um mundo melhor.

“Empresas que compreendem a importância de aproveitar o poder dos comportamentos colectivos para impulsionar mudanças positivas nos negócios serão bem-sucedidas.” – Gartner

E porque na minha empresa não é assim?

Quando dentro de uma empresa buscamos conhecimento para atingirmos uma meta, realizar um trabalho, só que a máquina da empresa, a obrigação, a rotina, seus processos não permitem troca de conhecimento, e esse ambiente inadequado, inibe a interação das pessoas.

Ninguém interage se não vê essa troca.

Para estabelecer relações precisam ser criadas conexões, as quais podem gerar ou não relações de confiança, onde geralmente, a troca de conhecimento pessoal começa a acontecer.

Talvez você já tenha experimentado isso de alguma forma. Você já conversou sua vida pessoal com algum colega do trabalho que você não confia? Mas já deve ter considerado o comentário de um desconhecido sobre um produto que você queria comprar.

Uma vez que as pessoas começam a trocar informações pessoais elas se viciam nisso e esse caminho evolui para o ambiente profissional.

Nessas conexões haverá pessoas com diversos perfis e nosso trabalho será identificar o perfil de cada um e incentivá-las. Os principais perfis são os CRIADORES (aquelas que geram conteúdo para outras pessoas), CRÍTICOS (aquelas que opinião sobre os conteúdos gerados), PARTICIPANTES (aquelas que participam comentando ou interagindo com o conteúdo gerado) e os ESPECTADORES (aquelas que apenas acompanham esses conteúdos).

Você deve estar se indagando, isso é bonito, mas sem controle vai virar uma bagunça!

O “controle” muda para moderação, bom senso, política de boa conduta. E isso a própria rede é capaz de “controlar” se as pessoas críticas entenderem a política da rede. Alias, VOCÊ DEVERIA SER UMA DESSAS PESSOAS COM PERFIL CRÍTICO!

Estamos na era da Economia da Colaboração. As pessoas agora interagem para a CO-CRIAÇÃO do conhecimento em busca de um mundo melhor. Então, permita de alguma forma que seu cliente ou colaborador faça parte do processo criativo e produtivo do projeto.

E porque as pessoas dedicam seu precioso tempo na co-criação de um produto?

1. Fazer parte de algo maior
2. Mostrar que fazem parte daquilo
3. Pura diversão
4. Oportunidade de colaborar
5. Recompesa financeira

Já está acontecendo. É real! Não conhece a CAMISETERIA, o NESPRESSO, o FIAT MIO, o DESIGN LAB ELECTROLUX ou ainda o WIKIPEDIA.

Contudo, nada disso faz sentido se não aprendermos, não compartilharmos, não inovarmos, não criticarmos, não participarmos. E para isso, são necessárias estratégias, capacitação, metodologias específicas e projetos.

Como é o ambiente na sua empresa? É colaborativo? Participativo? As pessoas se sentem confortáveis em expressarem suas opiniões? Torcem o nariz quando houvem falar de rede social? E qual sua opinião sobre o assunto?


PARTICIPE DA DISCUSSÃO NO FACEBOOK!




Artigos Recomendados:

>>   Pensando em ERGONOMIA e USABILIDADE
>>   Design centrado no usuário

 

terça-feira, 29 de março de 2011

Prepare-se para o C# 5 – Parte 2

Demorou mais chegou... rs

No último artigo mostramos que a expressão document = await Fetchasync(urls [i]) do C# 5.0 era realizada assim:

state = State.AfterFetch;
fetchThingy = FetchAsync(urls[i]);
if (fetchThingy.SetContinuation(archiveDocuments))
  return;
AfterFetch: ;
  document = fetchThingy.GetValue();

Nesse modelo, um método assíncrono retorna um Task<T>, e por hora, vamos assumir que o FetchAsync também retorne um Task<Document>. Então, o código atual será realizado assim:

fetchAwaiter = FetchAsync(urls[i]).GetAwaiter();
state = State.AfterFetch;
if (fetchAwaiter.BeginAwait(archiveDocuments))
  return;
AfterFetch: ;
  document = fetchAwaiter.EndAwait();

A chamada a FetchAsync cria e retorna um Task<Document>. Ao chamar este método ele imediatamente retorna um Task<Document> que de alguma forma busca o documento desejado de forma assíncrona. Para fazer alguma coisa quando ele estiver completo buscamos na tarefa por um Awaiter, e ele fornece 2 métodos: BeginAwait, assina a continuação para a tarefa (executado após a finalizada a tarefa) e o EndAwait, que extrai o resultado da tarefa finalizada.

Como esses métodos são implementados na Task (para métodos void) ou Task<T> (para métodos que retornem valor) como fica os métodos que não retornam Task ou Task<T>?

Nesse caso é utilizado a mesma estratégia do LINQ, ou seja, se tivermos:

From c in customers where c.City == "London"

Isso é traduzido para:

Customers.Where(c => c.City == "London")

E uma resolução de overload tenta encontrar o melhor método "Where" checando se a implementação de "Customers" implementa tal método, caso contrário, busca por métodos de extensão.

Com o padrão GetAwaiter/BeginAwait/EndAwait é a mesma coisa, é feita a resolução de overload na transformação da expressão, verificado o método ou a extensão adequeada.

O insight é que assincronia não requer paralelismo, mas o paralelismo exige assincronia, e muitas das ferramentas úteis para o paralelismo podem ser usadas para assincronia sem paralelismo.

Por isso o uso do Task, ele não possui paralelismo inerente e podemos representar unidades de trabalho pendentes que pode ser paralelizada e não requer multithreading, além de, já possui mecanismos de cancelamento entre outras características úteis da TPL (Task Parallel Library).

Voltando ao exemplo da busca de documentos, ele foi deliberadamente planejado para demostrar o pulo do gato, o CPS (Continuation Passing Style), para controlar até mesmo orquestrações simples de 2 tarefas assíncronas de métodos void.

Então, vamos falar um pouco sobre composição de métodos assíncronos.

Suponha que o método ArchiveDocuments retornasse o número total de bytes arquivados:

long ArchiveDocuments(List<Url> urls)
{
  long count = 0;
  for(int i = 0; i < urls.Count; ++i)
  {
    var document = Fetch(urls[i]);
    count += document.Length;
    Archive(document);
  }
  return count;
}

Agora, vamos reescrevê-lo de forma assíncrona usando um CPS:

void ArchiveDocumentsAsync(List<Url> urls, Action<long> continuation)
{
  // de alguma forma executa a busca de forma assíncrona,
  // depois invoca sua continuação
}

Dessa forma, o chamador do ArchiveDocumentsAsync precisaria ser escrito em um CPS de modo que a continuidade possa ser passada. E se o retorno fosse um resultado? Então, seria uma confusão.

No modelo TAP (Task Asynchrony Pattern, nome provisório para essa feature de composição de métodos assíncronos), ao invés disso, diriamos que o tipo que representa o trabalho assíncrono e retorna um valor é um Task<T>. Em C# 5, você poderia simplesmente escrever:

async Task<long> ArchiveDocumentsAsync(List<Url> urls)
{
  long count = 0;
  Task archive = null;
  for(int i = 0; i < urls.Count; ++i)
  {
    var document = await FetchAsync(urls[i]);
    count += document.Length;
    if (archive != null)
      await archive;
    archive = ArchiveAsync(document);
  }
  return count;
}

E o compilador se encarregará de reescrever e gerar algo como:

Task<long> ArchiveDocuments(List<Url> urls)
{
  var taskBuilder = AsyncMethodBuilder<long>.Create();
  State state = State.Start;
  TaskAwaiter<Document> fetchAwaiter = null;
  TaskAwaiter archiveAwaiter = null;
  int i;
  long count = 0;
  Task archive = null;
  Document document;
  Action archiveDocuments = () =>
  {
    switch(state)
    {
      case State.Start: goto Start;
      case State.AfterFetch: goto AfterFetch;
      case State.AfterArchive: goto AfterArchive;
    }
    Start:
    for(i = 0; i < urls.Count; ++i)
    {
      fetchAwaiter = FetchAsync(urls[i]).GetAwaiter();
      state = State.AfterFetch;
      if (fetchAwaiter.BeginAwait(archiveDocuments))
        return;
      AfterFetch:
      document = fetchAwaiter.EndAwait();
      count += document.Length;
      if (archive != null)
      {
        archiveAwaiter = archive.GetAwaiter();
        state = State.AfterArchive;
        if (archiveAwaiter.BeginAwait(archiveDocuments))
          return;
        AfterArchive:
        archiveAwaiter.EndAwait();
      }
      archive = ArchiveAsync(document);
    }
    taskBuilder.SetResult(count);
    return;
  };
  archiveDocuments();
  return taskBuilder.Task;
}

Vamos fazer um teste de mesa aqui para clarear as coisas.

O que acontece quando a lista está vazia? Nós criamos um contrutor de tarefas, um delegate que retorna void e invocamos ele de forma assíncrona. Ele inicializa a variável ”count” com 0, executa a label start, pula o loop, diz para o helper “você tem um resultado” e retorna. Finaliza o delegate. O taskbuilder é solicitado para uma tarefa, e uma vez que ele sabe que a tarefa foi concluida, retorna a tarefa concluida que simplesmente representa o número 0.

E caso existam vários documentos de arquivos? Novamente criamos um taskbuilder e um delegate que serão invocados assíncronamente. No primeiro loop começamos uma busca assíncrona, assinamos o delegate como sua continuação e retornamos do delegate. O taskbuilder contrói uma tarefa que representa “estou trabalhando de forma assíncrona no corpo do ArchiveDocumentsAsync” e retorna essa tarefa. Ao ser concluída, invoca sua continuação e o delegate inicia de novo “do ponto onde ele parou” graças a máquina de estado. Tudo continua exatamente como antes, porém, direferente da versão void, o Task<long> retornado para o ArchiveDocumentsAsync sinaliza que finalizou (invocando sua continuação) e o delegate diz ao task builder para definir o resultado.

NOTA:Tal qual o LINQ, o TAP pode ser extensível por qualquer tipo que tenha um GetAwaiter, que retorne um tipo que tenha BeginAwait, EndAwait e assim por diante, para que possa ser usado nas expressões “await”. Contudo, métodos marcados para serem assíncronos devem retornar void, Task ou Task<T>.

Existem situações onde sintaxe com tokens como “where” do LINQ são mais naturais e outras onde são a sintaxe “fluent” .Where(c => ...), no TAP haverá métodos com nomes como WhenAll ou WhenAny para compor e orquestrar tarefas assíncronas:

List<List<Url>> groupsOfUrls = whatever;
Task<long[]> allResults = Task.WhenAll(
      from urls in groupsOfUrls
      select ArchiveDocumentsAsync(urls));
long[] results = await allResults;

O que isto faz? Bem, o ArchiveDocumentsAsync retorna um Task<long>, então a query retorna um IEnumerable<Task<long>>. WhenAll pega a sequência de tarefas e produz uma nova tarefa, que de forma assíncrona aguarda cada um deles, preenche um array com o resultado e invoca sua continuação com o resultado quanto ele estiver disponível.

Da mesma forma o WhenAny pega uma sequência de tarefas e cria uma tarefa que invoca sua continuação com o primeiro resultado quando qualquer uma das tarefas estiverem finalizadas.

Existirão outras combinações de tarefas e helpers relacionados. Veja mais exemplos no CTP e repare que como não é possível modificar um Task existente os combinadores foram provisóriamente adicionados na classe TaskEx,mas, serão movidos para o Task até a versão final.

Até a próxima!


Artigos Recomendados:

>>   Prepare-se para o C# 5 – Parte 1
>>   Reflection de Alta de Performance
>>   Extension Methods = Manutenibilidade