Ir zen



Al evaluar mi trabajo, recientemente pensé mucho sobre cómo escribir un buen código. Dado que a nadie le interesa cómo escribir un código incorrecto , surge la pregunta: ¿cómo sabe si escribió un buen código en Go ? Si hay algún tipo de escala entre el bien y el mal, ¿cómo entender qué partes de la escala pertenecen al bien? ¿Cuáles son sus propiedades, atributos, características distintivas, patrones y modismos?

Ir idiomático


Estas consideraciones me llevaron al Go idiomático. Si llamamos a algo "idiomático", entonces este algo corresponde a un cierto estilo de algún tiempo. Si algo no es idiomático, entonces no corresponde al estilo dominante. Eso no está de moda.

Más importante aún, cuando decimos que el código de alguien no es idiomático, esto no explica la razón. ¿Por qué no idiomático? La respuesta la da el diccionario.

Idiom (n.): Una revolución del habla, utilizada como un todo, no sujeta a una mayor descomposición y generalmente no permite permutaciones dentro de sí misma.

Los modismos son sellos de significados comunes. Los libros no te enseñarán el Go idiomático; solo se sabe cuando te conviertes en parte de una comunidad.

Me preocupa el idiomático Go mantra porque a menudo es restrictivo. Ella dice: "no puedes sentarte con nosotros". ¿No es eso lo que queremos decir cuando criticamos el trabajo de otra persona como "no idiomático"? Lo hicieron mal. Esto no se ve bien. Esto no coincide con el estilo de la época.

Creo que el Go idiomático no es adecuado para enseñar a escribir un buen código, porque, en esencia, significa decirle a la gente que hicieron algo mal. Es mejor dar ese consejo que no aleje a una persona en el momento en que más quiera recibir este consejo.

Refranes


Vamos a distraernos de los problemas idiomáticos. ¿Qué otros artefactos culturales son inherentes a los programadores de Go? Dirígete a la hermosa página Go Proverbios . ¿Son estos dichos una herramienta de aprendizaje adecuada? ¿Les dicen a los principiantes cómo escribir un buen código Go?

No lo creo. No quiero menospreciar el trabajo del autor. Los dichos que compuso son meras observaciones, no definiciones de significados. El diccionario viene al rescate nuevamente:

Proverbio (n.): Una declaración breve que tiene un significado literal o figurado.

La misión de Go Proverbios es mostrar la profunda esencia de la arquitectura del lenguaje. ¿Pero será útil dar consejos como "La interfaz vacía no dice nada " a un principiante que vino de un idioma sin tipeo estructural?

En una comunidad en crecimiento, es importante reconocer que la cantidad de estudiantes de Go es mucho mayor que la cantidad de aquellos que dominan este idioma. Es decir, los dichos probablemente no sean la mejor manera de aprender en tal situación.

Valores de diseño


Dan Liu encontró una vieja presentación de Mark Lukowski sobre la cultura del diseño en el equipo de desarrollo de Windows NT-Windows 2000. Mencioné esto porque Lukowski describe la cultura como una forma común de evaluar arquitecturas y hacer compromisos.


La idea principal es tomar decisiones basadas en valores dentro de una arquitectura desconocida . El equipo de NT tenía estos valores: portabilidad, confiabilidad, seguridad y extensibilidad. En pocas palabras, los valores de diseño son una forma de resolver problemas.

Ir valores


¿Cuáles son los valores explícitos de Go? ¿Cuáles son los conceptos o filosofías clave que determinan cómo los programadores de Go interpretan el mundo? ¿Cómo se proclaman? ¿Cómo se les enseña? ¿Cómo se siguen? ¿Cómo cambian con el tiempo?

¿Cómo se convierte un programador Go para obtener los valores del diseño Go? ¿O cómo usted, un experimentado Go-pro, proclama sus valores a las generaciones futuras? Y para que entiendas, ¿este proceso de transferencia de conocimiento no es opcional? Sin la afluencia de nuevos participantes y nuevas ideas, nuestra comunidad se vuelve miope y se marchita.

Valores de otros idiomas


Para preparar el camino para lo que quiero decir, podemos prestar atención a otros idiomas, a sus valores de diseño.

Por ejemplo, en C ++ y Rust se cree que un programador no debe pagar por una función que no utiliza . Si el programa no utiliza alguna función del lenguaje que requiere muchos recursos, entonces no se puede obligar al programa a asumir el costo de mantener esta función. Este valor se proyecta desde el lenguaje en la biblioteca estándar y se utiliza como criterio para evaluar la arquitectura de todos los programas escritos en C ++.

Valor principal en Java, Ruby y Smalltalk: todo es un objeto. Este principio subyace en el diseño del programa en términos de transferencia de mensajes, ocultación de información y polimorfismo. Las arquitecturas que se ajustan a un paradigma procesal o funcional se consideran erróneas en estos lenguajes. O, como diría un programador de Go, no idiomático.

Volvamos a nuestra comunidad. ¿Qué valores de diseño profesan los programadores de Go? Las discusiones sobre este tema a menudo están fragmentadas, por lo que no es fácil formular un conjunto de significados. Es imperativo llegar a un acuerdo, pero la dificultad de alcanzarlo crece exponencialmente con el creciente número de participantes en la discusión. Pero, ¿y si alguien hiciera este trabajo difícil para nosotros?

Zen Python Go


Hace unas décadas, Tim Peters se sentó y escribió PEP-20 - El Zen de Python . Trató de documentar los valores de diseño a los que Guido Van Rossum se adhirió como el dictador Python generoso de por vida.

Miremos The Zen of Python y veamos si podemos aprender algo sobre los valores de diseño del diseñador Go.

Un buen paquete comienza con un buen nombre


Comencemos con el filoso:

Los espacios de nombres son una gran idea, ¡hagámoslos más grandes!

El zen de Python, récord 19.

Sin ambigüedades: los programadores de Python deberían usar espacios de nombres. Muchos espacios

En la terminología Go, un espacio de nombres es un paquete. No hay duda de que la agrupación favorece el diseño y la reutilización. Pero puede haber confusión sobre cómo hacer esto, especialmente si tiene muchos años de experiencia en programación en otro idioma.

En Go, cada paquete debe estar diseñado para algo. Y el nombre es la mejor manera de entender este destino. Reformulando los pensamientos de Peteres, cada paquete en Go debe estar diseñado para una cosa.

La idea no es nueva, ya he hablado de esto . Pero, ¿por qué debería usarse este enfoque, y no otro, en el que los paquetes se usan para las necesidades de una clasificación detallada? Se trata de los cambios.

— , .


El cambio es el nombre del juego en el que estamos participando. Nosotros, como programadores, gestionamos el cambio. Si lo hacemos bien, lo llamamos arquitectura. Y si es malo, entonces lo llamamos deuda técnica o código heredado.

Si escribe un programa que funciona muy bien una vez con un conjunto fijo de datos de entrada, entonces a nadie le interesará si tiene un buen código, porque solo el resultado de su trabajo es importante para los negocios.

Pero esto no sucede . Hay errores en los programas, los requisitos y el cambio de datos de entrada, y muy pocos programas se escriben con una sola expectativa de ejecución. Es decir, el programa va a cambiar con el tiempo. Tal vez esta tarea le sea asignada, pero lo más probable es que alguien más lo haga. Alguien debe acompañar este código.

¿Cómo facilitamos el cambio de programas? Añadir interfaces en todas partes? ¿Todo lo adecuado para crear trozos? ¿Desplegar dependencias estrechamente? Quizás, para algunos tipos de programas, estas técnicas son adecuadas, pero no para muchos. Sin embargo, para la mayoría de los programas, crear una arquitectura flexible es más que un diseño.

¿Y si en lugar de expandir los componentes los reemplazaremos? Si el componente no hace lo que se especifica en las instrucciones, entonces es hora de cambiarlo.

Un buen paquete comienza con la elección de un buen nombre. Considérelo una breve presentación que describe la función de un paquete con una sola palabra. Y cuando el nombre ya no cumpla con el requisito, busque un reemplazo.

La simplicidad importa


Simple es mejor que complejo.

El zen de Python, entrada 3.

PEP-20 afirma que lo simple es mejor que lo complejo, y estoy completamente de acuerdo. Hace unos años escribí:


La mayoría de los lenguajes de programación intentan ser simples al principio, pero luego deciden ser poderosos.

Según mis observaciones, al menos en ese momento, no podía recordar un idioma que sabía que no se consideraría tan simple. Como justificación y tentación, los autores de cada nuevo idioma declararon simplicidad. Pero descubrí que la simplicidad no era el valor central de muchos idiomas de la misma edad que Go (Ruby, Swift, Elm, Go, NodeJS, Python, Rust). Tal vez esto llegue a un punto doloroso, pero tal vez la razón es que ninguno de estos idiomas es simple. O sus autores no los consideraron simples. La simplicidad no se incluyó en la lista de valores centrales.

Puedes considerarme anticuado, pero ¿cuándo pasó de moda esta simplicidad? ¿Por qué la industria del software comercial olvida constantemente y con alegría esta verdad fundamental?

Hay dos formas de crear una arquitectura de software: hacerla tan simple que la falta de fallas sea obvia, y hacerla tan compleja que no tenga fallas obvias. El primer método es mucho más difícil.

Charles Hoar, The Emperor's Old Clothes, Turing Award Lecture, 1980

Simple no significa fácil, lo sabemos. A menudo se necesita más esfuerzo para garantizar la facilidad de uso, en lugar de la facilidad de creación.

La simplicidad es la clave de la fiabilidad.

Edsger Dijkstra, EWD498, 18 de junio de 1975

¿Por qué luchar por la simplicidad? ¿Por qué es importante que los programas Go sean simples? Simple significa crudo, significa legible y fácil de seguir. Simple no significa descuidado, significa confiable, inteligible y comprensible.

El núcleo de la programación es la gestión de la complejidad.

Brian Kernigan, Herramientas de software (1976)

Si Python sigue su mantra de simplicidad es una cuestión discutible. En Go, sin embargo, la simplicidad es un valor central. Creo que todos estaremos de acuerdo en que en Go el código simple es preferible al código inteligente.

Evitar estados a nivel de paquete


Explícito es mejor que implícito.

El zen de Python, entrada 2

Aquí, Peters, en mi opinión, más bien sueña que se adhiere a los hechos. En Python, mucho no es explícito: decoradores, métodos dunder, etc. Sin lugar a dudas, estas son herramientas poderosas, y existen por una razón. En la implementación de cada característica, especialmente compleja, alguien trabajó. Pero el uso activo de tales características hace que sea difícil evaluar el costo de la operación al leer el código.

Afortunadamente, los programadores de Go Go pueden hacer que el código sea explícito. Quizás, para usted, la manifestación puede ser sinónimo de burocracia y verbosidad, pero esta es una interpretación superficial. Será un error enfocarse solo en la sintaxis, cuidar la longitud de las líneas y la aplicación de los principios DRY a las expresiones. Me parece más importante proporcionar explícitamente en términos de conectividad y estados.

La conectividad es una medida de la dependencia de uno sobre el otro. Si uno está estrechamente relacionado con el otro, ambos se mueven juntos. Una acción que afecta a uno se refleja directamente en el otro. Imagine un tren en el que todos los vagones están conectados, o mejor dicho, conectados entre sí. Donde va el tren de vapor, están los vagones.

La conectividad también se puede describir con el término cohesión - cohesión. Esta es una medida de cuánto pertenece uno al otro. En un equipo soldado, todos los participantes están tan adaptados entre sí, como si hubieran sido creados especialmente de esa manera.

¿Por qué es importante la coherencia? Como en el caso del tren, cuando necesita cambiar un código, debe cambiar el resto del código estrechamente relacionado. Por ejemplo, alguien ha lanzado una nueva versión de su API, y ahora su código no se compila.

Una API es una fuente inevitable de enlace. Pero puede presentarse en formas más insidiosas. Todos saben que si la firma de la API ha cambiado, los datos transferidos hacia y desde la API también cambiarán. Se trata de la firma de la función: tomo los valores de un tipo y devuelvo los valores de otros tipos. ¿Y si la API comienza a transferir datos de una manera diferente? ¿Qué sucede si el resultado de cada llamada a la API depende de la llamada anterior, incluso si no cambió su configuración?

Esto se llama estado, y la gestión estatal es un problema en informática.

package counter

var count int

func Increment(n int) int {
        count += n
        return count
}

Aquí tenemos un paquete simple counter. Para cambiar el contador, puede llamar Increment, incluso puede recuperar el valor si aumenta con un valor cero.

Digamos que necesitas probar este código. ¿Cómo restablecer el contador después de cada prueba? Y si desea ejecutar pruebas en paralelo, ¿cómo se puede hacer esto? Y supongamos que desea utilizar varios contadores en el programa, ¿lo logrará?

Por supuesto no. Obviamente, la solución es encapsular la variable variableen el tipo.

package counter

type Counter struct {
        count int
}

func (c *Counter) Increment(n int) int {
        c.count += n
        return c.count
}

Ahora imagine que el problema descrito no se limita a los contadores, sino que también afecta la lógica comercial principal de sus aplicaciones. ¿Se puede probar de forma aislada? ¿Se puede probar en paralelo? ¿Se pueden usar varias instancias al mismo tiempo? Si la respuesta es no para todas las preguntas, entonces la razón es el estado a nivel de paquete.

Evita estas condiciones. Reduzca la conectividad y el número de acciones remotas de pesadilla al proporcionar tipos con las dependencias que necesitan como campos, en lugar de usar variables de paquete.

Haga planes para el fracaso, no para el éxito


Nunca pase errores en silencio.

El zen de Python, entrada 10

Esto se dice sobre los idiomas que fomentan el manejo de excepciones al estilo samurai: regresa con una victoria o no regreses en absoluto. En idiomas basados ​​en excepciones, las funciones solo devuelven resultados válidos. Si la función no puede hacer esto, entonces el flujo de control va de una manera completamente diferente.

Obviamente, las excepciones no verificadas son un modelo de programación inseguro. ¿Cómo puede escribir código confiable en presencia de errores si no sabe qué expresiones pueden generar una excepción? Java intenta reducir los riesgos con el concepto de excepciones marcadas. Y hasta donde sé, en otros idiomas populares no hay análogos de esta solución. Hay excepciones en muchos idiomas, y en todas partes, excepto Java, no están marcadas.

Obviamente, Go tomó un camino diferente. Los programadores de Go creen que los programas confiables están compuestos de partes que manejan fallas antes de procesar rutas exitosas. Dado que el lenguaje fue creado para el desarrollo del servidor, la creación de programas multiproceso, así como los programas que procesan los datos que ingresan a través de la red, los programadores deben centrarse en trabajar con datos inesperados y dañados, tiempos de espera y fallas de conexión. Por supuesto, si quieren hacer productos confiables.

Creo que los errores deben manejarse explícitamente, este debería ser el valor principal del lenguaje.

Peter Burgon, GoTime # 91

Me uno a las palabras de Peter, sirvieron de impulso a la redacción de este artículo. Creo que Go debe su éxito al manejo explícito de errores. Los programadores piensan principalmente en posibles bloqueos. Primero, resolvemos problemas como "y si". El resultado son programas en los que las fallas se manejan en la etapa de escribir código, y no como suceden durante la operación.

La verbosidad de este código.

if err != nil {
    return err
}

Supera la importancia de manejar deliberadamente cada estado fallido en el momento en que ocurre. La clave para esto es el valor de manejar explícitamente cada error.

Es mejor regresar temprano que invertir profundamente


Hermano es mejor que anidar

El zen de Python, entrada 5

Este sabio consejo proviene de un lenguaje en el que la sangría es la forma principal de flujo de control. ¿Cómo interpretamos este consejo en la terminología de Go? gofmt administra la cantidad total de espacio vacío en los programas Go, por lo que no tenemos nada que hacer aquí.

Escribí arriba sobre los nombres de los paquetes. Quizás sea aconsejable evitar una jerarquía compleja de paquetes. En mi experiencia, cuanto más intenta un programador separar y clasificar una base de código en Go, mayor es el riesgo de importación cíclica de paquetes.

Creo que el mejor uso de la quinta entrada de The Zen of Python es crear un flujo de control dentro de una función. En otras palabras, evite un flujo de control que requiera una sangría de varios niveles.

La visibilidad directa es una línea recta a lo largo de la cual nada oculta la vista.

May Ryer, Código: alinee la ruta feliz al borde izquierdo

May Ryer describe esta idea como programación en línea de visión directa:

  • Utilice las declaraciones de control para regresar antes si no se cumple la condición previa.
  • Colocando la declaración de retorno exitoso al final de la función, y no dentro del bloque condicional.
  • Reduzca el nivel general de anidamiento mediante la extracción de funciones y métodos.

Intente asegurarse de que las funciones importantes nunca se muevan fuera de la línea de visión al borde derecho de la pantalla. Este principio tiene un efecto secundario: evitará disputas sin sentido con el equipo sobre la longitud de las líneas.

Cada vez que sangra, agrega una condición previa más a los jefes de los programadores, ocupando una de sus 7 ± 2 ranuras de memoria a corto plazo. En lugar de profundizar el anidamiento, intente mantener la ruta exitosa de la función lo más cerca posible del lado izquierdo de la pantalla.

Si crees que algo funciona lentamente, pruébalo con un punto de referencia


Renunciar a la tentación de adivinar ante la ambigüedad.

El zen de Python 12

La programación se basa en las matemáticas y la lógica. Estos dos conceptos rara vez usan el elemento de la suerte. Pero nosotros, como programadores, hacemos numerosas suposiciones todos los días. ¿Qué hace esta variable? ¿Qué hace esta opción? ¿Qué pasa si paso cero aquí? ¿Qué sucede si llamo a la caja registradora dos veces? En la programación moderna, debes asumir mucho, especialmente cuando usas las bibliotecas de otras personas.

La API debe ser fácil de usar y difícil de usar incorrectamente.

Josh Bloch

Una de las mejores formas que he conocido para ayudar a un programador a evitar adivinar cuando crea una API es centrarse en los métodos de uso estándar . La persona que llama debe poder realizar operaciones normales con la mayor facilidad posible. Sin embargo, antes de escribir mucho y hablar sobre el diseño de la API, aquí está mi interpretación del registro 12: no adivine sobre el tema del rendimiento .

A pesar de su actitud ante el consejo de Knut, una de las razones del éxito de Go es la efectividad de su ejecución. Los programas eficaces se pueden escribir en este idioma, y gracias a esto, la gente seelige ir. Hay muchos conceptos erróneos relacionados con el rendimiento. Por lo tanto, cuando esté buscando formas de mejorar el rendimiento del código, o siga consejos dogmáticos como "ralentizar las estanterías", "CGO es costoso" o "siempre use operaciones atómicas en lugar de mutexes", no haga adivinación.

No complique su código debido a dogmas obsoletos. Y si crees que algo funciona lentamente, primero asegúrate de hacerlo con la ayuda de un punto de referencia. Go tiene excelentes herramientas gratuitas de evaluación comparativa y creación de perfiles. Úselos para encontrar cuellos de botella en el rendimiento de su código.

Antes de comenzar gorutin, averigüe cuándo se detendrá


Creo que he enumerado los artículos valiosos de PEP-20 y quizás expandí su interpretación más allá del buen gusto. Esto es bueno, porque aunque este es un dispositivo retórico útil, todavía estamos hablando de dos idiomas diferentes.

Escriba g, o, un espacio y luego una llamada a la función. Tres botones presionados, no puede ser más corto. Tres clics de botón, y usted lanzó el subproceso.

Rob Pike, la simplicidad es complicada , dotGo 2015

Los siguientes dos consejos los dedico a los goroutines. Las gorutinas son un rasgo característico del lenguaje, nuestra respuesta a la competitividad de alto nivel. Son muy fáciles de usar: coloque una palabra godelante del operador y ejecute la función de forma asincrónica. Sin hilos de ejecución, sin ejecutores de grupo, sin ID, sin seguimiento del estado de finalización.

Las gorutinas son baratas. Debido a la capacidad del entorno de tiempo de ejecución para multiplexar goroutines en un pequeño número de subprocesos de ejecución (que no necesita administrar), puede crear fácilmente cientos de miles o millones de goroutines. Esto le permite crear arquitecturas que serían poco prácticas al usar otros modelos competitivos, en forma de hilos de ejecución o devoluciones de llamadas de eventos.

Pero no importa cuán baratas sean las gorutinas, no son gratuitas. Su pila toma al menos unos kilobytes. Y cuando tienes millones de gorutinas, se vuelve notable. No quiero decir que no necesites usar millones de gorutinas, si la arquitectura te empuja a esto. Pero si lo usa, es extremadamente importante controlarlos, ya que en tales cantidades las gorutinas pueden consumir muchos recursos.

Las goroutinas son la principal fuente de propiedad de Go. Para ser útil, goroutine debe hacer algo. Es decir, casi siempre contiene un enlace a un recurso, es decir, información de propiedad: bloqueo, conexión de red, búfer de datos que envía el final del canal. Mientras goroutine vive, el bloqueo se mantiene, la conexión permanece abierta, el búfer se guarda y los destinatarios del canal esperarán nuevos datos.

La forma más sencilla de liberar recursos es vincularlos con el ciclo de vida de la rutina. Cuando se completa, los recursos se liberan. Y dado que es muy fácil ejecutar goroutine, antes de escribir "go and space" asegúrese de tener respuestas a estas preguntas:

  • ¿Bajo qué condición se detiene la gorutina? Ir no puede decirle a la rutina que termine. Por una razón específica, no hay función para detener o interrumpir. No podemos ordenar que las goroutines se detengan, pero podemos pedir cortésmente. Esto casi siempre está relacionado con el funcionamiento del canal. Cuando está cerrado, el rango se enlaza para salir del canal. Al cerrar el canal, puede seleccionarlo. La señal de una rutina a otra se expresa mejor como un canal cerrado.
  • ? , , : ?
  • , ? , - . , . . , .


Probablemente en cualquiera de sus programas Go serios, se use la concurrencia. Esto a menudo conduce al problema de un patrón de trabajo: una rutina por conexión.

Un buen ejemplo es net / http. Es bastante simple detener el servidor que posee el socket de escucha, pero ¿qué pasa con las goroutines que genera este socket? net / http proporciona un objeto de contexto dentro del objeto de solicitud que puede usarse para decirle al oyente que la solicitud debe cancelarse y, por lo tanto, interrumpir la rutina. Pero no está claro cómo averiguar cuándo debe hacerse todo esto. Una cosa es llamar context.Cancel, otra saber que la cancelación se ha completado.

A menudo encuentro fallas en net / http, pero no porque sea malo. Por el contrario, es la API más exitosa, más antigua y más popular en la base de código Go. Por lo tanto, su arquitectura, evolución y defectos se analizan cuidadosamente. Considere esta adulación, no crítica.

Por lo tanto, quiero traer net / http como un contraejemplo de buenas prácticas. Como cada conexión es procesada por el goroutin creado dentro del tipo net/http.Server, el programa fuera del paquete net / http no puede controlar los goroutins creados por el socket receptor.

Esta área de la arquitectura aún está en desarrollo. Puede recuperar run.Groupel go-kit, o ErrGroup, del equipo de desarrollo de Go, que proporciona un marco para ejecutar, cancelar y esperar funciones ejecutadas asincrónicamente.

Para todos los que escriben código que se puede ejecutar de forma asíncrona, el principio principal de la creación de arquitecturas es que la responsabilidad de ejecutar goroutines debe pasar a la persona que llama. Deje que elija cómo quiere correr, rastrear y esperar a que se completen sus funciones.

Escriba pruebas para bloquear el comportamiento de su paquete API


Es posible que haya esperado que en este artículo no mencione las pruebas. Lo siento, en otro momento.

Sus pruebas son un acuerdo sobre lo que hace su programa y lo que no. Las pruebas unitarias deberían bloquear el comportamiento de sus API a nivel de paquete. Las pruebas describen en forma de código lo que promete hacer el paquete. Si hay una prueba unitaria para cada conversión de entrada, entonces usted, en forma de código , y no de documentación, ha definido un acuerdo sobre lo que hará el código.

Aprobar este acuerdo es tan simple como escribir un examen. En cualquier etapa, puede declarar con un alto grado de confianza que el comportamiento en el que confiaban las personas antes de los cambios que realizó continuará funcionando después de los cambios.

Las pruebas bloquean el comportamiento de la API. Cualquier cambio que agregue, cambie o elimine la API pública debe incluir cambios en las pruebas.

La moderación es una virtud.


Go es un lenguaje simple con solo 25 palabras clave. En cierto modo, esto destaca las características integradas en el lenguaje. Estas son las características que permiten que el lenguaje se promueva a sí mismo: competencia simple, mecanografía estructural, etc.

Creo que todos estamos confundidos al tratar de usar todas las funciones de Go a la vez. ¿Cuántos de ustedes estaban tan inspirados por el uso de canales que los usaron siempre que pudieron? Descubrí que los programas resultantes son difíciles de probar, son frágiles y demasiado complejos. ¿Y tu?

Tuve la misma experiencia con goroutines. Intentando dividir el trabajo en pequeños fragmentos, creé la oscuridad de goroutin, que era difícil de controlar, y perdí de vista por completo el hecho de que la mayoría de ellos siempre estaban bloqueados debido a la expectativa de sus predecesores de completar el trabajo. El código era completamente consistente y tuve que aumentar considerablemente la complejidad para obtener una pequeña ventaja. ¿Cuántos de ustedes han encontrado esto?

Tuve lo mismo con la incrustación. Al principio lo confundí con la herencia. Luego se topó con el problema de una clase base frágil, combinando varios tipos complejos que ya tenían varias tareas en tipos enormes aún más complejos.

Este puede ser el consejo menos efectivo, pero considero importante mencionarlo. El consejo es el mismo: mantener la moderación, y las capacidades de Go no son una excepción. Siempre que sea posible, no use goroutines, canales, estructuras de incrustación, funciones anónimas, una gran cantidad de paquetes e interfaces. Use soluciones más simples que las inteligentes.

Facilidad de mantenimiento.


Finalmente, te daré otra entrada de PEP-20:

La legibilidad importa.

El zen de Python, récord 7

Se ha dicho mucho sobre la importancia de la legibilidad del código en todos los lenguajes de programación. Quienes promueven Go utilizan palabras como simplicidad, legibilidad, claridad, productividad. Pero todos estos son sinónimos de un concepto: la comodidad del mantenimiento.

El objetivo real es crear código que sea fácil de mantener. El código que sobrevive al autor. Un código que puede existir no solo como una inversión de tiempo, sino como una base para obtener un valor futuro. Esto no significa que la legibilidad no sea importante, solo la conveniencia del mantenimiento es más importante .

Go no es uno de esos lenguajes optimizados para programas de una sola línea. Y ninguno de esos idiomas está optimizado para programas con un número mínimo de líneas. No optimizamos para el tamaño del código fuente en el disco, o para la velocidad de escribir programas en el editor. Queremos optimizar nuestro código para que sea más comprensible para los lectores. Porque son ellos los que tendrán que acompañarlo.

Si escribe un programa para usted mismo, tal vez se iniciará solo una vez, o usted es el único que ve su código. En este caso, haz cualquier cosa. Pero si más de una persona trabaja en el código, o si se utilizará durante mucho tiempo y los requisitos, las capacidades o el tiempo de ejecución pueden cambiar, entonces el programa debería ser conveniente de mantener. Si el software no se puede mantener, no se puede reescribir. Y esta puede ser la última vez que su empresa invierte en Go.

¿En qué trabaja duro será conveniente acompañarlo después de su partida? ¿Cómo puede facilitar el mantenimiento de su código para aquellos que vienen después de usted hoy?

All Articles