¿Por qué es malo escribir algo en el lenguaje X como si estuviera escribiendo un programa en el lenguaje Y en términos de usar un paradigma de codificación compartido [cerrado]

25

Hace un tiempo, hice una pregunta en SO sobre algo escrito en C ++, pero en lugar de obtener una respuesta al problema en cuestión, los comentarios se volvieron locos en mi estilo de codificación, incluso cuando indiqué que era un código WIP y que tenía la intención de limpiarlo más tarde cuando tenía el caso base funcionando. (Obtuve tantos votos negativos que decidí sacar la pregunta, ya que mi representante en SO ya es casi abismal)

Me hizo preguntarme por qué la gente adopta una actitud tan dura como "eres un novato, vete a la mierda". Me acusaron de escribir C ++ como si fuera Java. Algo que no puedo entender y que todavía me desconcierta.

He estado programando en varios idiomas OOP durante varios años, aunque a intervalos. Elijo el idioma para usar en términos de sus bibliotecas disponibles y entornos de ejecución óptimos para el trabajo en cuestión. Adopto patrones de diseño en el código OOP y estoy bastante seguro de que mi uso de patrones es sólido y de que, sabiamente, puedo mantener el mío. Entiendo la caja de herramientas OOP, pero elijo usar las herramientas solo cuando creo que realmente es necesario, no solo usar un truco para mostrar mi ingenio de codificación. (Que sé que no son de primera categoría, pero creo que tampoco están en el nivel n00b).

Diseño mi código antes de escribir una sola línea. Para definir las pruebas, enumero los objetivos de una clase determinada y los criterios de prueba a los que debe cumplir. Debido a que es más fácil para mí crear diagramas de secuencia y luego escribir código, elegí escribir mis pruebas después de que la interfaz se hizo evidente.

Debo admitir que en el código que publiqué en la pregunta, todavía estaba usando punteros, en lugar de usar punteros inteligentes. Yo uso RAII siempre que puedo. Sé que una RAII adecuada significa protección contra los puntos nulos, pero trabajo de forma incremental. Era un trabajo en progreso y tenía la intención de limpiarlo más tarde. Esta forma de trabajar fue condenada enérgicamente.

En mi opinión, debería tener un ejemplo de trabajo primero para poder ver si el caso base es una forma de pensar viable. También pienso que limpiar el código es algo típico de la fase de refactorización ágil, después de que se haya probado el caso base. Debo admitir que, aunque lentamente estoy obteniendo el estándar Cxx, prefiero usar lo que entiendo, en lugar de arriesgarme a usar conceptos que todavía tengo que dominar en el código de producción. Intento cosas nuevas de vez en cuando, pero generalmente en proyectos de juego que tengo a un lado, solo para ese propósito.

[editar] Me gustaría aclarar que la sugerencia de mosquito [1] no apareció en la búsqueda que hice antes de comenzar a hacer mi pregunta. Sin embargo, aunque su sugerencia cubre un aspecto de la pregunta, la pregunta a la que se vinculó no responde al meollo de mi pregunta, solo parte de ella. Mi pregunta es más sobre la respuesta que obtuve a mi estilo de codificación y los aspectos profesionales de manejar diferentes estilos de codificación y niveles (aparentes) de habilidad. Con mi pregunta anterior sobre SO y su respuesta como un caso puntual. [/editar]

La pregunta entonces es: ¿por qué burlarse de alguien que no usa su estilo de codificación?

Los asuntos / subdivisiones disponibles para mí son:

  • ¿Por qué sería una mala práctica de programación usar más código propenso a errores en situaciones de prototipo, si la refactorización lo hace más robusto después?
  • ¿Cómo podría un programa escrito en C ++ ser como si estuviera escrito en Java? ¿Qué lo convierte en un mal programa (considerando que indiqué la intención del estilo actual y el trabajo planificado para mejorar?)
  • ¿Cómo sería un mal profesional si decidiera usar una construcción que se utiliza en un cierto paradigma de programación (por ejemplo, OOP / DP)?

[1] Desarrolle rápido y con errores, luego corrija los errores o sea lento, ¿cuidado con cada línea de código?

En ningún
fuente
55
Tal vez sea mejor hacerle esta pregunta a la gente de The C ++ Lounge. Póngase su traje a prueba de llamas primero.
Robert Harvey
48
La gente de C ++ es una raza inusual entre los programadores. Su kit de herramientas de Java es una caja de herramientas sensata y bien entendida con herramientas familiares en un estuche de cuero acolchado que funcionará en cualquier taller de herramientas. C ++ es una plataforma de herramientas completa con una sierra de corte al hilo, un taladro eléctrico y algunas herramientas que nadie reconoce, todo lo cual la multitud de C ++ puede manejar como ninjas. Les angustia cuando alguien entra y vuelve a poner alguna herramienta en el estante en el lugar equivocado. Son la "medida dos veces, corta una vez" de los programadores.
Robert Harvey
13
Tal vez sea la misma reacción que tendría al código Java que se escribió como FORTRAN: todo el código en una sola clase, sin colecciones, solo matrices de tamaño fijo, con intvariables separadas para realizar un seguimiento de la longitud real.
Kevin Cline
14
Si escribe C ++ como Java, es probable que termine con demasiadas asignaciones de almacenamiento dinámico, lo que hará que su programa funcione peor de lo que podría. Los idiomas tienden a estar diseñados y optimizados para promover ciertos patrones, y si rompes esos patrones, las cosas tenderán a empeorar para ti.
Gort the Robot
55
Publicó el código en línea para obtener algún tipo de ayuda. Me doy cuenta de que no querías / esperabas todos los comentarios sobre tu estilo, pero ¿preferirías no recibir ayuda? Se toma lo bueno con lo malo. Los programadores tienen que buscar fallas en el código; Es lo que hacemos.
JeffO

Respuestas:

26

Sin ver el código en cuestión, hay algunas formas de escribir código Java en C ++, algunas peores que otras.

  1. En el extremo, está diseñando su fuente como Java: todo en un archivo, todo dentro de la definición de clase, etc.
    class HelloWorldApp {
    public:
        void main() {
            cout << "Hello World!" << endl;
        }
    };
    Así es como se presentaría la fuente Java. Es técnicamente legal en C ++, pero poner todo en el archivo de encabezado y todo en línea (definiéndolo en la declaración de clase) es un estilo terrible y matará su rendimiento de compilación. No lo hagas
  2. Excesivamente OO: para simplificar demasiado, en Java, es el Reino de los sustantivos , donde todo es un objeto. Un código C ++ bueno (es decir, idiomático) es más probable que use funciones libres, plantillas, etc., en lugar de tratar de meter todo en un objeto.
  3. Sin RAII: ya mencionó esto, utilizando punteros y limpieza manual en lugar de punteros inteligentes. C ++ le brinda herramientas como RAII y punteros inteligentes, por lo que un código C ++ bueno (es decir, idiomático) utiliza esas herramientas.
  4. Sin C ++ avanzado: los conceptos básicos de Java y C ++ son lo suficientemente similares, pero una vez que ingresa a características más avanzadas (plantillas, biblioteca de algoritmos de C ++, etc.), comienzan a divergir.

Excepto por el n. ° 1, ninguno de estos hace que un programa de C ++ sea un mal programa, pero tampoco es el tipo de código en el que prefiero trabajar como programador de C ++. (Tampoco me gustaría trabajar con Perl no idiomático o de estilo C, Python no idiomático, etc.) Un lenguaje tiene sus propias herramientas y modismos y filosofía, y un buen código utiliza esas herramientas y modismos en lugar de intentar usar el mínimo común denominador o tratando de reproducir el enfoque de otro idioma. Escribir código no idiomático en un idioma / dominio de problema en particular / lo que sea que no haga que alguien sea un mal programador, solo significa que tienen más que aprender sobre ese idioma / dominio de problema / lo que sea. Y no hay nada de malo en eso; Hay una lista muy larga de cosas sobre las que tengo más que aprender, y C ++ en particular tiene muchísimas cosas que aprender.

Con respecto a la cuestión particular de escribir código propenso a errores con la intención de limpiarlo más tarde, no es en blanco y negro:

  • Si algún código prototipo no puede manejar todas las excepciones posibles y todos los casos de esquina posibles, entonces eso es de esperarse. Haz que funcione, luego haz que funcione de manera robusta. No hay problema.
  • Si algún código prototipo está escrito en lo que es simplemente un mal estilo o un mal diseño (malo para el idioma dado y sus expresiones idiomáticas, un diseño fundamentalmente malo para el problema, etc.), a menos que lo esté escribiendo como un descarte prueba de concepto, no estás ganando nada.

Para usar punteros en bruto versus punteros inteligentes como ejemplo, si va a trabajar en C ++, usar RAII y punteros inteligentes son lo suficientemente fundamentales como para que sea más rápido escribir código de esa manera que volver y limpiarlo más tarde. Una vez más, no hacer esto no significa que alguien sea un mal programador, no profesional, etc., pero sí significa que hay más para aprender.

Josh Kelley
fuente
11
hay perl idiomático?
monstruo de trinquete
21
@Onno Cuando preguntas "¿Cómo martillo este tornillo en la pared sin que se doble?" todos te dirán que no uses un martillo.
Sjoerd
99
@Onno En C ++, los punteros y newse consideran los powertools. El almacenamiento automático es la herramienta manual.
Sjoerd
99
@Onno: Debes darte cuenta de que los cursos de programación de C ++ tienden a retrasarse en la adopción de modismos modernos y lo que se considera bueno C ++ también ha evolucionado enormemente desde que se inventó C ++.
Bart van Ingen Schenau
77
Debido a la historia de C ++, y la gran cantidad de programadores que aprendieron el idioma antes de que aparecieran muchas de las características más avanzadas del lenguaje, todavía hay muchos C ++ basura que todavía escriben personas que escriben como lo hicieron hace una década. La inquietud acerca de cosas como RAII se trata de hacer que todos usen los métodos modernos para que podamos dejar de ver las mismas fallas predecibles.
Gort the Robot
42

Cada lenguaje de programación tiene un conjunto de expresiones idiomáticas y mejores prácticas, que generalmente conducirán a un código elegante, correcto y eficaz. Aquí hay algunas peores prácticas que están perfectamente bien en algún otro idioma:

  • Gritaré si escribes for ($i = 0; $i < 42; $i++) { … }en Perl, pero no en PHP
    (en Perl, las variables deben declararse y dichos bucles deben iterar en un rango)
  • Lloraré si escribes new Foo()en C ++ sin una buena razón, pero no en Java
    (C ++ no tiene recolección de basura, por lo que se debe usar RAII. De lo contrario, los noobs perderán memoria)
  • Me estremeceré si declaras todas tus variables en la parte superior de tu función, excepto en C89, Pascal o JavaScript.
  • Haré facepalm si pones todas tus funciones en una clase en Python, pero no en Java
    (Python es un lenguaje multi-paradigmático que obliga a "OOP" y admite funciones en el nivel superior)
  • Lloraré si estás return nullen Scala, pero no en ningún lenguaje tipo C
    (porque Scala tiene un Optiontipo)
  • Me quejaré si escribe un algoritmo recursivo en Java, pero no en OCaml
    (porque la pila de Java se desborda rápidamente, mientras que OCaml tiene una optimización de llamada de cola)
  • ...

Es fácil usar un nuevo idioma como si fuera algo que sabes, y con suerte incluso funcionará. "Puedes escribir Fortran en cualquier idioma". Pero realmente no desea ignorar las características específicas que ofrece el lenguaje X, porque es muy probable que X ofrezca alguna ventaja sobre U.

Elijo el idioma para usar en términos de sus bibliotecas disponibles y entornos de ejecución óptimos para el trabajo en cuestión ”, pero si este idioma X es realmente mejor que el idioma U para el trabajo en cuestión también depende de qué tan familiarizado esté ese idioma, o cuánto tiempo llevará familiarizarse lo suficiente como para usarlo bien. No cedería una motosierra pesada solo porque corta la madera más rápido, cuando realmente quiere su vieja navaja porque encaja perfectamente en su mano. A menos que realmente quieras talar un árbol.

Pero su pregunta es más sobre un tema cultural : aprender todas las mejores prácticas lleva mucho tiempo, y los novatos hacen la mayoría de las preguntas, mientras que los gurús las responden. Pero lo que es obvio para un gurú no lo es para un novato, y los gurús a veces lo olvidan. Como novato, la solución es no dejar de hacer preguntas. Sin embargo, uno puede mostrar una apertura para aprender y aplicar las mejores prácticas, por ejemplo, tratando de limpiar su código tanto como sea posible antes de mostrarlo a otros. La mayoría de los idiomas tienen algunas prácticas recomendadas básicas que son fáciles de aprender, incluso cuando toda la curva de aprendizaje es realmente muy larga.

Un problema común es que las personas nuevas en programación ignoran cualquier sangría u otro formato, y luego se confunden porque su programa no funciona. Yo también estaría confundido, y el primer paso para comprender un programa es asegurarme de que esté perfectamente diseñado. Luego, errores simples como una cita de cierre olvidada o una coma faltante de repente se vuelven obvios. Confío en que ya practique un buen formato, y aquí es una metáfora de otras mejores prácticas: las mejores prácticas evitan errores, las mejores prácticas facilitan la búsqueda de errores, la aplicación de las mejores prácticas es antes de encontrar el problema .

Es demasiado barato decir "Lo arreglaré más tarde", cuando arreglarlo ahora hubiera resuelto su problema (también, esa legendaria "fase de limpieza" nunca puede llegar, por lo que la única opción responsable es hacerlo bien el primera vez). Por lo menos, tratar de hacer que su código sea lo mejor posible antes de pedir ayuda a otros hace que sea más fácil para ellos razonar sobre su código, por lo que es una buena decisión.

amon
fuente
Tienes razón en algunos de los puntos que haces, pero al final no creo que estés dando en el blanco. Estás asumiendo el logro del conocimiento antes de tener la experiencia que lo ganará.
Onno
44
@Onno Mis puntos principales (que responden a las preguntas que hizo) son que no puede trasladar los hábitos de un idioma y asumir que es una mejor práctica en otro, y que tratar de escribir un código limpio desde el principio es preferible a la limpieza Más tarde. Limpiar el código, lo mejor que pueda, es imprescindible antes de pedir ayuda a otros (consulte sscce.org para obtener consejos sobre buenos fragmentos de código). No es aceptable volcar el código de basura en SO con un "por favor solucione esto", especialmente si lo sabe mejor.
amon
2
Pero con respecto a la pregunta que estás insinuando: la respuesta de jm666 contiene un punto clave: el gurú piensa "¿por qué preguntarías por X si no quisieras convertirte en un X-gurú tú mismo?" . Una posible forma de desactivar eso es mencionar que todavía está al comienzo de la curva de aprendizaje y lo investigará más adelante, pero por ahora tiene esta pregunta más inmediata a mano. Sin embargo, ese es un problema de comunicación, no un problema de programación.
amon
66
Tanto C ++ como C # tienen optional<T>y Nullable<T>respectivamente. Además, prácticamente todo el mundo pierde memoria en C ++ sin RAII, novato o no.
DeadMG
Creo que declarar variables al comienzo de un bloque generalmente hace que su código sea más fácil de leer en la mayoría de los idiomas. De esta manera, sabrá exactamente dónde buscar cuando necesite ayuda para recordar qué tipos son todas sus variables y cuáles.
Disfrute el
12

No soy un desarrollador hardcore de C ++, pero ...

¿Por qué sería una mala práctica de programación usar más código propenso a errores en situaciones de prototipo, si la refactorización lo hace más robusto después?

Una cosa a tener en cuenta es que un error en C ++ generalmente significa "comportamiento indefinido". En un idioma seguro, lo peor que podría suceder es una excepción que finalice su programa de inmediato. En C ++, tienes suerte si obtienes un segfault. Es completamente posible que su programa siga haciendo algo sutilmente incorrecto. También podría comportarse correctamente durante un período de tiempo y manifestar errores mucho más tarde, o podría comportarse correctamente todo el tiempo pero eventualmente consumir toda su memoria.

En cualquier caso, solo se necesita un solo error para llevar la ejecución del programa completamente fuera de los rieles a un territorio desconocido. Es probable que para el desarrollador de C ++ a tiempo completo, el "caso base" signifique "ninguna posibilidad de comportamiento indefinido o pérdidas de memoria".

¿Cómo podría un programa escrito en C ++ ser como si estuviera escrito en Java? ¿Qué lo hace un mal programa?

No creo que haya una respuesta a esto que no sea en gran medida especulativa y obstinada. Sin embargo, si desea mi opinión, Java tiende a tener un par de antipatrones asociados, como el hecho de que todo tiene que ser un objeto. Donde en otros idiomas a los que pasa un puntero, funtor, o función, en Java que se suele encontrar toneladas de vacua y en términos muy útil ThingDoers, FooFactoriesy IFrobnicatorsque son sólo funciones en el encubrimiento.

Del mismo modo, donde en otros idiomas puede pasar una tupla simple o una estructura sin nombre, en Java para agrupar incluso solo 2 objetos en un contenedor de datos simple, debe predefinir una clase NamedThing de más de 30 líneas con setters, getters y Javadocs. La relativa falta de características de Java obliga a los programadores a hacer dobles volteos orientados a objetos para hacer cosas a veces. El código resultante rara vez es idiomático fuera de Java.

Luego está el hecho de que en C ++ necesita un gráfico de objetos muy simplificado para administrar la memoria manualmente; generalmente un objeto es propiedad de otro objeto exactamente. En Java, no es necesario seguir restricciones tan estrictas, ya que el recolector de basura garantiza que las cosas se limpien cuando no haya más referencias a ellas. Por lo tanto, definitivamente existe el riesgo de una administración de memoria incorrecta si solo translitera el código de Java a C ++.

Finalmente, podría ser solo el elitismo. No voy a fingir que constituyen la mayoría, pero definitivamente he visto un sentimiento de "No necesito un lenguaje que tome mi mano y me impida hacer cosas estúpidas" entre algunos desarrolladores de C ++. En su opinión, C ++ es un lenguaje "real" y si no puede manejar sus idiosincrasias no es un "programador real".

Doval
fuente
1
Gran parte de esto se alivia con Java 8 - Lambdas entra para salvar la mayor parte del día :-)
Martijn Verburg
@MartijnVerburg De acuerdo, un gran paso adelante. ¡Pero los problemas tecnológicos son fáciles de solucionar! Los viejos hábitos mueren mucho y los estigmas aún más. Heck, algunas personas irán tan lejos como para quejarse de que Java no necesita ninguna de estas "nuevas" características, y que está en camino de convertirse en el próximo C ++.
Doval
Sí Siempre muevo la cabeza en aquel - Java será deliberadamente siempre evolucionan más lentamente que otros idiomas, ya que es un caballo de batalla a largo plazo. Sin embargo, la JVM puede avanzar a pasos agigantados algo más rápido, que es lo que permite que cosas como Lambdas finalmente lleguen al lenguaje.
Martijn Verburg el
6

Ligeramente fuera de la respuesta del tema ...

No se preocupe, este es un "comportamiento" común en cualquier comunidad de expertos. Y sea honesto, si es bueno en cualquier idioma y se encontrará con un código que es "extraño", probablemente también lo criticará. (porque, quiero ENSEÑAR).

Estoy en el mundo de Perl, cuando veré algo como:

$imax=$#array;
$str=""
for($i=0; $i<$imax; $i++) {
    $str = "$str" . $array[$i];
}

en lugar de:

my $str = join '', @array;

seguro lo comentará - (leer: enseñar al autor) sobre la joinfunción.

De todos modos, demasiadas críticas son contraproducentes y uno de los mejores ejemplos es el siguiente: (tomado de: http://perl-begin.org/humour/#How_can_I_switch_off_the_T.V..3F )

(Este bit se publicó de forma anónima en un pastebot el 23 de marzo de 2011. Se coloca aquí para la posteridad después de algunas modificaciones).

Pregunta: ¿cómo puedo encender mi televisor?

¿Qué quiere escuchar el OP?

Por ejemplo: ubique el botón de encendido / apagado del control remoto de su televisor y presiónelo. El botón generalmente es rojo y se encuentra en la línea superior del control remoto.

La respuesta del experto #perl: Primero, ¿qué quieres decir con "encender"? Defínalo primero. No pegue su TV, control remoto de TV y la sala de estar también.

... después de un nopaste:

Tu cuarto es feo. Y la televisión se ve terrible. Use Mr. Clean en la pantalla y primero limpie su sala de estar. Use tres trapeadores de limpieza en lugar de dos. Use HDMI y nunca use conectores euroconectores (?), A menos que realmente lo desee. Su control remoto de TV tiene botones ilegibles, limpie primero. Eres un principiante, así que lee:

http://experts.blog/how_to_design_a_future_3D_TV.html http://experts.blog/the_basics_of_tv_repairing.html http://experts.blog/viruses_in_living_room_short_essay.html http://experts.blog/global_chip_replacement_guide.html

Invitado del IRC: Pero no quiero ser un experto en televisión.

Respuesta: ¿Por qué quieres encender el televisor entonces?

jm666
fuente
1
Esta respuesta no está fuera de tema. Explica exactamente por qué alguien criticaría el uso no convencional de un lenguaje, y por qué ocasionalmente esa crítica automática puede llegar demasiado lejos. Me gusta.
trichoplax
1

¿Por qué sería una mala práctica de programación usar más código propenso a errores en situaciones de prototipo, si la refactorización lo hace más robusto después?

Al escribir rápido y sucio con la mente de arreglarlo más tarde, existe el peligro de olvidar algo que necesita arreglar.

¿Cómo podría un programa escrito en C ++ ser como si estuviera escrito en Java? ¿Qué lo convierte en un mal programa (considerando que indiqué la intención del estilo actual y el trabajo planificado para mejorar?)

En java no tienes que pensar en quién posee un determinado objeto, solo pasas la referencia y te olvidas de que no es nada. Sin embargo, en C ++ debe haber una definición clara de quién posee el objeto y quién es responsable de limpiarlo.

¿Cómo sería un mal profesional si decidiera usar una construcción que se utiliza en un cierto paradigma de programación (por ejemplo, OOP / DP)

No lo harías; C ++ es un lenguaje multi-paradigmático, soporta OOP bastante bien pero también puede hacer muchas otras cosas. Sin embargo, la mayor parte se reduce al uso de la herramienta correcta para el trabajo en lugar de sacar el martillo cada vez que necesita clavar una punta puntiaguda en un poco de madera.

La razón por la que recibió una mala respuesta es que la mayoría de las personas en SO tienden a juzgar las habilidades por lo idiomático que puede codificar en el idioma que está preguntando. Las personas familiarizadas con C ++ tienden a ponerse de rodillas cuando ven un código incorrecto que parece algo que los ha mordido en el pasado.

monstruo de trinquete
fuente
Puedo ver que olvidar mejorar podría ser un problema para algunos, pero mantengo una larga lista de tareas, y soy muy disciplinado al agregar etiquetas de tareas para este tipo de trabajos. (por eso me gusta VS, es bastante bueno en la gestión del trabajo) Es lo mismo para la documentación. No escribo una línea de código antes de escribir la documentación correspondiente. En cuanto a la pregunta de propiedad, debido a los diagramas de secuencia, creo que tengo una buena idea de quién tiene enlaces con quién.
Onno
1
@Onno: Francamente, nadie sabe ni le importa lo bueno que eres personalmente para hacer un seguimiento de esas cosas. La gran mayoría de las personas que escriben C ++ que se parece a Java o C, ni siquiera son tan meticulosos. Es mucho mejor para ellos aprender a hacer las cosas bien la primera vez que escribirse una nota para volver y arreglarla más tarde, porque la experiencia muestra que prácticamente nunca lo hacen.
cHao