¿Qué es un código hermoso en C ++ y por qué a la mayoría de los programadores les importa tanto? [cerrado]


8

Como la mayoría de los proyectos usan una API de C ++, se ocupan de las restricciones de la API y las restricciones del proyecto en sí.

Soy un principiante en programación, no me gusta usar OOP en absoluto porque nadie logró explicarme claramente POR QUÉ es tan importante restringirse con un alcance privado para evitar que otros programadores rompan la consistencia de la organización de datos de algún tipo.

Todavía puedo estar bien con OOP, ya que todavía permite hacer cosas geniales como Qt y Ogre3D, pero esas son solo API, no aplicaciones, y esos códigos deben ser perfectos para que nadie pueda criticar el trabajo.

No entiendo por qué la mayoría de los programadores, ya que crean aplicaciones y no API, quieren hacer un código perfecto como si diseñaran una pieza de código genial, y pierden tiempo en esto.


19
Déle un par de años para tener que volver a su antiguo código no perfecto e intentar agregarle funciones, corregir errores, etc. tiempo alrededor.
R0MANARMY

Ver (esta pregunta) [ programmers.stackexchange.com/q/65216/8823] . No porque usted no es un programador, sino porque hay un poco de buena descripción de qué código bello es bueno
Austin Hyde

2
¿Es esta pregunta sobre código hermoso, OOP o ámbito privado? Realmente no puedo decirlo.
Sean McMillan

1
Wow ... no sé por dónde empezar. Espero nunca tener que ver o trabajar con su código ...
Rig

1
Un buen código y una buena API tienen muchas cosas en común. Un buen código OOP debe tener una interfaz que se vea exactamente como una API bien diseñada.
rwong

Respuestas:


12

¿Alguna vez has escuchado el dicho "Ningún hombre es una isla" ?

Para la mayoría de los programadores esto es cierto. Casi nadie escribe código que sea "solo una aplicación". En muchas aplicaciones no triviales, un programador escribe la interfaz de usuario que un diseñador debe modificar fácilmente. También debe permitir un enlace claro de datos a la lógica de negocios (Controlador, ViewModel o como quiera llamarlo). Otro programador escribe ese controlador, que a menudo puede ser extremadamente complejo, pero debe ser lo suficientemente simple como para ser consumido fácilmente por el programador front-end. Ese codificador de lógica de negocios está consumiendo código de quien escribió la capa de datos (Modelo, Repositorio, etc.). No tiene que usar OOP, sin embargo, en lo que OOP es bastante bueno es que le permite encapsular la lógica detrás de una interfaz para que otras personas con las que trabaje puedan usar su código sin romperlo (¡suponiendo que haya probado esa interfaz!). La abstracción no es la bala de plata,

Entonces podría estar diciendo ahora "En serio, soy una excepción y nadie verá mi código ni trabajará con él en absoluto". Es justo, pero cuando necesite corregir un error en esa aplicación dentro de unos meses, o si desea agregar un par de características, probablemente verá que la persona que escribió ese código en ese momento y la persona que lo está modificando ahora están Dos personas totalmente diferentes. A menudo asumimos que recordaremos cosas, lo cual es el núcleo de por qué escribimos código descuidado, pero la verdad es que usted dentro de seis meses no recordará los hacks que ha puesto en su aplicación ahora. Tu futuro yo tendrá suficiente con lo que lidiar, así que ¿por qué no darle un descanso?


43

Cualquier tonto puede escribir código que una computadora pueda entender. Los buenos programadores escriben código que los humanos pueden entender. ~ Martin Fowler

En pocas palabras, es por eso que quieres preocuparte por un código hermoso.

No escribes código para la computadora. La computadora solo entiende el código binario de todos modos (que se produce a partir de su código fuente a través de compiladores e intérpretes). No le importa la belleza o la claridad, ni siquiera si su código hace lo que se supone que debe hacer.

Escribes código para tus compañeros programadores. Y hacen lo mismo por ti. Si no puede entender un código escrito por otra persona, ¿cuál cree que es su oportunidad de encontrar y corregir un error o agregar una nueva funcionalidad?


1
Añadiría que es especialmente fácil escribir código totalmente críptico en C ++, ¡y es por eso que esto es aún más importante en este lenguaje!
deadalnix

1
Bueno, realmente no estoy de acuerdo con esta cita, el código reutilizable es un buen código, es cierto, pero los lenguajes están hechos para que los programadores puedan trabajar más rápido, no necesariamente para ser leídos por otros programadores. Es doloroso leer el código, así que ya sea poner comentarios o cambiar el diseño para hacerlo más comprensible para un humano, sí, pero un buen diseño no siempre viene con "fácil de entender". Un programa puede ejecutar tareas simples y complicadas, y los lenguajes de programación pueden limitar qué tan bien puede diseñar aplicaciones sofisticadas. El lenguaje de programación hace las cosas más fáciles, no más elegantes.
jokoon

3

Lo que otros han dicho como si nunca supieras si es posible que necesites tu código nuevamente en el futuro es correcto, por supuesto.

Pero para mí hay un punto importante, por qué siempre trato de escribir un código hermoso:

Es entrenamiento para mejorar.

Si aprendo algo nuevo sobre un lenguaje que uso o sobre algunos conceptos generales de programación, inmediatamente trato de usarlo, trato de hacerlo parte de mi flujo de trabajo diario y cadena de herramientas mentales.

Si solo lee sobre algo como OOP, lo olvidará en pocas semanas. Y nunca recibirá la capacitación sobre cómo aplicarlo adecuadamente a grandes problemas, siempre y cuando no se enseñe a sí mismo al aplicarlo a pequeños problemas.

Ejemplo:

¿Por qué es importante restringirse con un ámbito privado?

En proyectos pequeños no lo es. Algunos lenguajes (por ejemplo, Ruby) incluso desalientan este tipo de encapsulación hasta cierto punto. Pero hay usos para ello. Muchos.

Y usarlo viene con ciertos problemas y muchos detalles que tienes que aprender. Usarlo en pequeños proyectos te enseñará esto. Verá algunos mensajes de error de su compilador que son nuevos para usted y en un proyecto pequeño podrá encontrar la fuente del problema más fácilmente.

Aprenderá sobre espacios de nombres en C ++. No hay tanta necesidad de ellos en pequeños proyectos. Lo mismo ocurre con la estructura genaral de los archivos de encabezado e incluye. Puede aprender todo esto desde el principio en la protección de una pequeña base de código.



1
  1. Lo que R0MANARMY dijo en su comentario. El código limpio y "hermoso" hace que sea más fácil de leer, comprender, mantener, cambiar y arreglar en el futuro, no solo para usted, sino también para los demás que vienen después de usted.

  2. Algunas personas, cuando hacen algo, intentan hacerlo lo mejor posible, de la mejor manera posible, por lo que es "perfecto", o en este caso, "hermoso". Descubrí que hay una gran superposición entre este conjunto de personas y desarrolladores (¡incluido yo mismo!).

Sin embargo, tenga en cuenta que "bello", "limpio" o "elegante" son términos muy subjetivos que significan cosas diferentes para diferentes personas. Sin embargo, por lo que he visto, el código que es ampliamente considerado como hermoso, limpio y / o elegante,

  • Es fácil de leer y entender.
  • No tiene, o tiene poco, código innecesario por ahí
  • Es fácilmente extensible y / o modular.
  • Está bien documentado
  • Sigue cualquier estándar para idiomas / tecnologías relacionadas
  • Y no hace nada inesperado (por ejemplo, efectos secundarios en un método de acceso)

1

Estoy de acuerdo con la mantenibilidad. Solo intente hacer un proyecto relativamente grande, y verá todo el desorden que ata sus manos a la corrección de errores, agregando nuevas características, etc. Pero para hablar de belleza:

El código hermoso es la calidad deseada del producto porque (al menos, C ++) la programación es un ART.


1
Aunque con la introducción de lambdas ahora involucra menos tiburones en formaldahído
Martin Beckett

1

[...] nadie logró explicarme claramente POR QUÉ es tan importante restringirse con un ámbito privado para evitar que otros programadores rompan algún tipo de consistencia de la organización de datos.

En un equipo lo suficientemente pequeño con una base de código lo suficientemente pequeña que está realmente bien coordinada con buenos estándares (podría ser una sola persona), a menudo puede encontrar un software confiable que simplemente deja todos los datos a la vista para que cualquiera pueda tocar todos los campos de datos de una structexposición abierta y con la structdefinición abierta para cualquier persona que incluya ese encabezado para acceder. La ley de Murphy no siempre se aplica en esos casos.

Pero he trabajado en el escenario opuesto de una enorme base de código con muchos millones de LOC que datan de los años 80 con un gran equipo de desarrolladores de todo el mundo donde solo nos reuníamos cara a cara cada pocos meses, coordinados de forma flexible, a veces apenas habla el mismo idioma, sin estándares de codificación, excepto el SDK que la gente a menudo no seguía de todos modos, sin pruebas de unidad / integración, usando SVN sin ramificación y a veces pasando 6 semanas sin registrar el código, solo para bombardearnos con errores, y No fue hasta entonces que realmente entendí el valor de ocultar información y mantener invariantes .

Me ocupé de errores en los que ni siquiera podía reproducir el problema de manera consistente en mi máquina, y a veces ninguno de nosotros podía hacerlo entre todo el equipo. Y cuando finalmente pude reproducir afortunadamente el problema informado por el usuario o algo que se parecía a él después de todo tipo de prueba y error (y la prueba y el error a menudo tomaron horas porque la ineficiencia de nuestro software se combinó con la ejecución de la depuración contra la producción del usuario final los datos a menudo tomaban más de 15 minutos solo para que los datos se cargaran), lo rastrearía a algo así como un structtipo de cadena que tenía un lenconjunto a un número negativo de basura, como una longitud de cadena de -921141282.

Eso nunca debería suceder, pero ¿quién lo hizo? Así que tuve que establecer puntos de interrupción de memoria y averiguarlo, y cuando finalmente lo hice, fue como una interacción en cascada de variables no inicializadas que se usan aritméticamente, que finalmente se sumaron a un lencampo de cadena que se estableció en un número de basura negativo, y ese código no había sido modificado en años. Voló por debajo del radar.

Y todo ese tiempo después de encontrar muchos errores como este, pensé para mí mismo, ¿cuánto más confiable sería nuestro software si solo se usara gettersy setters? Los captadores y establecedores son generalmente indicativos de los peores tipos de diseños de interfaz posibles, pero un establecedor podría al menos desencadenar una falla de aserción si alguien intenta establecer la longitud de una cadena en un valor negativo. Podríamos haber atrapado ese error añosantes en el momento preciso en que se introdujo en segundos, no en la culminación de horas de esfuerzo de investigación. Y eso es solo pensar egoístamente como desarrollador; no cubre todas las horas de dolor que podría haber salvado a los usuarios y al equipo de control de calidad también. Usted sabe que su sistema está en un lugar bastante malo cuando sueña con lo mejor que podría ser si usara setters y getters frente a los últimos 35 errores que pasó toda la noche arreglando.

Incluso tuvimos casos en los que structsse documentaron de manera tal que nadie más debería acceder a esos campos de datos, solo para encontrar lugares en el sistema que accedan a esos campos de datos.

Así que estos son los tipos de cosas que realmente solo puedes apreciar al máximo enfrentando el peor de los casos, pero a menudo lo harás a menos que tengas la suerte de pasar el resto de tu vida trabajando en bases de código más pequeñas con equipos bien coordinados y Fuertes estándares de codificación.

¿Qué es el código hermoso en C ++ [...]?

Esa es una dificil. Todavía estoy tratando de resolver eso. La mayor parte del código que considero hermoso que he escrito a lo largo de los años, o al menos confiable y relativamente intemporal y estable (no necesita / quiere cambios) fue escrito en C y recientemente en Lua. Todavía me cuesta escribir código C ++ que parece pasar la prueba del tiempo hasta el punto de no reflexionar sobre eso unos años más tarde y al menos desearía poder cambiarlo. Siento que se ha vuelto más fácil desde C ++ 11, pero necesito algunos años para descubrir qué tan bien mi código se las arregla para sobrevivir sin necesidad de cambios para asegurarlo. Para mí, la "belleza" definitiva es la "estabilidad", como en el código que no necesita y ni siquiera tienta a ningún cambio adicional, pero sigue siendo relevante y útil en los años venideros, ya que '


0

Bueno, definir interfaces limpias y útiles ("hermosa" es un calificador deficiente) se trata de asegurarse de que:

  1. El usuario comprende con un mínimo dolor cómo usar su objeto (o sistema de objetos) simplemente leyendo su interfaz.
  2. El usuario tendrá dificultades para usar el objeto / sistema de manera incorrecta: la interfaz dificulta hacer algo mal o señalar problemas temprano.
  3. La interfaz describe una abstracción útil.

Los puntos 1. y 2. requieren que piense mucho sobre el contrato que está haciendo con su usuario. Ese contrato, o protocolo, es la forma de comunicarle al usuario cómo puede usar su sistema. Por ejemplo, las funciones miembro de solo lectura (funciones miembro const) informan mucho sobre qué situaciones debería poder llamar a esa función. Del mismo modo, los atributos de cada función sumergen al usuario para recopilar y proporcionar la información mínima requerida para que el sistema funcione.

Todos los puntos juntos sugieren que sus interfaces solo deben mostrar servicios que sean útiles para el usuario. Primero, limitar el uso del sistema por parte del usuario solo para lo que se creó el sistema. En segundo lugar, evitando que manipule el estado interno de manera incorrecta. Por lo tanto, la forma más fácil en C ++ de lograr esto es poner a todos los miembros privados y declarar explícitamente qué servicios proporciona su sistema, utilizando funciones miembro o globales (en espacios de nombres). Otra forma es usar el idioma de PImpl.

Tercero, y lo más importante: su interfaz debe proporcionar una abstracción útil, lo que significa que el usuario no debería tener que entender la implementación. Cuando conduzco un automóvil o una lavadora, no quiero saber cómo está construido adentro (incluso si soy un geek tecnológico ...). Solo necesito usarlo y no tener que preocuparme por lo que hay dentro.

Es dificil.

Cualquier definición de protocolo, como el diseño de un lenguaje de programación o el diseño de una clase, no es tan obvio como puede haber pensado primero. Se requiere mucha experiencia para apreciar las sutilezas de diseñar interfaces.

Todo lo que no es revelador cuando se definen estructuras o clases que representan conceptos de muy bajo nivel. Cuanto más alto sea el hardware, más necesitará para tener interfaces limpias, claras y útiles.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.