De que se trata o artigo

Dependências sempre irão existir em desenvolvimento de software. Quanto mais dependências o software tem, maior o potencial de complexidade. O objeto do artigo é apresentar técnicas e ferramentas para manter as dependências controladas de forma a diminuir a complexidade do sistema como um todo.

Em que situação o tema é útil

Todo e qualquer sistema pode se beneficiar de técnicas para torná-lo menos complexo. Menor complexidade, maior facilidade de manutenção e, consequentemente, maior tempo para desenvolver coisas que agreguem mais valor.

Limites limpos e dependências controladas com Facade e IoC

Este artigo apresentará um caso real de um software cuja principal funcionalidade era manipular arquivos do Excel. Partindo desta premissa simples você conhecerá a ótima biblioteca NPOI para manipulação deste tipo de arquivo e será apresentado a uma série de técnicas de arquitetura para controlar os impactos na complexidade do sistema decorrentes da adição de dependências. Além da própria biblioteca NPOI, você verá um pouco do framework StructureMap (para inversão de controle) e do padrão Onion Architecture.

Vamos imaginar um cenário onde seja necessário criar um software que, dentre outras responsabilidades, deve criar e manipular planilhas Excel. Não cabe aqui entrar no mérito das regras de negócio, mas vale dizer que o aplicativo deve gerar as planilhas e receber estas mesmas planilhas, após serem alteradas pelos usuários, como entrada para determinadas situações. Ou seja, manipular planilhas do Excel consiste uma parte importante do software.

Outro fato relevante é que nesse cenário hipotético, não existe um framework corporativo utilizado/criado pela equipe, uma forma padronizada para fazer isto. Sendo assim, outra parte da tarefa será prover padronização para que outros desenvolvedores possam realizar tarefas semelhantes.

Devemos agora focar nosso esforço na escolha de ferramenta para manipulação dos arquivos do Excel, o impacto que dependências como estas podem ter na complexidade dos sistemas de informação e algumas formas de mantê-las sob controle.

Automation?

Como manipular planilhas do Excel? O primeiro impulso nestes casos sempre é utilizar Microsoft Office Automation. Apesar de esta ser uma alternativa, muitos desenvolvedores já sofreram bastante em alguns projetos para saber que ela não se aplica bem para códigos que rodam do lado do servidor. São comuns problemas como concorrência (deadlock, travamentos e afins) e alguns relacionados à distribuição (principalmente quanto à versão do Excel instalado no servidor). Sendo assim, estudaremos outra opção.

NPOI

Ao descartar a possibilidade de utilizar Automation tem-se a opção de utilizar diversas bibliotecas para manipulação do Excel, dentre elas o NPOI, foco desse artigo. Esta biblioteca, como sua própria página diz, é a versão .NET de um projeto Java chamado POI, que por sua vez é um projeto de código aberto que propicia uma forma mais eficiente que o Office Automation para ler e escrever arquivos xls, doc e ppt. Uma ótima característica do NPOI é que seu uso não requer qualquer tipo de instalação do Office para funcionar.

Após baixar os binários do NPOI (vide seção Links) você verá que ela é composta de dois componentes (NPOI.dll e Ionic.Zip.dll). Na mesma página de download, além dos códigos fontes, você terá acesso a um projeto repleto de exemplos de utilização, o que facilita muito o aprendizado. Um típico código utilizando NPOI pode ser visto na Listagem 1.

Talvez seja interessante realizar alguns testes de aprendizagem para verificar se a curva de aprendizagem vale a pena para um determinado projeto, considerando uma dada equipe de desenvolvedores.

Nota do DevMan

Testes de aprendizagem, assim chamada por Jim Newkirk, é uma técnica de TDD que visa utilizar uma abordagem diferente para entender e usar códigos de terceiros. A idéia básica é que ao invés de gastar tempo apenas lendo a documentação para saber como o código de terceiro funciona, os desenvolvedores devem escrever testes com o objetivo de aprender sobre a API a ser utilizada. Além disso, estes testes ainda podem ser usados para validar uma eventual atualização no componente de terceiro para garantir que aquilo que estava funcionando no momento da adoção da biblioteca apresenta os mesmos resultados após a atualização.

Listagem 1. Exemplo de criação de um arquivo do Excel vazio utilizando a biblioteca NPOI

static void Main(string[] args)
  {
      HSSFWorkbook hssfworkbook = new HSSFWorkbook();
   
      DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
      dsi.Company = ".net Magazine";
      hssfworkbook.DocumentSummaryInformation = dsi;
   
      SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
      si.Subject = "Exemplo para artigo";
      hssfworkbook.SummaryInformation = si;
   
      hssfworkbook.CreateSheet("Planilha 1");
      hssfworkbook.CreateSheet("Planilha 2");
   
      FileStream file = new FileStream(@"teste.xls", FileMode.Create);
      hssfworkbook.Write(file);
      file.Close();
  }

Entrar nos detalhes acerca da utilização do NPOI está fora do escopo deste artigo.

Problema resolvido?

Então é isso, problema resolvido. Basta colocar os componentes da biblioteca à disposição da equipe de desenvolvimento (tipicamente em um diretório lib) e referenciá-los nos projetos que necessitam utilizá-los. Apenas para exemplificar esta solução, foi criado um pequeno aplicativo ASP.NET MVC, feita as devidas referências e inserido o código para criar uma planilha como pode ser visto na Listagem 2. O código não tem nada demais e o resultado final pode ser visto na Figura 1.

Listagem 2. Código para criar uma planilha com comentários usando a biblioteca NPOI


     11 [AcceptVerbs(HttpVerbs.Post)]
     12 public ActionResult GenerateWorkbook()
     13 {
     14     HSSFWorkbook hssfworkbook = new HSSFWorkbook();
     15 
     16     DocumentSummaryInformation dsi =
     17     PropertySetFactory.CreateDocumentSummaryInformation();
     18 
     19     dsi.Company = "Exemplo";
     20     hssfworkbook.DocumentSummaryInformation = dsi;
     21 
     22     SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
     23     si.Subject = "Exmeplo de geração de planilha vazia utilizando o NPOI";
     24     hssfworkbook.SummaryInformation = si;
     25 
     26     Sheet sheet = hssfworkbook.CreateSheet("Comentário");
     27 
     28     HSSFPatriarch patr = (HSSFPatriarch)sheet.CreateDrawingPatriarch();
     29 
     30     Cell cell1 = sheet.CreateRow(1).CreateCell(1);
     31     cell1.SetCellValue(new HSSFRichTextString("Célula com comentário"));
     32 
     33     Comment comment1 = patr.CreateCellComment(
     34         new HSSFClientAnchor(0, 0, 0, 0, 4, 2, 6, 5));
     35 
     36     comment1.String = (new HSSFRichTextString("usando comentários"));
     37     comment1.Author = ("Autor");
     38 
     39     cell1.CellComment = (comment1);
     40 
     41     Cell cell2 = sheet.CreateRow(6).CreateCell(1);
     42     cell2.SetCellValue(36.6);
     43     HSSFComment comment2 = (HSSFComment)patr.CreateCellComment
     44     new HSSFClientAnchor(0, 0, 0, 0, 4, 8, 6, 11));
     45     comment2.SetFillColor(204, 236, 255);
     46 
     47     HSSFRichTextString str = new HSSFRichTextString("Teste");
     48     Font font = hssfworkbook.CreateFont();
     49     font.FontName = ("Arial");
     50     font.FontHeightInPoints = 10;
     51     font.Boldweight = (short)FontBoldWeight.BOLD;
     52     font.Color = HSSFColor.RED.index;
     53     str.ApplyFont(font);
     54 
     55     comment2.String = str;
     56     comment2.Visible = true;
     57     comment2.Author = "Outro autor";
     58     comment2.Row = 6;
     59     comment2.Column = 1;
     60 
     61     FileStream file = new FileStream(@"test.xls", FileMode.Create);
     62     try
     63     {
     64         hssfworkbook.Write(file);
     65     }
     66     finally
     67     {
     68         file.Close();
     69     }
     70 
     71     return View("GenerateWorkbookSuccess", (object)file.Name);
     72 } ... 

Quer ler esse conteúdo completo? Tenha acesso completo