2009/9/15 Nicolás Sanguinetti <[email protected]>:
> 2009/9/15 Nicolás Sanguinetti <[email protected]>:
>> 2009/9/14 Sebastian A. Espindola <[email protected]>:
>>> Gente,
>>>  Estaba tirando código para un proyecto personal (una implementación
>>> en Ruby de
>>>  un server del protocolo OpenDMTP) y me encontre con la necesidad de
>>> que una clase
>>>  interprete si los datos que recibe desde un socket estan en un
>>> formato binario o texto
>>>  y genere una instancia que actue sobre esa codificación.
>>
>> Hola, me llamo Nicolás y no entiendo nada de diplomacia. Tu solucion
>> es horrible.
>>
>> Sin saber bien lo que estas haciendo (lease, no se que es OpenDMTP) lo
>> que yo haría (y después, abajo, comento tu código parte por parte.
>
> Eh, por cierto, FAIL mio, tendría que ser algo como esto:
>
> module Packet
>  BINARY_PACKET_TYPE = 224
>  ASCII_PACKET_TYPE = 36
>
>   def self.read(message)
>     case message
>     when BINARY_PACKET_TYPE; Packet::Binary.new(message)
>     when ASCII_PACKET_TYPE;  Packet::Text.new(message)
>     else raise ArgumentError, "Wrong packet type: #{message}"
>   end
>
>   class Binary
>   end
>
>   class Text
>   end
> end

Ta, doble FAIL: me falto el `end` que cierra el `case message`.

Pero ta, se entiende la idea :)

> O bueno, los nombres capaz que no son los mejores (de nuevo, ni idea
> que es OpenDMTP :)), pero no esta bueno tirar numeros "al azar" en el
> medio del codigo :)
>
> -f
>
>> Packet.read(...)
>>
>> Fijate como no tenés que andar haciendo aliases ni mapeando strings a
>> clases, y como me ahorro varios niveles de indirección.
>>
>>>  Leyendo varios articulos encontrados en google respecto a la
>>> implementación del patron
>>>  factory en ruby y jugando un poco con metaprogramación, me quedó el
>>> siguiente codigo:
>>>
>>>  class Packet
>>>
>>>    class << self
>>>      alias :nuevo :new
>>>
>>>      def inherited(subclass)
>>>        class << subclass
>>>          alias :new :nuevo
>>>        end
>>>      end
>>
>> Sobre esto:
>>
>> 1) (esta es a título personal) por favor, POR FAVOR, no escriban
>> nombres de métodos en español. Queda horrible leer código con pedazos
>> en otros idiomas.
>>
>> Imaginate si mañana buscás una librería que soluciona un problema X, y
>> empezás a usarla, y cuando te encontrás con un error y querés revisar
>> el código, los comentarios y la mitad de los métodos están escritos en
>> ruso? :-/
>>
>> (ojo, digo ruso como podría decir cualquier idioma, si justo sabés
>> ruso cambialo por otro :P)
>>
>> 2) En mi opinion personal, no esta bueno redefinir Class#new (en este
>> caso particular Packet.new). Prefiero mil veces agregar otro metodo de
>> clase que llame new. Pero ta, ponele que queres igual usar new, porque
>> te gusto, esto alcanza:
>>
>> class Packet
>>  class << self
>>    alias_method :new_without_factory, :new
>>  end
>>
>>  def self.new(*args)
>>    # haces cosas
>>    new_without_factory(*args)
>>  end
>> end
>>
>> No tenes que usar self.inherited ni dar esas vueltas que te hacen leer
>> como 3 veces el código para saber que querés lograr.
>>
>>>      def new(*args)
>>>        msg = *args
>>>        encoding = get_packet_encoding(msg)
>>>        Kernel.const_get(encoding).new unless encoding == "Unknown"
>>>      end
>>
>> Tiene sentido que Packet.new reciba más de un argumento? Porque
>> después cuando llamas BinaryPacket.new, o TextPacket.new, no les estás
>> pasando los args.
>>
>> No se si te falto un new(*args) o simplemente querés usar el primer
>> argumento para deducir el tipo de clase a usar. Si es lo segundo,
>> entonces usar splat-args no tiene sentido. Definí simplemente 'msg'
>> como parametro.
>>
>>>      def get_packet_encoding(msg)
>>>        encoding = case msg[0]
>>>          when 224 then "BinaryPacket"
>>>          when 36 then "TextPacket"
>>>          else "Unknown"
>>>        end
>>>      end
>>>    end
>>
>> Aca viene la parte que creo es más fea. Para qué querés devolver
>> strings y hacer const_get de esos strings, cuando podés devolver
>> directamente la clase que querés? Estás agregandole niveles de
>> indirección totalmente innecesarios.
>>
>> Y por último, "Unknown". Si yo hago Packet.new(42) con tu codigo,
>> devuelve nil. Eso es feo. Tener que andar chequeando por nil es Feo
>> (con f mayúscula).
>>
>> Vos querés que *no funcione*, entonces lo ideal es que el usuario
>> reciba una notificación de que lo que hace, *no funciona*. Ergo, una
>> excepción me parece una mejor idea. Cuál? Depende, si estás haciendo
>> una libreria capaz que definir tu propia excepción tipo class
>> WrongPacketTypeProvided < ArgumentError; end tiene sentido. Si no, con
>> tirar un ArgumentError está bien (en mi opinión, es debatible :))
>>
>>>    def initialize
>>>      puts "hola desde #{self.class}"
>>>    end
>>>  end
>>>
>>>  class TextPacket < Packet
>>>  end
>>>
>>>  class BinaryPacket < Packet
>>>  end
>>
>> Y ta, después, lo de hacer Packet::Text en lugar de TextPacket <
>> Packet es puramente un tema de estilo personal, dado lo fácil que es
>> en ruby de pisar cosas sin darte cuenta, prefiero poner todo en
>> namespaces.
>>
>> Si TextPacket y BinaryPacket heredaban de Packet por algún tema de
>> funcionalidad compartida, es fácil de cambiar. O directamente, definí
>> la funcionalidad compartida en el módulo Packet, y hace include Packet
>> adentro de las child classes.
>>
>>>  No conocia la posibilidad de definir alias de metodos, la
>>> posibilidad de hacer modificaciones
>>>  temporales en runtime "backupeando" el metodo con un alias es alucinante.
>>>
>>>  Si uno le muestra esto a un programador que no conozca ruby, cuando
>>> entienda como
>>>  funciona se le vuela el peluquín. :)
>>>
>>>  Calculo que en un par de meses voy a tener una implementacion
>>> cliente-servidor de
>>>  OpenDMTP decente basada en EventMachine, cuando la termine la voy a 
>>> liberar.
>>>
>>>  En fin, queria compartir mi "descubrimiento" con ustedes.
>>
>> Y ta, por último, no te lo tomes a mal, si el lenguaje te parece
>> violento o algo, creeme que no es intencional, cuando digo que no
>> entiendo nada de diplomacia, es cierto, simplemente te digo lo que me
>> parece haría a tu código mejor :)
>>
>> Y ta, obviamente, todo el mundo está invitado a demostrarme como
>> mejorar mi ejeplo :D
>>
>> <chivo> Los code reviews son divertidos, tu equipo puede mejorar su
>> calidad de código usando http://howsmycode.com :P </chivo>
>>
>> -foca
>>
>
_______________________________________________
Ruby mailing list
[email protected]
http://lista.rubyargentina.com.ar/listinfo.cgi/ruby-rubyargentina.com.ar

Responder a