¿Qué proyectos de programación le han dado más información sobre un concepto / técnica de programación?

El proyecto que me dio una visión más profunda de la programación, y cambió mi filosofía de programación al núcleo, fue diseñar un lenguaje de programación .

La palabra clave es diseñar : no se trataba de implementar un lenguaje existente y aprender sobre compiladores; Si bien es importante, ese tipo de cosas no es fundamental. No, este proyecto en realidad estaba diseñando mi propio lenguaje desde cero.

Mi principal conclusión fue que la semántica es importante . Muy importante. ¿Todas esas cosas que aprendiste sobre la semántica operacional y la semántica denotacional y el cálculo λ y la teoría de tipos? Son cómo deben diseñarse los idiomas . Ahora no tengo el tiempo ni la paciencia para lidiar con idiomas que fueron pirateados sin pensar profundamente en cuestiones fundamentales. Ya sabes, la mayoría de ellos.

La semántica es lo que busco en un idioma . No tienen que estar completamente formalizados o especificados; Solo me importa que los diseñadores de idiomas piensen realmente en ellos. Puntos de bonificación importantes para la semántica denotacional limpia (o al menos limpia). Me imagino que lo que significa mi programa es lo más importante : cómo se comporta debería ser una función de su significado, no viceversa. Esto hace que los programas sean más fáciles de escribir, más fáciles de pensar y más fáciles de mantener.

Aprendí estas cosas diseñando un lenguaje sin pensar mucho en la semántica en ningún sentido formal y viendo lo fácil que es conseguir un desastre completo. Nunca usaría el lenguaje que diseñé para algo serio, ¡pero no es tan diferente de JavaScript o PHP o incluso Python!

Diseñando un lenguaje

Dejando a un lado todas esas lecciones, lo primero que aprendí fue que realmente no sé cómo nombrar las cosas. ¡Terminé llamando a mi lenguaje TPL para “Lenguaje de programación de Tikhon”! Tan creativo. Una pena que el mismo esquema realmente no funcione cuando finalmente escribo un compilador Haskell.


Bien, lo admito, esa lección no es muy profunda.

Las ideas profundas llegaron con el diseño de cómo el lenguaje debería funcionar desde cero. No tanto diseñar la sintaxis que terminó siendo muy simple y minimalista sino diseñar la semántica .

Mi enfoque para armar el lenguaje fue muy ad-hoc. Tenía un intérprete y, cada vez que pensaba en una función, simplemente la implementaba. Luego jugaba con él en el REPL o en los archivos fuente para ver si me gustaba. La mayoría de las características que me gustaron. Algunos necesitaban ajustes. Un poco realmente no funcionó en absoluto, no importa lo que intenté.

Fuera de las características que realmente no funcionaron, creo que la más importante fue la coerción automática entre tipos a la JavaScript. Cuando comencé el lenguaje, quería hacer esto bien : sistemática, extensible e inteligente. Resulta que simplemente no puedes. Es un diseño terrible. Va a hacer un lío con su código sin importar lo que haga. Originalmente, estaba realmente muy emocionado por hacer esto, pero terminé eliminándolo completamente de mi idioma.

Accidentes felices

Otras veces, características interesantes surgieron por accidente. Mi ejemplo favorito sería mi enfoque de “pereza a pedido” ¹, que le permite diferir fácilmente los valores que se ejecutarán más adelante. Básicamente, puede “diferir” una expresión como x + 10 con $ . Esta expresión se vuelve a evaluar cada vez que se usa, lo que le permite responder a los cambios en las variables que usa:

  y = $ (x + 10) - x = 0 e y 10
 x <- 10 - ahora x = 10
 y - ahora y se vuelve a evaluar como 20 ya que x cambió

Esto resultó ser muy útil en muchos casos. ¡Pero el núcleo de la idea fue en realidad el resultado de no pensar en mi diseño originalmente! En particular, utilicé el estilo Haskell para la aplicación de funciones, donde las funciones siempre tienen currículum y no usas paréntesis ni comas. En particular:

  f (a, b + c, d) - estilo C
 fa (b + c) d - en TPL (y Haskell y ML y ...)

Por supuesto, Haskell hace esto realmente bien porque las funciones con 0 argumentos no existen; la idea ni siquiera tiene sentido. ¡Pero en mi lenguaje imperativo, las funciones de 0 argumentos son realmente útiles! Entonces, ¿cómo puedo saber si f es una llamada a función sin argumentos o una referencia a la función en sí?

OCaml hace esto obligando a todas las funciones como esta a tomar un argumento ficticio () (pronunciado “unidad”). Pero siempre pensé que esto era estúpido. (¡Apestas OCaml!) Así que decidí que f fuera una llamada de función si f era una función de 0 argumentos. Y para referirme a f sin llamarlo, agregué $ como sintaxis. Luego, esto terminó siendo útil para diferir cosas que no eran funciones, y se convirtió en una característica genial que terminé extendiendo un poco.

Minimalismo

Una cosa interesante que encontré fue que la mayoría de los idiomas tienen más conceptos de los que necesitan. Me suscribí a una estética relativamente minimalista (tanto en programación como en todo, desde diseño gráfico hasta música), así que realmente no me gustó esto. En mi idioma, terminé tratando de colapsar tantos conceptos diferentes en uno como sea posible.

Un ejemplo concreto serían los objetos. Primero, tomé el enfoque JavaScript / Lua de hacer objetos hash-maps (y viceversa). Esto estuvo muy bien. ¡Pero luego noté que mi implementación de ámbitos era casi la misma que mis objetos! Así que terminé haciendo ámbitos ciudadanos de primera clase: puede especificar un objeto arbitrario como el alcance de una función, y puede acceder al alcance actual como un objeto.

Esto terminó siendo muy poderoso cuando extendí objetos con la posibilidad de personalizar cómo se realizan las búsquedas (similar a los proxies de JavaScript). Esto me permite hacer objetos personalizados con diferentes tipos de comportamientos de búsqueda y usarlos como ámbitos para travesuras de estilo que faltan en el método Ruby. Un gran caso de uso sería el script de shell, donde podría tener un objeto que busque variables desconocidas en su ruta para permitirle usar binarios directamente en el programa. ¡Podría tener esto como una biblioteca pura, sin tener que agregar capacidades de secuencias de comandos al lenguaje central!

Esta experiencia me convenció de que la mayoría de los idiomas están sobre diseñados . Ahora soy totalmente partidario de la idea de que los idiomas deberían poder crecer . Esto se resume mejor en la maravillosa charla de Guy Steele “Growing a Language” ², que sigue siendo mi charla CS favorita. Más simple es mejor .

Loco

Ahora, cuando estaba escribiendo mi idioma, mi intérprete ciertamente tenía errores. Algunos de ellos eran muy difíciles de cazar. Multa. Pero la mayoría de los proyectos de programación tienen errores. Y los más duraderos tendrán errores duros. Sí, mejoré en la depuración, pero eso no dice mucho.

No, los errores interesantes no estaban en el intérprete. Estaban en el diseño del lenguaje en sí ! Es decir, mis problemas principales surgieron cuando el intérprete realmente funcionó perfectamente bien. Es la semántica del lenguaje la que terminó siendo inconsistente. Y dado que no tenía un modelo simple para mi semántica, era casi imposible de depurar o arreglar sin reestructurar profundamente el lenguaje. Es por eso que me he vuelto tan adherente a tener una semántica explícita o al menos operativa para su lenguaje: la semántica formal es el modelo simple que le permite depurar el diseño de su lenguaje . ¿Y le gustaría usar algo que no podría haberse depurado correctamente? ¡Probablemente no!

Después de diseñar esto, leí un libro interesante sobre el diseño de Bondi, un lenguaje funcional con patrones de primera clase. Es un libro bastante bueno y un lenguaje interesante. Pero lo principal que aprendí fue la forma en que se presenta el lenguaje: se desarrolla extendiendo iterativamente el cálculo λ sin tipo con características adicionales. Esto hace que sea muy fácil considerar las características por sí mismas y ver el “núcleo” del lenguaje, la parte que realmente importa. A su vez, esto asegura que cada característica tenga sentido y hace que las esquinas extrañas en el diseño sean mucho menos probables.

Básicamente, esto lleva las ideas de modularidad de la programación normal al diseño del lenguaje, con las mismas ventajas. Es mucho más fácil trabajar en piezas pequeñas a la vez, con una complejidad incidental mucho menor de la que preocuparse.

La próxima vez que esté diseñando un lenguaje, este es el enfoque que adoptaré.

Y esto es también lo que espero de los idiomas que otras personas diseñan. Al igual que me alejaría de los programas llenos de código PHP de spaghetti, compuestos por vulnerabilidades de seguridad unidas a variables globales, me gustaría evitar lenguajes que no se diseñaron bien con características que simplemente no tienen sentido. Me gusta JavaScript. O PHP.

El respeto

Diseñar un idioma también tuvo el mismo efecto que aprender a cocinar. Después de poner un poco de esfuerzo en cocinar en casa, he ganado un gran respeto por los mejores chefs que hacen que las cosas que son innovadoras, interesantes y se vean maravillosas además de tener un sabor maravilloso. Del mismo modo, tengo un inmenso respeto por los diseñadores de buenos idiomas.
Ni siquiera puedo imaginar cómo hacer algo así …

Por otro lado, en realidad he perdido el respeto por muchos restaurantes de gama baja. ¿Lo haces profesionalmente pero no puedes hacer algo sustancialmente mejor que yo en casa? ¡Guauu! En cambio, intentas que tenga buen sabor con grandes cantidades de sal, grasa y azúcar. Y estoy aún menos impresionado por la comida rápida, aunque eso es lo que sirven los restaurantes más populares.

Esto es lo que pienso de PHP ahora.

Tal vez eso me hace un poco snob, pero creo que no hay nada de malo en preocuparse por la calidad. (Y, tal vez, algo malo en no preocuparse por la calidad). Es doblemente cierto para los lenguajes de programación porque, a diferencia de la buena comida, todos los mejores lenguajes son gratuitos.

Entonces sí: TPL fue probablemente mi proyecto más formativo . No solo me enseñó más sobre programación, sino que también cambió profundamente mi perspectiva sobre mis propios programas y diseños, así como sobre otros programas y lenguajes de programación. Fue una experiencia increíblemente valiosa.

Notas al pie
Aside Como pedante aparte, estrictamente no es “pereza” porque las expresiones pueden evaluarse más de una vez. Pero ese es el nombre que elegí entonces y ese es el nombre que usaré ahora. ¡Suena mucho mejor que “call-by-name on demand”!

² Aquí está el video de YouTube. Comienza extraño, ¡pero vale la pena verlo!

Así que voy a ser un poco poco convencional con mis proyectos.

Tuve 2 proyectos en mi segundo semestre de la universidad que realmente me hablaron. Estaba tomando una clase llamada Computer Architecture and Organization. Al principio no estaba realmente emocionado porque nunca había hecho algo así antes y me considero más una persona de primera línea, pero, no hace falta decir que me sorprendió gratamente.

Uno de mis proyectos de programación favoritos fue lo que voy a llamar el proyecto bomba . Se repite en muchas universidades, creo. La premisa es que tienes que ingresar códigos de acceso en una bomba y si te equivocas, tu bomba explota. Cuantas más explosiones, más puntos te dedujeron. El “código de bomba” tenía miles de líneas de código de largo (en 3 columnas de alrededor de tamaño 7 u 8, terminó siendo alrededor de 7 páginas en Microsoft Word). Este proyecto me enseñó la importancia de los depuradores; porque podría hacer todo el proyecto sin explotar la bomba (incluso con un código de acceso incorrecto) si utilizara los puntos de interrupción correctamente. Eso, y fue solo un proyecto divertido para resolver problemas. Definitivamente el menos serio de mis dos proyectos favoritos.

Otro de mis proyectos de programación favoritos fue un laboratorio de tuberías . Para alguien con poco conocimiento práctico de computación antes de la universidad, este proyecto me abrió muchas puertas. Esencialmente, se nos asignó la tarea de modificar el código de ensamblaje para hacer que el código C simple se ejecute más rápido (se nos proporcionó el código C y no se nos permitió modificarlo). La mayoría de mis amigos odiaban el proyecto, pero realmente me gustó porque me hizo pensar en aspectos de mi código fuera de la corrección. Empecé a pensar en la optimización y en hacer que mi código se ejecute mucho más rápido y de manera más eficiente. Me interesé en la optimización y, de hecho, mi proyecto de pasantía en Amazon para Kindle se basó en la optimización (cuando tuve que elegir entre 2 proyectos y vi una optimización involucrada, definitivamente me encantó).

Mi punto al mencionar estos proyectos es: a veces puedes encontrar lecciones realmente interesantes y perspicaces en lugares poco probables. Incluso en los laboratorios!

Personalmente, siempre he aprendido mucho de proyectos que involucran gráficos. Si bien, obviamente, puede trabajar en muchos proyectos diferentes que involucran gráficos, creo que los juegos funcionan particularmente bien si está tratando de aprender sobre un lenguaje / marco.

También creo que hay mucho más código para crear juegos, por lo que también es una ventaja. Los juegos contienen numerosos componentes y muchos ángulos diferentes en los que tienes que pensar.

Intenta hacer un juego multiplataforma y creo que realmente apreciarás cuánto aprenderás

Lo más importante que hice fue unirme a una comunidad de código abierto. Para mí, ese fue el proyecto Fedora (así como algunos otros proyectos más pequeños, como Phabricator), pero las mismas habilidades (en gran medida, habilidades sociales, no necesariamente un concepto de programación) podrían adquirirse uniéndose a cualquier número de proyectos.

Al unirse a un proyecto de código abierto, puede trabajar con muchas personas, incluidas muchas más inteligentes que usted. Aprende cosas como cómo contribuir con éxito a proyectos más grandes, cómo ayudar a otros a unirse a un proyecto y cómo familiarizarse con una base de código / documentación / herramientas de administrador de sistemas / lo que sea (dependiendo del equipo al que se una) que ya existe Estas son todas las habilidades que pueden y lo ayudarán a lo largo de su carrera.

Incluso si no desea, o no tiene tiempo, para unirse a un proyecto más grande en este momento, busque oportunidades para codificar en colaboración. Tal vez los grupos http://meetup.com cerca de usted que están orientados a la programación, o si es un estudiante, busque desafíos competitivos de programación dentro de su universidad.

Trabajar con otras personas para aprender y compartir conocimiento probablemente ha sido una de las cosas más importantes, si no la más importante, lo he hecho hasta ahora para obtener el conocimiento de programación que tengo hasta ahora.

Yo y otros 2 colegas construimos el sistema de chat de texto y video en un sitio web de citas llamado True, True Beginnings, LLC. Aprendí que 3 personas es el tamaño óptimo del equipo. Aumentar ese equipo a 4 aumentó las rutas de comunicación en n (n + 1), lo que nos ralentizó significativamente y afectó nuestra capacidad de mejorar la aplicación y el sistema. Sé que esta no es una técnica de programación, pero es la lección más importante que he aprendido construyendo tecnología.

Trabajar en el almacén de datos de MasterCard me enseñó mucho sobre la optimización de la base de datos y cómo las bases de datos procesan las consultas. No puedo imaginar una mejor experiencia de aprendizaje.

Escribir para mi DocForge Wiki continuamente me hace pensar en nuevas ideas y cómo explicarlas claramente. Escribir sobre un tema, similar a enseñarlo, te obliga a contemplar cosas.

Contribuir a Drupal me enseñó los requisitos internos / backend para la funcionalidad común de CMS. También me dio información sobre cómo no implementar ciertas cosas.

En 1982-1985, era programador en una tienda de IBM. Una de las mejores cosas que aprendí fue un sistema que se llamaba “CGS”, o Sistema de Grupo Consolidado. Este sistema era un sistema de procesamiento de registros a gran escala, que estaba muy adelantado a su tiempo.

La belleza del sistema era que todos los módulos que procesaban registros recibían un “código de actividad”. Este código era una identidad para un programa llamado “líder”, para esa actividad, y procesó la actividad, en función del tipo de información que estaba incrustada en el registro de actividad.

Lo bueno de esto fue que las cosas que debían ocurrir (dentro del gran esquema de las cosas), en un orden específico, podían controlarse mediante porciones de la clave de cada registro secuencial procesado.

Todos los registros fueron ordenados por esta maravillosa clave. Si la memoria sirve, la clave era prefijo, contrato, registro, número de identificación, tipo de identificación.

El sistema CGS se utilizó durante muchos años en esta tienda debido a la versatilidad y simplicidad del diseño general.

Esta técnica siempre estaba en el fondo de mi mente, cuando me acercaba a un nuevo desarrollo. Es decir, pensar intensamente en su flujo de entrada de antemano, y sus procesos subordinados se simplificarán enormemente, más adelante, cuando resuelva grandes problemas.

Bueno, soy un estudiante universitario y puede que no esté muy expuesto a muchos lenguajes de programación y proyectos. Soy un gran admirador de Python , pero déjame decirte que comencé con C y luego C ++ (para programación orientada a objetos).
Luego este último estuve expuesto a muchos lenguajes para mencionar algunos, python, ruby, PHP, Java, Haskel, R, lisp …
pero si ha estudiado C / C ++ a fondo y ha intentado todos los ejercicios básicos y avanzados, confíe en mí, realmente puede aprender cualquier otro idioma.
Eso es lo que pienso ….

Creo que solo darte tiempo y concentrarte en un proyecto a la vez ayuda a obtener un conocimiento completo sobre cualquier dominio, ya sea gráficos / almacenamiento de datos / cualquier cosa …
Probablemente no se dará cuenta de cuánto sabe hasta que alguien le diga

Si te gusta algo y quieres aprenderlo, establece metas y cúmplelas …

cualquier cosa que involucrara ensamblaje.