language-agnostic

language agnostic - ¿Qué práctica de programación que alguna vez te haya gustado te hizo cambiar de opinión?



language-agnostic (30)

Abreviatura variable / método / tabla / ... Nombres

Solía ​​hacer esto todo el tiempo, incluso cuando trabajaba en idiomas sin límites impuestos en la longitud de los nombres (bueno, probablemente eran 255 o algo así). Uno de los efectos secundarios fue una gran cantidad de comentarios distribuidos en todo el código que explica las abreviaturas (no estándar). Y, por supuesto, si los nombres fueron cambiados por alguna razón ...

Ahora prefiero llamar a las cosas lo que realmente son, con buenos nombres descriptivos. incluyendo abreviaturas estándar solamente. No es necesario incluir comentarios inútiles, y el código es mucho más legible y comprensible.

A medida que programamos, todos desarrollamos prácticas y patrones que utilizamos y en los que confiamos. Sin embargo, con el tiempo, a medida que cambia nuestro entendimiento, madurez e incluso el uso de la tecnología, nos damos cuenta de que algunas prácticas que alguna vez pensamos que eran excelentes no son (o ya no se aplican).

Un ejemplo de una práctica que una vez utilicé bastante a menudo, pero que en los últimos años ha cambiado, es el uso del patrón de objetos de Singleton .

A través de mi propia experiencia y largos debates con colegas, me he dado cuenta de que los singletons no siempre son deseables : pueden dificultar las pruebas (al inhibir técnicas como el burlarse) y pueden crear un acoplamiento no deseado entre las partes de un sistema. En cambio, ahora utilizo fábricas de objetos (generalmente con un contenedor IoC) que ocultan la naturaleza y la existencia de los singleton de partes del sistema que no les importa, o necesitan saber. En cambio, dependen de una fábrica (o localizador de servicios) para adquirir acceso a tales objetos.

Mis preguntas a la comunidad, en un espíritu de superación personal, son:

  • ¿Qué patrones de programación o prácticas ha reconsiderado recientemente y ahora intenta evitar?
  • ¿Con qué decidiste reemplazarlos?

Al igual que usted, también he adoptado los patrones de IoC para reducir el acoplamiento entre varios componentes de mis aplicaciones. Hace que el mantenimiento y el intercambio de piezas sean mucho más simples, siempre que pueda mantener cada componente lo más independiente posible. También estoy utilizando más frameworks relacionales de objetos como NHibernate para simplificar las tareas de administración de bases de datos.

En pocas palabras, estoy usando marcos "mini" para ayudar a crear software de manera más rápida y eficiente. Estos mini-frameworks ahorran mucho tiempo, y si se hace bien, puede hacer que una aplicación sea muy sencilla de mantener en el futuro. ¡Plug ''n Play para ganar!


Bibliotecas de utilidad. Solía ​​llevar una asamblea con una variedad de métodos y clases de ayudantes con la teoría de que podría usarlos en algún otro lugar algún día.

En realidad, acabo de crear un gran espacio de nombres con muchos bits de funcionalidad mal organizados.

Ahora, simplemente los dejo en el proyecto en el que los creé. Con toda probabilidad no los voy a necesitar, y si lo hago, siempre puedo refactorizarlos para que sean reutilizables más adelante. A veces los marcaré con un // TODO para una posible extracción en un ensamblado común.


Comentando el código. Solía ​​pensar que el código era precioso y que no puedes simplemente borrar esas gemas hermosas que has creado. Ahora borro cualquier código comentado que encuentre a menos que haya un TODO o NOTE adjunto porque es demasiado peligroso dejarlo allí. A saber, he encontrado viejas clases con enormes porciones comentadas y realmente me confundió por qué Estuve allí: ¿recientemente fueron comentados? ¿Es esto un cambio de entorno de desarrollo? ¿Por qué hace este bloque sin relación?

En serio, considere no comentar el código y simplemente eliminarlo en su lugar. Si lo necesita, todavía está en control de fuente. YAGNI sin embargo.


Cuando tuve que hacer una refacturación, pensé que era más rápido y más limpio comenzar de inmediato y poner en práctica el nuevo diseño, arreglando las conexiones hasta que funcionen. Entonces me di cuenta de que es mejor hacer una serie de refactorizaciones pequeñas para progresar lenta pero confiablemente hacia el nuevo diseño.


Dejé de seguir el método de diseño recomendado por la universidad antes de la implementación. Trabajar en un sistema caótico y complejo me ha obligado a cambiar de actitud.

Por supuesto, sigo investigando el código, especialmente cuando estoy a punto de tocar un código que nunca había tocado, pero normalmente trato de enfocarme en implementaciones tan pequeñas como sea posible para que algo funcione primero. Este es el objetivo principal. Luego, refine gradualmente la lógica y deje que el diseño simplemente aparezca por sí mismo. La programación es un proceso iterativo y funciona muy bien con un enfoque ágil y con muchas refactorizaciones.

El código no se verá en todo lo que primero pensaste que sería. Sucede cada vez :)


Diseñando más de lo que codifiqué. Después de un tiempo, se convierte en parálisis de análisis.


El desarrollo de cascadas en general, y en particular, la práctica de escribir especificaciones funcionales y de diseño completas y completas que de alguna manera se espera que sean canónicas y luego esperar que una implementación de las mismas sea correcta y aceptable. Lo he visto reemplazado por Scrum, y me libré de él, digo. El simple hecho es que la naturaleza cambiante de las necesidades y deseos de los clientes hace que cualquier especificación fija sea efectivamente inútil; la única forma de abordar el problema correctamente es con un enfoque iterativo. No es que Scrum sea una bala de plata, por supuesto; Lo he visto mal y abusado muchas, muchas veces. Pero es mejor que la cascada.


El uso de Caffine. Una vez me mantuvo despierto y en un estado de programación gloriosa, donde el código voló de mis dedos con fluidez febril. Ahora no hace nada, y si no lo tengo me da dolor de cabeza.


El uso de un DataSet para realizar la lógica de negocios. Esto vincula el código demasiado a la base de datos, también el DataSet generalmente se crea a partir de SQL, lo que hace que las cosas sean aún más frágiles. Si el SQL o la base de datos cambian, tiende a llegar a todo lo que toca el conjunto de datos.

Realización de cualquier lógica comercial dentro de un constructor de objetos. Con la herencia y la capacidad de crear constructores sobrecargados tienden a dificultar el mantenimiento.


El uso excesivo / abuso de directivas #region. Es solo una pequeña cosa, pero en C #, antes usaba las directivas #region para organizar mis clases. Por ejemplo, agruparía todas las propiedades de clase juntas en una región.

Ahora miro hacia atrás al código anterior y, en general, me molestan. No creo que realmente aclare las cosas la mayor parte del tiempo, y a veces simplemente lo hacen más lento. Así que ahora he cambiado de idea y creo que las clases bien diseñadas son en su mayoría más limpias sin directivas de la región.


En C #, usando _notation para miembros privados. Ahora pienso que es feo.

Luego cambié a this.notation para miembros privados, pero descubrí que era inconsistente al usarlo, así que también lo dejé caer.


Envolver los componentes de acceso a datos existentes, como Enterprise Library, con una capa personalizada de métodos de ayuda.

  • No hace la vida de nadie más fácil
  • Es más código que puede tener errores en él
  • Mucha gente sabe cómo usar los componentes de acceso a datos EntLib. Nadie más que el equipo local sabe cómo usar la solución de acceso a datos internos

Escuché por primera vez acerca de la programación orientada a objetos mientras leía Smalltalk en 1984, pero no tuve acceso a un lenguaje oo hasta que usé el compilador cfront C ++ en 1992. Finalmente llegué a usar Smalltalk en 1995. Había anticipado ansiosamente oo tecnología, y compró en la idea de que salvaría el desarrollo de software.

Ahora, simplemente veo oo como una técnica que tiene algunas ventajas, pero es solo una herramienta en la caja de herramientas. Hago la mayor parte de mi trabajo en Python, y a menudo escribo funciones independientes que no son miembros de la clase, y a menudo colecciono grupos de datos en tuplas o listas donde en el pasado habría creado una clase. Sigo creando clases cuando la estructura de datos es complicada, o necesito un comportamiento asociado con los datos, pero tiendo a resistirme.

De hecho, estoy interesado en hacer algún trabajo en Clojure cuando tengo el tiempo, lo que no me proporciona facilidades, aunque puedo usar objetos Java si entiendo correctamente. No estoy listo para decir algo como oo está muerto, pero personalmente no soy el seguidor que solía ser.


Esto es algo pequeño, pero: preocuparse por dónde van las llaves (¿en la misma línea o en la siguiente línea?), Sugiere longitudes máximas de línea de código, convenciones de nomenclatura para variables y otros elementos de estilo. Descubrí que a todos parece importarles más esto que a mí, así que sigo con la corriente de la persona con la que estoy trabajando hoy en día.

Editar: La excepción a este ser, por supuesto, cuando soy el que más se preocupa (o es el que está en posición de establecer el estilo para un grupo). En ese caso, ¡hago lo que quiero!

(Tenga en cuenta que esto no es lo mismo que no tener un estilo consistente. Creo que un estilo consistente en una base de código es muy importante para la legibilidad).


Inicializando todos los miembros de la clase.

Solía ​​inicializar explícitamente a cada miembro de la clase con algo, generalmente NULL. Me he dado cuenta de esto:

  • normalmente significa que cada variable se inicializa dos veces antes de leerse
  • es tonto porque en la mayoría de los lenguajes inicializa automáticamente las variables a NULL.
  • en realidad impone un ligero golpe de rendimiento en la mayoría de los idiomas
  • puede hinchar código en proyectos más grandes

La arquitectura "perfecta"

Vine con LA arquitectura hace un par de años. Me presioné técnicamente tanto como pude, así que había capas 100% débilmente acopladas, uso extensivo de delegados y objetos livianos. Fue un paraíso técnico.

Y fue una mierda. La pureza técnica de la arquitectura solo disminuyó la velocidad de mi equipo de desarrollo, apuntando a la perfección sobre los resultados y casi logré la falla completa.

Ahora tenemos una arquitectura mucho más simple, menos técnicamente perfecta y nuestra tasa de entrega se ha disparado.


Notación húngara (formas y sistemas). Solía ​​prefijar todo. strSomeString o txtFoo. Ahora uso someString y textBoxFoo. Es mucho más legible y más fácil para alguien nuevo que viene y recoge. Como una ventaja adicional, es trivial mantenerlo constante: camelCase el control y añada un nombre útil / descriptivo. Las formas húngaras tienen el inconveniente de no ser siempre consistentes y los sistemas húngaros en realidad no te ganan mucho. Chunking de todas sus variables juntas no es realmente tan útil, especialmente con IDE modernos.


Pensé que tenía sentido aplicar patrones de diseño cada vez que los reconocía.

Poco sabía que en realidad estaba copiando estilos de lenguajes de programación extranjeros, mientras que el lenguaje con el que estaba trabajando permitía soluciones mucho más elegantes o más fáciles.

El uso de múltiples (muy) diferentes idiomas me abrió los ojos y me hizo darme cuenta de que no tengo que aplicar mal las soluciones de otras personas a problemas que no son míos. Ahora me estremezco cuando veo el patrón de fábrica aplicado en un idioma como Ruby.


Prueba obsesiva Solía ​​ser un partidario rabioso del desarrollo de prueba primero. Para algunos proyectos tiene mucho sentido, pero me he dado cuenta de que no solo es inviable, sino que es perjudicial para muchos proyectos el adherirse servilmente a una doctrina de pruebas de unidad de escritura para cada pieza de funcionalidad.

De verdad, adhiriéndose servilmente a cualquier cosa puede ser perjudicial.


Puntos de retorno únicos.

Una vez preferí un punto de retorno único para cada método, porque con eso podía asegurarme de que no se pasaba por alto ninguna limpieza que la rutina necesitara.

Desde entonces, pasé a rutinas mucho más pequeñas, por lo que la probabilidad de pasar por alto la limpieza se reduce y, de hecho, la necesidad de limpieza se reduce, y descubro que los retornos iniciales reducen la complejidad aparente (el nivel de anidación) del código. Los artefactos del único punto de retorno -manteniendo variables de "resultado", manteniendo variables de bandera, cláusulas condicionales para situaciones que ya no están hechas- hacen que el código parezca mucho más complejo de lo que realmente es, hacen que sea más difícil de leer y mantener. Las salidas tempranas y los métodos más pequeños son el camino a seguir.


Que cualquier cosa que valga la pena solo estaba codificada en un idioma en particular. En mi caso, creía que C era el mejor lenguaje de todos los tiempos y nunca tuve ningún motivo para codificar nada en ningún otro idioma ... nunca.

Desde entonces, he llegado a apreciar muchos idiomas diferentes y los beneficios / funcionalidades que ofrecen. Si quiero codificar algo pequeño, rápido, usaría Python. Si quiero trabajar en un proyecto grande, codificaría en C ++ o C #. Si quiero desarrollar un tumor cerebral, codificaría en Perl .


Quizás lo más importante que ha cambiado en mis prácticas de codificación, así como en otras, es la aceptación de clases y bibliotecas externas descargadas de Internet como base para los comportamientos y la funcionalidad en las aplicaciones. En la escuela en el momento en que asistía a la universidad, nos animaban a descubrir cómo mejorar las cosas a través de nuestro propio código y confiar en el idioma para resolver nuestros problemas. Con los avances en todos los aspectos de la interfaz de usuario y el consumo de servicio / datos, esto ya no es una noción realista.

Hay ciertas cosas que nunca cambiarán en un idioma, y ​​tener una biblioteca que envuelva este código en una transacción más simple y en menos líneas de código que deba escribir es una bendición. Conectarse a una base de datos siempre será el mismo. La selección de un elemento dentro del DOM no cambiará. Enviar un correo electrónico a través de un script del lado del servidor nunca cambiará. Tener que escribir esto una y otra vez desperdicia tiempo que podría estar usando para mejorar mi lógica central en la aplicación.


Solía ​​ser grande en el diseño por contrato. Esto significaba una gran cantidad de comprobación de errores al comienzo de todas mis funciones. Los contratos siguen siendo importantes, desde la perspectiva de la separación de preocupaciones, pero en lugar de tratar de aplicar lo que mi código no debería hacer, trato de usar pruebas unitarias para verificar lo que hace.


Tal vez la "práctica de programación" más importante sobre la que he cambiado de opinión ahora, es la idea de que mi código es mejor que el de los demás. Esto es común para programadores (especialmente novatos).


Usaría static''s en muchos métodos / clases ya que era más conciso. Cuando comencé a escribir pruebas, esa práctica cambió muy rápidamente.


Excepciones controladas

Una idea increíble en papel: define claramente el contrato, no hay margen de error ni se olvida de verificar alguna condición de excepción. Me vendieron cuando escuché por primera vez.

Por supuesto, resultó ser un desastre en la práctica. Hasta el punto de tener bibliotecas hoy como Spring JDBC, que ha ocultado el legado de las excepciones comprobadas como una de sus características principales.


Nunca chocando.

Parece una buena idea, ¿no? A los usuarios no les gustan los programas que fallan, así que vamos a escribir programas que no se cuelguen, y los usuarios deberían agradar el programa, ¿no? Así es como empecé.

Hoy en día, estoy más inclinado a pensar que si no funciona, no debería pretender que está funcionando. Fallar tan pronto como sea posible, con un buen mensaje de error. Si no lo hace, su programa se bloqueará aún más duro unas pocas instrucciones más tarde, pero con algún error nulo de puntero nulo que le llevará una hora para la depuración.

Mi patrón favorito de "no chocar" es este:

public User readUserFromDb(int id){ User u = null; try { ResultSet rs = connection.execute("SELECT * FROM user WHERE id = " + id); if (rs.moveNext()){ u = new User(); u.setFirstName(rs.get("fname")); u.setSurname(rs.get("sname")); // etc } } catch (Exception e) { log.info(e); } if (u == null){ u = new User(); u.setFirstName("error communicating with database"); u.setSurname("error communicating with database"); // etc } u.setId(id); return u; }

Ahora, en lugar de pedirles a los usuarios que copien / peguen el mensaje de error y se lo envíen, deberán buscar en los registros para encontrar la entrada del registro. (Y dado que ingresaron una identificación de usuario no válida, no habrá entrada de registro).



//Coming out of university, we were taught to ensure we always had an abundance //of commenting around our code. But applying that to the real world, made it //clear that over-commenting not only has the potential to confuse/complicate //things but can make the code hard to follow. Now I spend more time on //improving the simplicity and readability of the code and inserting fewer yet //relevant comments, instead of spending that time writing overly-descriptive //commentaries all throughout the code.



  • Intentando codificar las cosas perfectamente en el primer intento.
  • Tratando de crear el modelo OO perfecto antes de codificar.
  • Diseñando todo para la flexibilidad y las mejoras futuras.

En una palabra overengineering .