7 anos de Tá Safo

A comunidade Tá Safo vem demonstrando, através de ações, que em qualquer tipo de empreendimento, o fator decisivo são as pessoas. 7 anos se passaram desde o primeiro encontro da comunidade e nesse percurso fizemos muitos amigos por todo o Brasil, participando de eventos, compartilhando idéias fomentando a cultura de colaboração que é o carro chefe desse momento em que vivemos no Brasil e no mundo. O momento de transformar ideias em ações concretas de forma colaborativa.

Mesmo depois de 7 anos, ainda nos perguntam: como participar do Tá Safo? E a resposta pode parecer simples, mas, realmente, não é. Pois para participar do Tá Safo, é preciso quebrar regras, quebrar paradigmas, sair da zona de conforto. É preciso se expor, não ter medo de parecer bobo. Não ter medo de errar e saber que a falha é medida primária de progresso. É preciso saber disseminar informação, compartilhar conhecimento. É preciso conhecer pessoas. Entender que tecnologia é um meio e não um fim. Saber compreender as diferenças. É preciso querer mudar o mundo.

Por isso, talvez não seja fácil participar do Tá Safo. Mas queremos muito que você participe dessa jornada conosco. “Porque aqueles que são loucos o suficiente para achar que podem mudar o mundo, são as que de fato, mudam.

The crazy ones. Citação do famoso comercial da Apple  de 1997.

“Isto é para os loucos. Os desajustados. Os rebeldes. Os criadores de caso. Os que são peças redondas nos buracos quadrados. Os que vêem as coisas de forma diferente. Eles não gostam de regras. E eles não têm nenhum respeito pelo status quo. Você pode citá-los, discordá-los, glorificá-los ou difamá-los. A única coisa que você não pode fazer é ignorá-los. Porque eles mudam as coisas. Eles inventam. Eles imaginam. Eles curam. Eles exploram. Eles criam. Eles inspiram. Eles empurram a raça humana para frente. Talvez eles tenham que ser loucos. Como você pode olhar para uma tela em branco e ver uma obra de arte? Ou sentar em silêncio e ouvir uma música jamais composta? Ou olhar para um planeta vermelho e ver um laboratório sobre rodas?

Enquanto alguns os vêem como loucos, nós vemos gênios. Porque aqueles que são loucos o suficiente para achar que podem mudar o mundo, são os que de fato, mudam.”

Parabéns a Comunidade Tá Safo!

Rails para desenvolvimento de produtos

Não é novidade que RubyOnRails, hoje conhecido somente como Rails, tomou de assalto o mundo do desenvolvimento web. Sendo uma verdadeiro canivete suíço para o desenvolvedor full stack, Rails, aliado a simplicidade da linguagem Ruby, tornou-se referência para desenvolvimento de apps de maneira rápida e com qualidade. Não é a toa que o Rails é tão utilizado em startups. Neste post, vamos entender o porquê.

Ferramentas de linha de comando

Infelizmente, ainda temos pessoas com a mentalidade de que a linha de comando é algo ultrapassado, quando, na verdade, esta mentalidade é que é ultrapassada. A tela preta, ou branca se você usa mac :p, é uma ferramenta que pode nos proporcionar uma grande produtividade.

Como disse acima, o rails é um canivete suíço. Dentro dele, podemos encontrar algumas ferramentas que serão importantes durante o ciclo de desenvolvimento. O Rake é um software de gerenciamento de tarefas similar ao Make do Unix. Ele irá nos auxiliar na automatização de tarefas. Aquelas tarefas chatas, como executar migrações de banco agora poderão ser executadas de maneira mais ágil. Ele já vem com algumas tasks pré-definidas, mas também é possível criar as próprias tasks. Pra quem usa banco de dados relacional, é uma mão na roda. O rake foi criado pelo saudoso Jim Weirich, falecido recentemente.

tarefas pré-definidas

tarefas pré-definidas do rake

O Bundler é outra ferramenta de linha de comando que vem com o rails. Sua função é gerenciar as dependências do projeto. Não gosto de fazer essa comparação, mas pra quem vem do java, seria similar ao Maven. Sim, o rails possui dependências. Bibliotecas, que no universo ruby são conhecidas como gems. O Bundler gerencia essas gems que ficam definidas em um arquivo na raiz do projeto chamado Gemfile. Através dele, podemos ter controle sobre versões, instalação e atualizações das gems, organizando-as de acordo com o environment,  promovendo um ambiente mais consistente.

 

Gemfile

Gemfile

Com o comando rails server ou simplesmente rails s, o rails executa seu servidor embutido WEBrick. Uma maneira simples de rodar a aplicação em ambiente de desenvolvimento.

rails server

rails server

Assets Pipeline

Esta é uma das ferramentas mais poderosas para a produtividade  do desenvolvedor web, existente na atualidade. Ela, na verdade, é um conjunto de bibliotecas voltadas para resolver a questão dos assets nos projetos rails. Com a necessidade de se criar apps que proporcionam a melhor experiência possível ao usuário, não é novidade que abusamos de arquivos css, imagens e plugins do jquery. Logo é uma boa prática, minificar esses arquivos, para melhorar o carregamento das páginas e evitar requests desnecessárias ao servidor. Mesmo hoje em dia, ainda encontramos sites e web  apps que carregam tudo sem mificar. Esse é justamente o problema que o assets pipeline veio resolver com o comando: bundle exec rake assets:precompile.

Após a execução, o rails calcula o digest MDi do arquivo e adiciona ao nome do arquivo ficando assim application-e049a640704156e412f6ee79daabc7f6.css. Esse nome depende do conteúdo do arquivo, logo quando uma nova versão do asset for gerada, o nome irá mudar fazendo com que o cache do navegador não seja acionado, resolvendo o famigerado problema de o usuário ter de limpar o cache cada vez que tiver uma atualização nos arquivos estáticos.

Além de minificar, o assets pipeline compacta os arquivos no formato gzip, o que significa um arquivo com tamanho em bytes muito menor, se o servidor web aceitar o formato, claro. Hoje já existem ferramentas ótimas que auxiliam o desenvolvedor front-end como o Yeoman, mas em se tratando de rails, o assets pipeline ainda é uma excelente opção.

RubyGems

A comunidade ruby é extremamente ativa e moldada pela filosofia open source. A infinidade de gems existentes é um absurdo. Essas bibliotecas se tornaram grandes aliadas na produtividade do desenvolvedor. Para todo problema que você pensar, é possível que alguém já tenha criado uma gem. Existem algumas que considero tops e merecem uma atenção extra.

O Devise é uma biblioteca que resolve o problema da autenticação no rails. Autenticação é algo que, quase sempre, é uma implementação repetitiva, ou seja, para todo app que você fizer, a implementação será a mesma. O que considero até uma tarefa meio chata e que não tem valor agregado. O Devise nos proporciona implementar uma autenticação robusta de forma fácil e rápida. Ele possui encripitação por Bcrypt, suporte a Omniauth, confirmação por email, recuperar senha, track através de contador, timestamp e ip, suporte a internacionalização, entre outras coisas. Ele gera automaticamente as views com os formulários, nos poupando de uma tarefa meio ‘sacal’, com pouquíssimas etapas de configuração.

O Simple Form é uma ferramenta que nos fornece helpers com componentes para a criação de formulários de forma simples e rápida. O rails já vem, por default, com helpers de formulário. Eles nos auxiliam a criar formulários com código ruby, sem os div hell, tornando o código mais legível. O Simple Form nos proporciona uma DSL mais elegante, e componentes mais semânticos. Ele possui integração com o Twitter bootstrap e com o Foundation, nos possibilita criar formulários estilizados sem tocar em nenhum css.

Abaixo um exemplo de formulário html puro utilizando twitter bootstrap:


<form accept-charset="UTF-8" action="/articles/6" class="simple_form form-horizontal" id="edit_article_6" method="post" novalidate="novalidate">

  <legend>Article</legend>
  <div class="control-group string required article_name">
  	<label class="string required control-label" for="article_name">
  		<abbr title="required">*</abbr> Name
  	</label>
  	<div class="controls">
  		<input class="string required span6" id="article_name" name="article[name]" type="text" value="SimpleForm 2.0" />
  		<p class="help-block">add your article title here</p>
  	</div>
  </div>

  <div class="control-group string required article_name">
  	<div class="controls">
  		<div class="input-prepend">
    		<span class="add-on">Name</span>
    		<input class="string required" id="article_name" maxlength="255" name="article[name]" size="255" type="text" value="SimpleForm 2.0" />
			</div>
		</div>
	</div>

  <div class="control-group boolean optional article_published">
  	<label class="boolean optional control-label" for="article_published">
  		Published
  	</label>
  	<div class="controls">
  		<input name="article[published]" type="hidden" value="0" />
  		<label class="checkbox">
  			<input class="boolean optional" id="article_published" name="article[published]" type="checkbox" value="1" />
  		</label>
  	</div>
  </div>

  <div class="control-group check_boxes optional article_content_type">
  	<label class="check_boxes optional control-label">
  		Stacked checkboxes
  	</label>
  	<div class="controls">
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_blog" name="article[content_type][]" type="checkbox" value="Blog" />
  			Blog
  		</label>
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_editorial" name="article[content_type][]" type="checkbox" value="Editorial" />
  			Editorial
  		</label>
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_announce" name="article[content_type][]" type="checkbox" value="Announce" />
  			Announce
  		</label>
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_advertisement" name="article[content_type][]" type="checkbox" value="Advertisement" />
  			Advertisement
  		</label>
  		<input name="article[content_type][]" type="hidden" value="" />
  	</div>
  </div>

  <div class="control-group check_boxes optional article_content_type">
  	<label class="check_boxes optional control-label">
  		Inline checkboxes
  	</label>
  	<div class="controls">
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_blog" name="article[content_type][]" type="checkbox" value="Blog" />
  			Blog
  		</label>
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_editorial" name="article[content_type][]" type="checkbox" value="Editorial" />
  			Editorial
  		</label>
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_announce" name="article[content_type][]" type="checkbox" value="Announce" />
  			Announce
  		</label>
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_advertisement" name="article[content_type][]" type="checkbox" value="Advertisement" />
  			Advertisement
  		</label>
  		<input name="article[content_type][]" type="hidden" value="" />
  	</div>
  </div>

  <div class="control-group radio_buttons optional article_content_type">
  	<label class="radio_buttons optional control-label">
  		Stacked radios
  	</label>
  	<div class="controls">
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_blog" name="article[content_type]" type="radio" value="Blog" />
  			Blog
  		</label>
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_editorial" name="article[content_type]" type="radio" value="Editorial" />
  			Editorial
  		</label>
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_announce" name="article[content_type]" type="radio" value="Announce" />
  			Announce
  		</label>
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_advertisement" name="article[content_type]" type="radio" value="Advertisement" />
  			Advertisement
  		</label>
  	</div>
  </div>

  <div class="control-group radio_buttons optional article_content_type">
  	<label class="radio_buttons optional control-label">
  		Inline radios
  	</label>
  	<div class="controls">
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_blog" name="article[content_type]" type="radio" value="Blog" />
  			Blog
  		</label>
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_editorial" name="article[content_type]" type="radio" value="Editorial" />
  			Editorial
  		</label>
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_announce" name="article[content_type]" type="radio" value="Announce" />
  			Announce
  		</label>
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_advertisement" name="article[content_type]" type="radio" value="Advertisement" />
  			Advertisement
  		</label>
  	</div>
  </div>

  <div class="control-group select optional article_content_type">
  	<label class="select optional control-label" for="article_content_type">
  		Content type
  	</label>
  	<div class="controls">
  		<input name="article[content_type][]" type="hidden" value="" />
  		<select class="select optional" id="article_content_type" multiple="multiple" name="article[content_type][]">
  			<option value="Blog">Blog</option>
				<option value="Editorial">Editorial</option>
				<option value="Announce">Announce</option>
				<option value="Advertisement">Advertisement</option>
			</select>
			<p class="help-block">multiple select</p>
		</div>
	</div>

  <div class="control-group select optional article_category">
  	<label class="select optional control-label" for="article_category">
  		Category
  	</label>
  	<div class="controls">
  		<select class="select optional" id="article_category" name="article[category]">
  			<option value=""></option>
				<option value="Blog">Blog</option>
				<option value="Editorial">Editorial</option>
				<option value="Announce">Announce</option>
				<option value="Advertisement">Advertisement</option>
			</select>
			<p class="help-block">simple select box</p>
		</div>
	</div>

  <div class="control-group text optional article_content">
  	<label class="text optional control-label" for="article_content">
  		Content
  	</label>
  	<div class="controls">
  		<textarea class="text optional span6" id="article_content" name="article[content]">
			</textarea>
		</div>
	</div>

  <div class="control-group string optional disabled article_disabled_text">
  	<label class="string optional control-label" for="article_disabled_text">
  		Disabled text
  	</label>
  	<div class="controls">
  		<input class="string optional disabled" disabled="disabled" id="article_disabled_text" name="article[disabled_text]" type="text" />
  		<p class="help-block">an example of disabled input</p>
  	</div>
	</div>

  <div class="control-group string optional article_disabled_text">
  	<label class="string optional control-label" for="article_disabled_text">Disabled text</label>
  	<div class="controls">
	  	<div class="input-prepend">
		    <span class="add-on">
		      <input id="remove" name="remove" type="checkbox" value="true" />
				</span>
				<input class="string optional disabled" disabled="disabled" id="article_disabled_text" maxlength="255" name="article[disabled_text]" size="255" type="text" />
			</div>
			<span class="help-block">This is the hint text</span>
		</div>
	</div>

  <div class="control-group string optional article_disabled_text">
  	<label class="string optional control-label" for="article_disabled_text">
  		Disabled text
  	</label>
  	<div class="controls">
	  	<div class="input-append">
		    <input class="string optional disabled mini" disabled="disabled" id="article_disabled_text" maxlength="255" name="article[disabled_text]" size="255" type="text" />
		    <span class="add-on active">
		      <input id="remove" name="remove" type="checkbox" value="true" />
				</span>
			</div>
			<span class="help-block">This is the hint text</span>
		</div>
	</div>

  <div class="form-actions">
    <input class="btn btn-primary" name="commit" type="submit" value="Update Article" />
    <input class="btn btn-danger" name="commit" type="reset" value="Cancel" />
  </div>

</form>

E agora, o mesmo formulário com código ruby com Simple Form:


<% simple_form_for(@article, :html => { :class => 'form-horizontal' }) do |f| %>

<%= f.input :name, :input_html => { :class => "span6" }, :hint => "add your article title here" %>

<%= f.input :name, :wrapper => :prepend, :label => false do %>
    <%= content_tag :span, "Name", :class => "add-on" %>
    <%= f.input_field :name %>
<% end %>

<%= f.input :published, :as => :boolean %>

<%= f.input :content_type, :collection => content_type_options, :as => :check_boxes, :label => 'Stacked checkboxes' %>

<%= f.input :content_type, :collection => content_type_options, :as => :check_boxes, :item_wrapper_class => 'inline', :label => 'Inline checkboxes' %>

<%= f.input :content_type, :collection => content_type_options, :as => :radio_buttons, :label => 'Stacked radios' %>

<%= f.input :content_type, :collection => content_type_options, :as => :radio_buttons, :item_wrapper_class => 'inline', :label => 'Inline radios' %>

<%= f.input :content_type, :collection => content_type_options,
              :hint => "multiple select", :input_html => { :multiple => true } %>

<%= f.input :category, :collection => content_type_options,
              :hint => "simple select box" %>

<%= f.input :content, :input_html => { :class => "span6" } %>

<%= f.input :disabled_text, :disabled => true,
              :hint => "an example of disabled input" %>

<%= f.input :disabled_text, :wrapper => :prepend, :hint => 'This is the hint text' do %>
	<%= content_tag :span, :class => "add-on" do %>
	  <%= check_box_tag :remove, 'true' %>
	<% end %>
	<%= f.input_field :disabled_text, :disabled => true %>
<% end %>   

<div class="form-actions">
	<%= f.button :submit, :class => 'btn-primary' %>
	<%= submit_tag 'Cancel', :type => :reset, :class => "btn btn-danger" %>
</div>                                       

Existem outras gems muito utilizadas: paperclip, uma solução simples para upload de arquivos; resque para se criar background jobs; omniauth, autenticador multi-provider; Rspec, suite de testes automatizados; Capybara ajuda a criar testes automatizados que rodam no navegador e muitas outras. O próprio rails é uma gem.

RestFul

Dependendo do cenário, quando no início do projeto vem a dúvida de fazer ou não mobile first. Hoje, a web mobile ainda possui certas limitações, como performance, usabilidade e acesso a dispositivos do smartphone. Nesse caso, normalmente opta-se por apps nativos. No entanto, mesmo apps nativos se comunicam com recursos externos. Se não houver necessidade de um módulo web, o rails talvez não seja a melhor solução. Um cenário mais conhecido é apps web tendo necessidade de uma versão mobile.

É considerado uma boa prática expor uma interface restful que poderá ser acessada por um eventual aplicativo mobile ou desktop. Criar rotas restful no rails é muito simples. Basta utilizar o método resources no arquivo config/routes.rb.

 

routes.rb

routes.rb

Com o comando rake routes é possível visualizar as rotas criadas:

rake routes

rake routes

Exemplo de controller restful:


class ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update, :destroy]

  # GET /products
  # GET /products.json
  def index
    @products = Product.all
  end

  # GET /products/1
  # GET /products/1.json
  def show
  end

  # GET /products/new
  def new
    @product = Product.new
  end

  # GET /products/1/edit
  def edit
  end

  # POST /products
  # POST /products.json
  def create
    @product = Product.new(product_params)

    respond_to do |format|
      if @product.save
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
        format.json { render :show, status: :created, location: @product }
      else
        format.html { render :new }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /products/1
  # PATCH/PUT /products/1.json
  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
        format.json { render :show, status: :ok, location: @product }
      else
        format.html { render :edit }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.json
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to products_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def product_params
      params.require(:product).permit(:name, :price, :category)
    end
end

Controllers restful também são muito úteis quando usamos algum framework javascript para single-page applications como AngularJs ou Backbone.js.

Testes automatizados

No vocabulário de startups existe um termo conhecido como “pivotar” que nada mais é quando o empreendedor decide mudar o plano de negócios depois de ter testado uma estratégia e não ter obtido os resultados esperados. E em se tratando de produtos web, muitas vezes há a necessidade de realizar mudanças no modelo de domínio da aplicação. Agora, imagine não possuir testes automatizados em um cenário como este. Seria catastrófico.

A comunidade ruby, é muito exigente nesse aspecto. É preciso ter cobertura de testes. Tanto que o rails vem com uma suite de testes embutida, o minitest. Apesar disso, muitos desenvolvedores preferem adotar uma suite de testes externa e mais robusta, o Rspec. A api do Rspec nos fornece uma DSL simples e elegante para BDD (Behaviour-Driven Development). Logo, além de uma cobertura de testes, ele nos fornece uma documentação da nossa aplicação sempre atualizada.

Abaixo, um exemplo de teste de model com rspec:


require "spec_helper"

describe User do
  it "orders by last name" do
    lindeman = User.create!(first_name: "Andy", last_name: "Lindeman")
    chelimsky = User.create!(first_name: "David", last_name: "Chelimsky")

    expect(User.ordered_by_last_name).to eq([chelimsky, lindeman])
  end
end

A linha 8 é a assertiva. Repare como é fácil entender o código.

Conclusão

Essa foi uma abordagem bem superficial. É claro que o rails possui muito mais recursos. Sem dúvida é uma excelente ferramenta que ajuda a resolver problemas de maneira prática e elegante, possui uma comunidade muito ativa, com excelentes profissionais que prezam pela qualidade e boas práticas.

referências:

http://guides.rubyonrails.org/

http://www.akitaonrails.com/2012/07/01/asset-pipeline-para-iniciantes

 

Tá safo! no Startup Weekend Belém

topo_site_swbelem1-1024x327Olá, moçada! Para quem ainda não está sabendo, no mês de Abril acontecerá a 1ª edição de Belém de um evento conhecido mundialmente, o Startup Weekend. Nós do Tá safo! estamos apoiando o evento e agora podemos publicar uma excelente notícia. Além de estarem vindo pessoas de renome no cenário empreendedor nacional, teremos pessoas da comunidade:

tasafoA novidade é que convidamos um pessoal irado, e que admiramos tanto, do #horaextra que finalmente conhecerão a galera e os sabores de Belém do Pará :)

horaextraA cereja do bolo fica por conta de uma das pessoas mais fantásticas com quem já trabalhei. A Verena Petitinga é Product Manager da aceleradora 21212, ela ajuda você a destampar sua mente e desenvolver produtos de altíssima qualidade.

21212Pessoal, é só uma mostra do que tem por vir. Espero que vocês fiquem motivados a participar do evento que será uma experiência bem intensa e produtiva. Veja a programação e grade completa no site do evento. E o último recado é que as inscrições estão bombando, não perca tempo e faça logo a sua clicando aqui!

Nos vemos por lá! Tá safo?

13 Anos do Manifesto Ágil

Reunião que gerou o Manifesto Ágil.

Do dia 11 a 13 de Fevereiro de 2001, 17 pessoas se reuniram num resort de esqui, nas montanhas de Wasatch, em Utah, para esquiar, relaxar, comer e discutir sobre melhores formas de desenvolver software. Mas o resultado dessa reunião que foi marcante para nossa área. Assim surgiu o Manifesto Ágil, que mudou não só a forma de desenvolvermos, mas sim de pensar, agir, viver. E hoje, estamos comemorando 13 anos do seu surgimento. É nesse ritmo que a Comunidade parabeniza todos os adeptos, evangelistas, simpatizantes do Agile no mundo afora. Obrigado por contribuírem e, acima de tudo, acreditarem que podemos sempre melhorar.

Agile Game com Natalie Volk

Grande amiga da comunidade, Natalie Volk estava de férias passando por nossa Belém e aproveitamos para convidá-la para realizarmos um #tasafoemacao, cujo convite foi aceito com muita alegria. Ela nos presenteou com uma “Dinâmica sobre dia o dia com ágil” inovadora chamada Agile Game que é feita como forma de imersão na ThoughtWorks para novos funcionários a fim de explicar como funciona o desenvolvimento em um ambiente ágil.

Continue lendo

#TasafoEmAcao – Semana Acadêmica de Computação UFPA

Esse post traz a cobertura completa do #tasafoemacao na Semana Acadêmica de Computação da UFPA. O evento contou com diversas atividades durante a semana. Tivemos um contratempo, devido um palestrante que não pôde se apresentar no dia anterior ocupou o tempo de nossa grade e só pudemos começar a partir das 18hs. Mas mesmo assim não nos abalamos, ficaram no auditório apenas as pessoas que estavam ansiosas em ver o estilo de apresentações que faz da comunidade Tá safo! ser recebida tão bem nos lugares que é convidada.

A comunidade esteve presente com três palestras: Enter SCRUM, A linguagem Ruby e o framework Rails e Testes de software.

III Semana Academica UFPA 2013

Continue lendo