• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Design de código: qualidade que faz a diferença, qcon 2011
 

Design de código: qualidade que faz a diferença, qcon 2011

on

  • 3,404 views

Apresentação de design de código e a qualidade de um projeto a longo prazo. Apresentado por Guilherme Silveira na QCON sp 2011

Apresentação de design de código e a qualidade de um projeto a longo prazo. Apresentado por Guilherme Silveira na QCON sp 2011

Statistics

Views

Total Views
3,404
Views on SlideShare
3,389
Embed Views
15

Actions

Likes
12
Downloads
0
Comments
1

5 Embeds 15

http://twitter.com 6
http://us-w1.rockmelt.com 5
http://a0.twimg.com 2
https://twitter.com 1
http://paper.li 1

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Design de código: qualidade que faz a diferença, qcon 2011 Design de código: qualidade que faz a diferença, qcon 2011 Presentation Transcript

  • Design de Códigoqualidade a longo prazo Guilherme Silveira @guilhermecaelum
  • o difícil de um projeto é implementar bem
  • Implementação Design Arquitetura
  • Implementação Design Arquitetura
  • IOC
  • IOCDESIGN
  • IOC Usando uma boa prática de designPaulo Silveira DESIGN
  • IOC Usando uma boa prática de designPaulo Silveira DESIGN ARQUITETURA
  • IOC Usando uma boa prática de designPaulo Silveira DESIGN Mudamos a arquitetura e economizamos $$$. ARQUITETURA Sérgio Lopes
  • DESIGNIMPLEMENTAÇÃO
  • DESIGN Como seu código se comunica? (design interface de comunicação)IMPLEMENTAÇÃO
  • DESIGN Como seu código se comunica? (design interface de comunicação) Como seu código é executado? (design da implementação)IMPLEMENTAÇÃO
  • design arquitetura java, ruby, scala, objective-c, c# servidores, firewalls etc implementação
  • (s
  • arquitetura toda bem definida é muito bonita...
  • arquitetura toda bem definida é muito bonita... mas nem sempre é fácíl entender
  • A única coisa que existe é a implementação
  • o difícil de um projeto é implementar bem
  • Interpreto o código através de como ele se comunica.ver através dos olhos de design
  • ver através dos olhos da arquitetura Interpreto o código através de como partes do sistema influenciam outras. e caracteristicas que nascem disso
  • várias maneirasde ver o código
  • design := uma interpretaçãoarquitetura := outra interpretação
  • não posso falar de arquitetura ou de design sem falar de implementação
  • .
  • arquitetura é o mínimose a arquitetura não atende, não há conversa
  • o que sobra é pensarmos no design...de interface ===> dificil manutenção de código ===> dificil manutenção
  • veremos código
  •       def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end fonte pequena?
  •       def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end agora sim? fonte 16
  • 23...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • 23...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • mas e se... 23...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • mas eese... mas se... 23...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • mas eese... mas ese... 23... mas se...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • mas eese... mas ese... 23... mas ese... mas se...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • mas eese... mas ese... 23... mas ese... mas ese... mas se...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • mas eese... mas ese... 23... mas ese... mas ese... mas se...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • mas eese... mas ese... 23... mas ese... mas ese... mas ese... mas se...      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • conciso?
  •       def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • o fluxo é COMPLEXO      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • o fluxo éSEMANTICA não há COMPLEXO      def _read_attribute(attr_name)        attr_name = attr_name.to_s        attr_name = self.class.primary_key if attr_name == id        value = @attributes[attr_name]        unless value.nil?          if column = column_for_attribute(attr_name)            if unserializable_attribute?(attr_name, column)              unserialize_attribute(attr_name)            else              column.type_cast(value)            end          else            value          end        end      end
  • variáveis zoadas?Nico Steppat
  • variáveis zoadas? Non. Nonca vi.Nico Steppat
  • complexidade invisivel        def cached_attributes          @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set        end
  • complexidade invisivel        def cached_attributes          @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set        end Mateus, programador do cão
  • complexidade invisivel        def cached_attributes          @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set        end Ahn? Mateus, programador do cão
  • entendeu?        def cached_attributes          @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set        end
  • entendeu?      def cached_attributes        @cached_attributes ||= columns.select { |c|cheable_column?(c) }.map { |col| col.name }.to_set      end mas essa linha não cabe nem em slide!!!!! vergonha
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end for
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end UMA LINHA for
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end UMA LINHA for if
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end UMA LINHA for for if
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end UMA LINHA for for for if
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end UMA LINHA for for for oops... if if
  • quantos fors tem aqui?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end UMA LINHA for for for oops... if if Mein Gott. Coisa assim nonca vi!
  • QUANTOS TESTES PRECISA?      def cached_attributes        @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set      end
  • e agora?     def cached_attributes       @cached_attributes ||= columns.select { |c| cacheable_column?(c) } .map { |col| col.name } .to_set     end
  • ,
  • dê enter tarefa do bem
  • menos palavras zoou seu código um enter não mata        def cached_attributes          @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set        end
  • concisão = com o mínimo de palavras, deixar claro tarefa do bem
  • concisão =baixar o nível =
  • concisão = eu tô bembaixar o nível = ˆo b3w especialista em linguagem de programação miguxês
  • cliente.a
  • cliente.a meta-aspecto-meta-aspecto programador
  • cliente.aQuer ver uma mágica? meta-aspecto-meta-aspecto programador
  • cliente.aacontece o método b, c, d, e, f, ... Quer ver uma mágica? meta-aspecto-meta-aspecto programador
  • cliente.a acontece o método b, c, d, e, f, ... Quer ver uma mágica?Meta meta meta meta programming. meta-aspecto-meta-aspecto programador
  •        # Deletes the records according to the <tt>:dependent</tt> option.       def delete_records(records, method)         if method == :destroy           records.each { |r| r.destroy }           update_counter(-records.length) unless inverse_updates_counter_cache?         else           keys = records.map { |r| r[reflection.association_primary_key] }           scope = scoped.where(reflection.association_primary_key => keys)           if method == :delete_all             update_counter(-scope.delete_all)           else             update_counter(-scope.update_all(reflection.foreign_key => nil))           end         end       end
  • quem escreveu?
  • meu amigo sérgio
  •        # Deletes the records according to the <tt>:dependent</tt> option.       def delete_records(records, method)         if method == :destroy           records.each { |r| r.destroy }           update_counter(-records.length) unless inverse_updates_counter_cache?         else           keys = records.map { |r| r[reflection.association_primary_key] }           scope = scoped.where(reflection.association_primary_key => keys)           if method == :delete_all             update_counter(-scope.delete_all)           else             update_counter(-scope.update_all(reflection.foreign_key => nil))           end         end       end
  • um “if if if if if if” dói (aka. sanduíche íche íche pattern)
  • ninguém acerta de primeira É vital refatorar!
  • esse dói?select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo
  • esse dói? select * from Contatos where a=b or (c=d && e=f) order by primeiro_campoMaurício Aniche
  • esse dói? select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo Como você testaria isso?Maurício Aniche
  • esse dói? select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo Como você testaria isso? mock.assert(_.select(“select from ...”))?Maurício Aniche
  • esse dói? select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo Como você testaria isso? mock.assert(_.select(“select from ...”))? 1 teste?Maurício Aniche
  • O objetivo não é usar outro, ou esconder o controle de fluxo.Quebre ele em dois. Mais faceis de entender
  • O objetivo não é usar outro, ou esconder o controle de fluxo.Quebre ele em dois. Mais faceis de entender
  • teste é moda, é positivo, é importante, e garante várias coisas
  • mas
  • sua cobertura mente
  • select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo limit 2
  • select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo limit 2
  • select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo limit 2
  • Facinho...select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo limit 2
  • Facinho... select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo limit 2Martin Fowler
  • Facinho... select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo limit 2 sql também é linguagem...Martin Fowler
  • Facinho... select * from Contatos where a=b or (c=d && e=f) order by primeiro_campo limit 2 sql também é linguagem... mina gata hein...Martin Fowler
  • dá para fazer lógica sem fazer lógica? não dá!
  • menos de 5 testes não garantomas a cobertura diz “100%”...mentirosa ...
  • de verdade, não assim: - teste sem assert - teste verifica que uma string é passada - teste “salva”
  • Um código é dificil de entender pois tem fluxos.São os fluxos que deixam ele dificil.
  • tarefa do bemfluxo “invisíveis”, TESTE
  • conscientizar-se da complexidade de nosso códigoJim Webber
  • conscientizar-se da complexidade de nosso código não adianta esconder o spaguetti, ele continua lá.Jim Webber
  • conscientizar-se da complexidade de nosso código não adianta esconder o spaguetti, ele continua lá. tem que deixar explícito!Jim Webber
  • tarefa do bem para trabalhar com algo complexonão se deve fingir que ele não existe mas ensinar a resolver o problema
  • esconder o complexo é julgar alguem incapaza complexidade continuará lá... agora com um gargalo
  • pior ainda, quem usa ele, vai usar mal usado pois não sabe o que esta acontecendo
  • se você tem que executar algo sempre que cria um Cliente?
  • se você tem que executar algosempre que cria um Cliente?
  • se você tem que executar algo sempre que cria um Cliente?
  • declare dependência e código no CONSTRUTOR
  • declare dependência e código no CONSTRUTORmas e no Rails, Javabeans, Hibernate, etc?
  • construtor não faz nadaatributos públicos (get/set/attr)
  • O padrão de OO no mercado é a “orgia dos objetos” pattern. Todo mundo pega todo mundo.
  • Duvidou? Spring: CTRL+F staticRails: ActiveRecord.methods.size
  • Lição de Casa? Apague um getter e um setter.Um atributo. Controle o escopo. Veja a caca que já está feita...
  • relacionamentos classe Clientes?
  • relacionamentos@OneToManyList<Usuario> clientes;+ 10 metodos classe Clientes?
  • relacionamentos has_many :clientes, :class => Us +10 metodos@OneToManyList<Usuario> clientes;+ 10 metodos classe Clientes?
  • classe Clientes
  • classe Clientespublic Clientes getClientes() { return new Clientes(this.clientes);}
  • classe Clientes def clientes Clientes.new(super) endpublic Clientes getClientes() { return new Clientes(this.clientes);}
  • classe Clientes def clientes Clientes.new(super) endpublic Clientes getClientes() { return new Clientes(this.clientes);} + encapsulamento
  • a questao da web nao ser OO a web eh outra coisa o outro sistema é outra coisaCLIENTE
  • a questao da web nao ser OO a web eh outra coisa o outro sistema é outra coisaCLIENTE
  • a questao da web nao ser OO a web eh outra coisa o outro sistema é outra coisaCLIENTE
  • a questao da web nao ser OO a web eh outra coisa o outro sistema é outra coisaCLIENTE BANCO
  • a questao da web nao ser OO a web eh outra coisa o outro sistema é outra coisaCLIENTE BANCO
  • invisivel (esconder) ou clara e bem definida
  • frameworkscomponent based escondem a web...
  • frameworkscomponent based escondem a web... Mas e se minha preocupação é fazer um sistema otimizado para a web? (keynote do sérgio)
  • frameworkscomponent based escondem a web... Mas e se minha preocupação é fazer um sistema otimizado para a web? (keynote do sérgio) booooo!
  • AR mistureba. menos camadas :) modelo domínio banco modelo banco queries insertstodo mundo tem acesso a tudo ESCOPO
  • adiciona uma camda :(. entra o controle de escopo. :) banco modelo do domínio ESCOPO ESCOPO
  • adiciona uma camda :(. entra o controle de escopo. :) modelo banco banco queries inserts modelo do domínio ESCOPO ESCOPO
  • como moldar nosso sistema entao?
  • modele REGRAS
  • Qualquer coisa que eu mudar, quebra...
  • Qualquer coisa que eu mudar, quebra...
  • Qualquer coisa que eu mudar, quebra...
  • Qualquer coisa que eu mudar, quebra...
  • Qualquer coisa que eu mudar, quebra...
  • no lugar ADEQUADO
  • post post postAh! Quebrou encapsulamento dá nisso!
  • post post postAh! Quebrou encapsulamento dá nisso!
  • post post postAh! Quebrou encapsulamento dá nisso!
  • post post postAh! Quebrou encapsulamento dá nisso!
  • post post postAh! Quebrou encapsulamento dá nisso!
  • Posso agulhar? post post postAh! Quebrou encapsulamento dá nisso!
  • no lugar ADEQUADOse eu mudar, eu quebro... mas ai tudo bem! encapsulamento++ demeter++
  • no lugar ADEQUADOse eu mudar, eu quebro... mas ai tudo bem! encapsulamento++ demeter++
  • presentation code != domain code controller model viewif discussion.author==myself || myself.roles[:moderator]
  • presentation code != domain code controller model if discussion.author==myself view myself.roles[:moderator]if mysel.canEdit(discussion)
  • esses ifs não ficam repetidos em várias views
  • abra *.jsp, *.erb, *.ssp, *.similares CTRL+F, if com algo != de booleanCTRL+F, if com chamada != de boolean
  • sem arquitetura adequadanão há conversa
  • o código existeo resto, é interpretação
  • código é complicado
  • esconder o complicado não é simplificar
  • se é difícil de testar,o código tem débito
  • @guilhermecaelumhttp://www.caelum.com.brhttp://online.caelum.com.brobrigado