SlideShare ist ein Scribd-Unternehmen logo
1 von 60
Reglas de Código
(Code Rules)
Pablo Santos Luaces
@psluaces
Presentación
• Pablo Santos Luaces - @psluaces
• Fundador de Códice Software (2005) y CTO
Soporte, marketing, Desarrollo, Roadmap
Somos 18
https://www.plasticscm.com/company/team
Desarrollamos productos de control de versiones
Tenemos clientes de todo tipo
Enormes, medianos, pequeños
Financial Sector IT & Embedded SW Automobile & Logistics
Games & 3D DesignDefense & Gov.
Utilities & Logistics
Medical Devices
Objetivo
+1.8 millones de
líneas de código
después…
Solo nos importa que todo sea lo más
sencillo posible
Podríamos
reducir todo a
1 sola regla…
Pasa parámetros, Luke
Pasar parámetros evita casi todos los males
• Adiós a los Singletons.
• Las dependencias y efectos laterales se hacen explícitos.
• Es más fácil de testear todo (casi funcional).
Volveremos a ello más adelante
Y nos hemos puesto unas reglas
• Jamás usamos herencia (no adoramos la OOP precisamente)
• Nunca usamos sobrecarga de métodos. Ni constructores.
• Datos y comportamiento… bien separados! No más Revision.Save()
• Nada de “elses”.
• Muchas subclases e interfaces que pertenecen a clases.
• Nada de “doers, handlers”. Mejor “SaveRevision.Save()” que “RevisionSaver”.
Que me gustaría compartir y … discutir
¿Cuál es el principal atributo que debe
tener el código? – un mantra
“Programs must be written for people to read, and only incidentally for
machines to execute.”
“The Structure and Interpretation
of Computer Programs”.
@psluaces
Una historia de objetos
Item Changeset LabelBranch Attribute
Revision
Item Changeset LabelBranch Attribute
Revision
id date name comment id date comment id date name comment id date name commentid date
id date
Item Changeset LabelBranch Attribute
Revision
id date name comment
Object
Server Code
Datalayer
SQL
Server
MySQL SQLite
¿Cómo guardas objetos?
• Datalayer.Save(Object o) parecía mala idea.
• Era mucho mejor Object.Save(), se guardaba solito.
• Y con miles de objetos? Pues nada, miles de Save()…
No íbamos a ser tan cutres como para hacer una función en la era de los ORM, verdad?
Por supuesto no funcionó
• Datalayer.Save(Object o)
• Que dentro tenía un SWITCH enorme para guardar cada objeto de una forma… y con el tiempo se
fueron optimizando y separando…
• Y era todo un desastre, porque querías buscar desde qué sitios se guardaban ramas y… no había
manera, era todo Datalayer.Save “genérico”.
Y pasamos a la segunda peor versión
Ahora lo hacemos tan explícito…
• Por supuesto no más herencia.
• Y los métodos son de este tipo:
• Datalayer.SaveRevision(Revision r)
• Datalayer.SaveBranch(Branch b)
• Etc
• Tan explícito y sencillo como podemos.
• Sí, son muchos métodos… y qué?
Que no hay lugar a dudas
Herencias
La herencia es el root of all evil
• El 99% de las veces la herencia se usa de forma incorrecta.
• O bien se usa para “compartir código común” – error, para eso está la composición (no cumple con
subtipado).
• O bien para “montar castillos terribles”, para “generalizar”, para “cuando cambie”.
Porque es dificilísimo usarlo bien
La herencia es un problema en sí mismo
• Muy pocos programadores desarrollan frameworks, si no aplicaciones, luego no deben
preocuparse de romper compatibilidad si no de hacer código legible y sencillo.
• No generalices hasta que tengas al menos 3 ejemplos: típica capa abstracta de acceso a base de
datos, para acceder a un único tipo de base de datos! :-S
A menos que hagas frameworks… pero casi nadie hace eso
Un ejemplo de herencia *real*
Para un triste progreso!!!
FiniteProgress
Progress
abstract
FastUpdateProgress
IFiniteProgress
FastUpdateApplierProgress
CLIFastUpdateUpdateApplierProgress
CLIFastUpdateProgress
Que se quedó así
Si es algo simple… el código debe ser simple
FiniteProgress
Progress
abstract
FastUpdateProgress
IFiniteProgress
FastUpdateApplierProgress
CLIFastUpdateUpdateApplierProgress
CLIFastUpdateProgress
IFastUpdateProgress
FastUpdateApplierProgress FastUpdateProgress
La herencia destruye neuronas
• Estas leyendo código y ves un “abstract” o un “protected” o un “virtual”…
• Y de inmediato piensas “cuidado”! Alguien está implementando/extendiendo/modificando ese
comportamiento.
• Cerebro en modo peligro.
• Y a veces es sólo “por si acaso”, para hacerlo extensible… pa na!
• Un “private” nunca te pone en ese modo, está clarísimo que nunca, nunca lo llamará nadie. Te da
confianza, es bueno, fácil, no gastas cerebro para nada.
Y quita confianza
Otro ejemplo muy real de herencia
Que le pasó a un amigo
Siempre composición
Casi nunca se cumplen las relaciones “is-a” y solo quieres compartir código
Eliminar herencia para simplificar
Nada de “uso lo del padre”
No reutilices
No reutilices antes de tiempo
Es casi como salir de Matrix
• Quién usa EncryptPassword? Solo CredentialsDialog? Pues el método ahí tranquilo y privado.
• “Es que eso debería estar en un sitio común y”…
• No!
• Común cuando se use desde más de un sitio, mientras tanto, en un único sitio. Evita complicarte la
vida diseñando “para luego”.
Generalizamos solo si hay varios ejemplos
Nunca antes de tiempo
Es más fácil hacerlo bien…
• La optimización prematura es un problema ampliamente aceptado.
• Pero se unen otros no tan comúnmente aceptados:
• La reutilización prematura – “para cuando cambie” – salimos tatuados con esto de la universidad. Escribe
código para “hoy” no vaya a ser que no llegues a mañana. (Torvalds dixit!)
• La generalización prematura – intentar hacer todo “genérico” en lugar de terriblemente simple.
Es MUCHO más fácil hacer cosas concretas, no genéricas, resolviendo el problema de HOY. Resuelve el
problema de hoy e igual estás en el negocio para resolver el de mañana. Resuelve el de mañana y no
llegarás.
Una vez que tienes claro que está bien
Las reglas
Y nos hemos puesto unas reglas
• Jamás usamos herencia (no adoramos la OOP precisamente)
• Nunca usamos sobrecarga de métodos. Ni constructores.
• Datos y comportamiento… bien separados! No más Revision.Save()
• Nada de “elses”.
• Muchas subclases e interfaces que pertenecen a clases.
• Nada de “doers, handlers”. Mejor “SaveRevision.Save()” que “RevisionSaver”.
Que me gustaría compartir y … discutir
Adiós overload
Que se pueda hacer no quiere decir que sea obligatorio
Ganas claridad de código.
No hay que explicar los constructores ni los métodos, el nombre te dice lo que hacen.
Además, muchos de los métodos sobrecargados no se usan o se pueden evitar pasando un parámetro
extra. Menos métodos => más simple.
Ser flexible NO es bueno => no hacemos frameworks.
Datos y métodos separados
• No es orientado a objetos.
• Pero una vez te liberas de Matrix, vives muy bien.
• Tienes una clase Config.Data y un método Save(Config.Data d).
• Fácil y sencillo.
• Y si la clase Config.Data no permite cambiar sus valores… mejor.
Usamos muchas clases solo de datos… y qué?
Pasa parámetros y no uses globales
No usar variables globales – como en la primera clase de programación
Pasa parámetros y no uses globales
No usar variables globales – como en la primera clase de programación
MAGIA!!!
Es que no son variables globales… son miembros!
• Es que los objetos tienen estado.
• Y así es más fácil porque “no pierdes tiempo” pasando parámetros.
• Y son intrínsecos al objeto.
• Y sí, no hace falta que se pasen.
• Y …
The OOP true religion
Sin excusas!
Pasa los parámetros y nos harás la vida más fácil
Lo siguiente es que todo son funciones
De esto
MergeCalculator calculator = new MergeCalculator(diffs, revs, blah);
MergeResult r = calculator.Calculate();
Pasas a esto:
MergeReult r = CalculateMerge.Calculate(diffs, revs, blah);
No hay estado, ni constructor… y se prueba facilísimo
Empiezas pasando parámetros y luego…
Hemos plagado nuestro código de métodos
estáticos
• Y todo es mucho más fácil.
• No necesitas mocks, ni inyectar dependencias para probar… solo pasar tristes y sencillos
parámetros.
• Mucho del estado incontrolable de hace años, son ahora sencillísimos parámetros.
• Muchas veces es solo cambiar la forma de pensar, y te das cuenta de la absurdez:
ClickCommand command = new ClickCommand(dialog, status, blahblah, blah);
Command.Execute();
Con lo fácil que es: ClickCommand.Execute(dialog, status, blahblah, blah); Y adiós!
Y clases que en realidad son funciones complicadas con varios pasos
Adiós a la complejidad gratuita
• Descubrimos que muchas de las partes complejas lo eran por deporte.
• Por aplicar patrones para tener comandos reusables… en lugar de llamar a una simple función y
ya.
• Muchas jerarquías sobraban.
• Todo podía ser más sencillo.
Un ejemplo en una GUI
Qué debe hacer el OnClick del botón OK?
Welcome to PlasticSCM ×
OK Cancel
Use SSL
Enter the name/IP and portof your server (e.g: myserver.mynetwork.net:8087)
localhost:8087
Configure your credentials
pablo *********** Check
Credentials checked OK
Un ejemplo en una GUI
Qué debe hacer el OnClick del botón OK?
Welcome to PlasticSCM ×
OK Cancel
Use SSL
Enter the name/IP and portof your server (e.g: myserver.mynetwork.net:8087)
localhost:8087
Configure your credentials
pablo *********** Check
Credentials checked OK
• Pues debería recibir un ICommand que ejecute una
acción.
• De ese modo haces que la GUI no dependa de algo
concreto y…
• Para qué???
• El click del botón llama a código totalmente sencillo y
se ve lo que hace, sin cuarenta indirecciones.
Una fácil, salir del if cuanto antes
Es un pecado en “programación estructurada”… pero… y qué?
Nombres de clases
• FileReader => ReadFile
• ProgressCalculator => CalculateProgress
Más fácil, más humano, más “hace algo sencillo” en lugar de es “un calculador de progreso”
Es casi una obsesión
Subclases
Esto va en contra de las normas de buenas prácticas en .NET :-O
Usamos mucho esto, en lugar de polucionar el mundo con clases “de primer nivel” que en realidad no
viven por sí solas… y hacemos lo mismo con las interfaces.
Interfaces definidas dentro de clases
Tú necesitas la interfaz, tú la defines. NO el que la implementa, el que la necesita para funcionar
Ejemplo de pasar parámetros
• Cómo accedemos al API en cada sitio? Un singleton? RestApi.Get().Blah() ???
• No, pasamos el REST API a cada clase.
• Puede parecer pesado => pero las dependencias se hacen clarísimas en lugar de ocultas.
gmaster – usa un REST API para comunicarse con gmaster.io
Visibilidad mínima
• Nada es “para si luego”.
• Se hace solo lo que uses *ahora*.
Si puede ser private, mejor que internal, mejor que public
Properties
• Regla: una property NUNCA realiza una operación.
• Ejemplo: Branch.Name simplemente devolverá un valor que ya tenga el objeto, jamás disparará
una llamada al servidor (esto nos ha pasado).
En C# las properties son algo que ha estado desde siempre
Ermitaños del código
• https://pragprog.com/book/kpiod/interface-oriented-design
• Chatty object oriented interfaces – un error que cometimos hace mucho tiempo (¡porque parecía
que era la forma de hacerlo bien!)
• En red: siempre “document oriented” -> minimiza roundtrips. No es “transparente” pero está bien
Prefiero un triste socket que Remoting, WCF, Protocol Buffers, DCOM, RMI, etc, etc
Terminando
Bibliografía
• Clean Code – Robert C. Martin
• Implementation Patterns – Kent Beck
• Code Complete – Steve McConnell
Adoramos el código
• The Code is the Design – Jack W. Reeves -
http://www.developerdotstar.com/mag/articles/reeves_design_main.html
Conclusión
• Cuantas menos cosas complicadas, mejor.
• No pasa nada por no usar lo último del nuevo C#. Es duro quitarse el complejo.
Escribimos código que cualquiera pueda entender
THANKS
FOR YOUR
TIME
You can reach me at
@psluaces

Weitere ähnliche Inhalte

Ähnlich wie Reglas de Código Simple

DevOps & Infraestructura como código: Promesas Rotas
DevOps & Infraestructura como código: Promesas RotasDevOps & Infraestructura como código: Promesas Rotas
DevOps & Infraestructura como código: Promesas RotasRicard Clau
 
NoEresTanEspecial-PulpoCon22.pdf
NoEresTanEspecial-PulpoCon22.pdfNoEresTanEspecial-PulpoCon22.pdf
NoEresTanEspecial-PulpoCon22.pdfRicard Clau
 
Charla Tdd Uji 032010
Charla Tdd Uji 032010Charla Tdd Uji 032010
Charla Tdd Uji 032010Carlos Ble
 
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012Alfredo Chavez
 
.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez
.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez
.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez.NET UY Meetup
 
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring -  Junta General del MexALN 28/06/2012Retos en la Adopción del Refactoring -  Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012Alfredo Chavez
 
Buenos Aires vs. (London vs. Chicago) Agiles 2020
Buenos Aires vs. (London vs. Chicago) Agiles 2020Buenos Aires vs. (London vs. Chicago) Agiles 2020
Buenos Aires vs. (London vs. Chicago) Agiles 2020Hernan Wilkinson
 
Rooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalez
Rooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalezRooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalez
Rooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalezRootedCON
 
Técnicas y herramientas para que la computadora haga más y el programador m...
Técnicas y herramientas para que la computadora haga más y el programador m...Técnicas y herramientas para que la computadora haga más y el programador m...
Técnicas y herramientas para que la computadora haga más y el programador m...Hernan Wilkinson
 
Escalabilidad y alto rendimiento con Symfony2
Escalabilidad y alto rendimiento con Symfony2Escalabilidad y alto rendimiento con Symfony2
Escalabilidad y alto rendimiento con Symfony2Ricard Clau
 
Cobertura de Código con Tests Funcionales
Cobertura de Código con Tests Funcionales Cobertura de Código con Tests Funcionales
Cobertura de Código con Tests Funcionales atSistemas
 
Observabilidad: Todo lo que hay que ver
Observabilidad: Todo lo que hay que verObservabilidad: Todo lo que hay que ver
Observabilidad: Todo lo que hay que verSoftware Guru
 
Presentación de Paradis
Presentación de ParadisPresentación de Paradis
Presentación de ParadisC-cube ITESMCQ
 
Análisis de Metadatos con la Foca
Análisis de Metadatos con la FocaAnálisis de Metadatos con la Foca
Análisis de Metadatos con la FocaJose Moruno Cadima
 
Plantillas en Drupal 6
Plantillas en Drupal 6Plantillas en Drupal 6
Plantillas en Drupal 6Manuel Garcia
 

Ähnlich wie Reglas de Código Simple (20)

DevOps & Infraestructura como código: Promesas Rotas
DevOps & Infraestructura como código: Promesas RotasDevOps & Infraestructura como código: Promesas Rotas
DevOps & Infraestructura como código: Promesas Rotas
 
NoEresTanEspecial-PulpoCon22.pdf
NoEresTanEspecial-PulpoCon22.pdfNoEresTanEspecial-PulpoCon22.pdf
NoEresTanEspecial-PulpoCon22.pdf
 
Charla Tdd Uji 032010
Charla Tdd Uji 032010Charla Tdd Uji 032010
Charla Tdd Uji 032010
 
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
 
.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez
.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez
.NET UY Meetup 4 - AOP & PostSharp by Bruno Bologna & Fabian Fernandez
 
Scrum y craftsmanship
Scrum y craftsmanshipScrum y craftsmanship
Scrum y craftsmanship
 
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring -  Junta General del MexALN 28/06/2012Retos en la Adopción del Refactoring -  Junta General del MexALN 28/06/2012
Retos en la Adopción del Refactoring - Junta General del MexALN 28/06/2012
 
Buenos Aires vs. (London vs. Chicago) Agiles 2020
Buenos Aires vs. (London vs. Chicago) Agiles 2020Buenos Aires vs. (London vs. Chicago) Agiles 2020
Buenos Aires vs. (London vs. Chicago) Agiles 2020
 
Rooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalez
Rooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalezRooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalez
Rooted2020 dev secops-into_the_unknown_-_jesus_alcalde_-_daniel_gonzalez
 
Técnicas y herramientas para que la computadora haga más y el programador m...
Técnicas y herramientas para que la computadora haga más y el programador m...Técnicas y herramientas para que la computadora haga más y el programador m...
Técnicas y herramientas para que la computadora haga más y el programador m...
 
Codemotion 2016
Codemotion 2016Codemotion 2016
Codemotion 2016
 
Escalabilidad y alto rendimiento con Symfony2
Escalabilidad y alto rendimiento con Symfony2Escalabilidad y alto rendimiento con Symfony2
Escalabilidad y alto rendimiento con Symfony2
 
Cobertura de Código con Tests Funcionales
Cobertura de Código con Tests Funcionales Cobertura de Código con Tests Funcionales
Cobertura de Código con Tests Funcionales
 
Hibernate - JPA @luce
Hibernate - JPA @luceHibernate - JPA @luce
Hibernate - JPA @luce
 
Observabilidad: Todo lo que hay que ver
Observabilidad: Todo lo que hay que verObservabilidad: Todo lo que hay que ver
Observabilidad: Todo lo que hay que ver
 
Presentación de Paradis
Presentación de ParadisPresentación de Paradis
Presentación de Paradis
 
Análisis de Metadatos con la Foca
Análisis de Metadatos con la FocaAnálisis de Metadatos con la Foca
Análisis de Metadatos con la Foca
 
legacy
legacylegacy
legacy
 
Plantillas en Drupal 6
Plantillas en Drupal 6Plantillas en Drupal 6
Plantillas en Drupal 6
 
Testing, tipos y otros flamewars
Testing, tipos y otros flamewarsTesting, tipos y otros flamewars
Testing, tipos y otros flamewars
 

Mehr von psluaces

Refactoring merged code - ReSharper meets SemanticMerge
Refactoring merged code - ReSharper meets SemanticMergeRefactoring merged code - ReSharper meets SemanticMerge
Refactoring merged code - ReSharper meets SemanticMergepsluaces
 
Semantic Merge - No fear refactoring
Semantic Merge - No fear refactoringSemantic Merge - No fear refactoring
Semantic Merge - No fear refactoringpsluaces
 
How dvcs can reduce your development costs and enhance productivity final
How dvcs can reduce your development costs and enhance productivity finalHow dvcs can reduce your development costs and enhance productivity final
How dvcs can reduce your development costs and enhance productivity finalpsluaces
 
Merge Recursive Explained
Merge Recursive ExplainedMerge Recursive Explained
Merge Recursive Explainedpsluaces
 
Semanticmerge
SemanticmergeSemanticmerge
Semanticmergepsluaces
 
Cas 2011 Integración continua vs controlada
Cas 2011 Integración continua vs controladaCas 2011 Integración continua vs controlada
Cas 2011 Integración continua vs controladapsluaces
 
Creating parallel tests for NUnit with PNUnit - hands on lab
Creating parallel tests for NUnit with PNUnit - hands on labCreating parallel tests for NUnit with PNUnit - hands on lab
Creating parallel tests for NUnit with PNUnit - hands on labpsluaces
 

Mehr von psluaces (7)

Refactoring merged code - ReSharper meets SemanticMerge
Refactoring merged code - ReSharper meets SemanticMergeRefactoring merged code - ReSharper meets SemanticMerge
Refactoring merged code - ReSharper meets SemanticMerge
 
Semantic Merge - No fear refactoring
Semantic Merge - No fear refactoringSemantic Merge - No fear refactoring
Semantic Merge - No fear refactoring
 
How dvcs can reduce your development costs and enhance productivity final
How dvcs can reduce your development costs and enhance productivity finalHow dvcs can reduce your development costs and enhance productivity final
How dvcs can reduce your development costs and enhance productivity final
 
Merge Recursive Explained
Merge Recursive ExplainedMerge Recursive Explained
Merge Recursive Explained
 
Semanticmerge
SemanticmergeSemanticmerge
Semanticmerge
 
Cas 2011 Integración continua vs controlada
Cas 2011 Integración continua vs controladaCas 2011 Integración continua vs controlada
Cas 2011 Integración continua vs controlada
 
Creating parallel tests for NUnit with PNUnit - hands on lab
Creating parallel tests for NUnit with PNUnit - hands on labCreating parallel tests for NUnit with PNUnit - hands on lab
Creating parallel tests for NUnit with PNUnit - hands on lab
 

Reglas de Código Simple

  • 1. Reglas de Código (Code Rules) Pablo Santos Luaces @psluaces
  • 2. Presentación • Pablo Santos Luaces - @psluaces • Fundador de Códice Software (2005) y CTO Soporte, marketing, Desarrollo, Roadmap
  • 4. Desarrollamos productos de control de versiones
  • 5. Tenemos clientes de todo tipo Enormes, medianos, pequeños Financial Sector IT & Embedded SW Automobile & Logistics Games & 3D DesignDefense & Gov. Utilities & Logistics Medical Devices
  • 7. +1.8 millones de líneas de código después… Solo nos importa que todo sea lo más sencillo posible
  • 10. Pasar parámetros evita casi todos los males • Adiós a los Singletons. • Las dependencias y efectos laterales se hacen explícitos. • Es más fácil de testear todo (casi funcional). Volveremos a ello más adelante
  • 11. Y nos hemos puesto unas reglas • Jamás usamos herencia (no adoramos la OOP precisamente) • Nunca usamos sobrecarga de métodos. Ni constructores. • Datos y comportamiento… bien separados! No más Revision.Save() • Nada de “elses”. • Muchas subclases e interfaces que pertenecen a clases. • Nada de “doers, handlers”. Mejor “SaveRevision.Save()” que “RevisionSaver”. Que me gustaría compartir y … discutir
  • 12. ¿Cuál es el principal atributo que debe tener el código? – un mantra “Programs must be written for people to read, and only incidentally for machines to execute.” “The Structure and Interpretation of Computer Programs”. @psluaces
  • 13. Una historia de objetos
  • 14. Item Changeset LabelBranch Attribute Revision
  • 15. Item Changeset LabelBranch Attribute Revision id date name comment id date comment id date name comment id date name commentid date id date
  • 16. Item Changeset LabelBranch Attribute Revision id date name comment Object
  • 18. ¿Cómo guardas objetos? • Datalayer.Save(Object o) parecía mala idea. • Era mucho mejor Object.Save(), se guardaba solito. • Y con miles de objetos? Pues nada, miles de Save()… No íbamos a ser tan cutres como para hacer una función en la era de los ORM, verdad?
  • 19. Por supuesto no funcionó • Datalayer.Save(Object o) • Que dentro tenía un SWITCH enorme para guardar cada objeto de una forma… y con el tiempo se fueron optimizando y separando… • Y era todo un desastre, porque querías buscar desde qué sitios se guardaban ramas y… no había manera, era todo Datalayer.Save “genérico”. Y pasamos a la segunda peor versión
  • 20. Ahora lo hacemos tan explícito… • Por supuesto no más herencia. • Y los métodos son de este tipo: • Datalayer.SaveRevision(Revision r) • Datalayer.SaveBranch(Branch b) • Etc • Tan explícito y sencillo como podemos. • Sí, son muchos métodos… y qué? Que no hay lugar a dudas
  • 22. La herencia es el root of all evil • El 99% de las veces la herencia se usa de forma incorrecta. • O bien se usa para “compartir código común” – error, para eso está la composición (no cumple con subtipado). • O bien para “montar castillos terribles”, para “generalizar”, para “cuando cambie”. Porque es dificilísimo usarlo bien
  • 23. La herencia es un problema en sí mismo • Muy pocos programadores desarrollan frameworks, si no aplicaciones, luego no deben preocuparse de romper compatibilidad si no de hacer código legible y sencillo. • No generalices hasta que tengas al menos 3 ejemplos: típica capa abstracta de acceso a base de datos, para acceder a un único tipo de base de datos! :-S A menos que hagas frameworks… pero casi nadie hace eso
  • 24. Un ejemplo de herencia *real* Para un triste progreso!!! FiniteProgress Progress abstract FastUpdateProgress IFiniteProgress FastUpdateApplierProgress CLIFastUpdateUpdateApplierProgress CLIFastUpdateProgress
  • 25. Que se quedó así Si es algo simple… el código debe ser simple FiniteProgress Progress abstract FastUpdateProgress IFiniteProgress FastUpdateApplierProgress CLIFastUpdateUpdateApplierProgress CLIFastUpdateProgress IFastUpdateProgress FastUpdateApplierProgress FastUpdateProgress
  • 26. La herencia destruye neuronas • Estas leyendo código y ves un “abstract” o un “protected” o un “virtual”… • Y de inmediato piensas “cuidado”! Alguien está implementando/extendiendo/modificando ese comportamiento. • Cerebro en modo peligro. • Y a veces es sólo “por si acaso”, para hacerlo extensible… pa na! • Un “private” nunca te pone en ese modo, está clarísimo que nunca, nunca lo llamará nadie. Te da confianza, es bueno, fácil, no gastas cerebro para nada. Y quita confianza
  • 27. Otro ejemplo muy real de herencia Que le pasó a un amigo
  • 28. Siempre composición Casi nunca se cumplen las relaciones “is-a” y solo quieres compartir código
  • 29. Eliminar herencia para simplificar
  • 30. Nada de “uso lo del padre”
  • 32. No reutilices antes de tiempo Es casi como salir de Matrix • Quién usa EncryptPassword? Solo CredentialsDialog? Pues el método ahí tranquilo y privado. • “Es que eso debería estar en un sitio común y”… • No! • Común cuando se use desde más de un sitio, mientras tanto, en un único sitio. Evita complicarte la vida diseñando “para luego”.
  • 33. Generalizamos solo si hay varios ejemplos Nunca antes de tiempo
  • 34. Es más fácil hacerlo bien… • La optimización prematura es un problema ampliamente aceptado. • Pero se unen otros no tan comúnmente aceptados: • La reutilización prematura – “para cuando cambie” – salimos tatuados con esto de la universidad. Escribe código para “hoy” no vaya a ser que no llegues a mañana. (Torvalds dixit!) • La generalización prematura – intentar hacer todo “genérico” en lugar de terriblemente simple. Es MUCHO más fácil hacer cosas concretas, no genéricas, resolviendo el problema de HOY. Resuelve el problema de hoy e igual estás en el negocio para resolver el de mañana. Resuelve el de mañana y no llegarás. Una vez que tienes claro que está bien
  • 36. Y nos hemos puesto unas reglas • Jamás usamos herencia (no adoramos la OOP precisamente) • Nunca usamos sobrecarga de métodos. Ni constructores. • Datos y comportamiento… bien separados! No más Revision.Save() • Nada de “elses”. • Muchas subclases e interfaces que pertenecen a clases. • Nada de “doers, handlers”. Mejor “SaveRevision.Save()” que “RevisionSaver”. Que me gustaría compartir y … discutir
  • 37. Adiós overload Que se pueda hacer no quiere decir que sea obligatorio Ganas claridad de código. No hay que explicar los constructores ni los métodos, el nombre te dice lo que hacen. Además, muchos de los métodos sobrecargados no se usan o se pueden evitar pasando un parámetro extra. Menos métodos => más simple. Ser flexible NO es bueno => no hacemos frameworks.
  • 38. Datos y métodos separados • No es orientado a objetos. • Pero una vez te liberas de Matrix, vives muy bien. • Tienes una clase Config.Data y un método Save(Config.Data d). • Fácil y sencillo. • Y si la clase Config.Data no permite cambiar sus valores… mejor. Usamos muchas clases solo de datos… y qué?
  • 39. Pasa parámetros y no uses globales No usar variables globales – como en la primera clase de programación
  • 40. Pasa parámetros y no uses globales No usar variables globales – como en la primera clase de programación MAGIA!!!
  • 41. Es que no son variables globales… son miembros! • Es que los objetos tienen estado. • Y así es más fácil porque “no pierdes tiempo” pasando parámetros. • Y son intrínsecos al objeto. • Y sí, no hace falta que se pasen. • Y … The OOP true religion
  • 42. Sin excusas! Pasa los parámetros y nos harás la vida más fácil
  • 43. Lo siguiente es que todo son funciones De esto MergeCalculator calculator = new MergeCalculator(diffs, revs, blah); MergeResult r = calculator.Calculate(); Pasas a esto: MergeReult r = CalculateMerge.Calculate(diffs, revs, blah); No hay estado, ni constructor… y se prueba facilísimo Empiezas pasando parámetros y luego…
  • 44. Hemos plagado nuestro código de métodos estáticos • Y todo es mucho más fácil. • No necesitas mocks, ni inyectar dependencias para probar… solo pasar tristes y sencillos parámetros. • Mucho del estado incontrolable de hace años, son ahora sencillísimos parámetros. • Muchas veces es solo cambiar la forma de pensar, y te das cuenta de la absurdez: ClickCommand command = new ClickCommand(dialog, status, blahblah, blah); Command.Execute(); Con lo fácil que es: ClickCommand.Execute(dialog, status, blahblah, blah); Y adiós! Y clases que en realidad son funciones complicadas con varios pasos
  • 45. Adiós a la complejidad gratuita • Descubrimos que muchas de las partes complejas lo eran por deporte. • Por aplicar patrones para tener comandos reusables… en lugar de llamar a una simple función y ya. • Muchas jerarquías sobraban. • Todo podía ser más sencillo.
  • 46. Un ejemplo en una GUI Qué debe hacer el OnClick del botón OK? Welcome to PlasticSCM × OK Cancel Use SSL Enter the name/IP and portof your server (e.g: myserver.mynetwork.net:8087) localhost:8087 Configure your credentials pablo *********** Check Credentials checked OK
  • 47. Un ejemplo en una GUI Qué debe hacer el OnClick del botón OK? Welcome to PlasticSCM × OK Cancel Use SSL Enter the name/IP and portof your server (e.g: myserver.mynetwork.net:8087) localhost:8087 Configure your credentials pablo *********** Check Credentials checked OK • Pues debería recibir un ICommand que ejecute una acción. • De ese modo haces que la GUI no dependa de algo concreto y… • Para qué??? • El click del botón llama a código totalmente sencillo y se ve lo que hace, sin cuarenta indirecciones.
  • 48. Una fácil, salir del if cuanto antes Es un pecado en “programación estructurada”… pero… y qué?
  • 49. Nombres de clases • FileReader => ReadFile • ProgressCalculator => CalculateProgress Más fácil, más humano, más “hace algo sencillo” en lugar de es “un calculador de progreso” Es casi una obsesión
  • 50. Subclases Esto va en contra de las normas de buenas prácticas en .NET :-O Usamos mucho esto, en lugar de polucionar el mundo con clases “de primer nivel” que en realidad no viven por sí solas… y hacemos lo mismo con las interfaces.
  • 51. Interfaces definidas dentro de clases Tú necesitas la interfaz, tú la defines. NO el que la implementa, el que la necesita para funcionar
  • 52. Ejemplo de pasar parámetros • Cómo accedemos al API en cada sitio? Un singleton? RestApi.Get().Blah() ??? • No, pasamos el REST API a cada clase. • Puede parecer pesado => pero las dependencias se hacen clarísimas en lugar de ocultas. gmaster – usa un REST API para comunicarse con gmaster.io
  • 53. Visibilidad mínima • Nada es “para si luego”. • Se hace solo lo que uses *ahora*. Si puede ser private, mejor que internal, mejor que public
  • 54. Properties • Regla: una property NUNCA realiza una operación. • Ejemplo: Branch.Name simplemente devolverá un valor que ya tenga el objeto, jamás disparará una llamada al servidor (esto nos ha pasado). En C# las properties son algo que ha estado desde siempre
  • 55. Ermitaños del código • https://pragprog.com/book/kpiod/interface-oriented-design • Chatty object oriented interfaces – un error que cometimos hace mucho tiempo (¡porque parecía que era la forma de hacerlo bien!) • En red: siempre “document oriented” -> minimiza roundtrips. No es “transparente” pero está bien Prefiero un triste socket que Remoting, WCF, Protocol Buffers, DCOM, RMI, etc, etc
  • 57. Bibliografía • Clean Code – Robert C. Martin • Implementation Patterns – Kent Beck • Code Complete – Steve McConnell
  • 58. Adoramos el código • The Code is the Design – Jack W. Reeves - http://www.developerdotstar.com/mag/articles/reeves_design_main.html
  • 59. Conclusión • Cuantas menos cosas complicadas, mejor. • No pasa nada por no usar lo último del nuevo C#. Es duro quitarse el complejo. Escribimos código que cualquiera pueda entender
  • 60. THANKS FOR YOUR TIME You can reach me at @psluaces