Diseño y construcción de una aplicación web progresiva sin un marco (Parte 3)
Publicado: 2022-03-10En la primera parte de esta serie, explicamos por qué surgió este proyecto. Es decir, el deseo de aprender cómo se podría hacer una pequeña aplicación web en JavaScript estándar y hacer que un desarrollador que no es diseñador trabaje un poco en sus habilidades de diseño.
En la segunda parte, tomamos algunos diseños iniciales básicos y pusimos todo en marcha con algunas opciones de herramientas y tecnología. Cubrimos cómo y por qué cambiaron partes del diseño y las ramificaciones de esos cambios.
En esta parte final, cubriremos cómo convertir una aplicación web básica en una aplicación web progresiva (PWA) y 'enviar' la aplicación antes de ver las lecciones más valiosas aprendidas al hacer que la aplicación web simple sea de entrada/salida:
- El enorme valor de los métodos de matriz de JavaScript;
- Depuración;
- Cuando eres el único desarrollador, eres el otro desarrollador;
- El diseño es desarrollo;
- Problemas continuos de mantenimiento y seguridad;
- Trabajar en proyectos paralelos sin perder la cabeza, la motivación o ambos;
- Enviar algunos productos es mejor que enviar ningún producto.
Entonces, antes de ver las lecciones aprendidas, veamos cómo convertir una aplicación web básica escrita en HTML, CSS y JavaScript en una aplicación web progresiva (PWA).
En términos del tiempo total dedicado a hacer esta pequeña aplicación web, calculo que probablemente fue alrededor de dos o tres semanas. Sin embargo, como se hizo en fragmentos de 30 a 60 minutos por las noches, en realidad tomó alrededor de un año desde la primera confirmación hasta que subí lo que considero la versión '1.0' en agosto de 2018. Como obtuve la aplicación ' característica completa', o más simplemente hablando, en una etapa con la que estaba contento, anticipé un gran impulso final. Verá, no había hecho nada para convertir la aplicación en una aplicación web progresiva. Resulta que esta fue en realidad la parte más fácil de todo el proceso.
Hacer una aplicación web progresiva
La buena noticia es que cuando se trata de convertir una pequeña aplicación basada en JavaScript en una 'aplicación web progresiva', hay montones de herramientas para hacer la vida más fácil. Si recuerda la primera parte de esta serie, recordará que ser una aplicación web progresiva significa cumplir con una serie de criterios.
Para tener una idea de cómo se mide su aplicación web, su primera parada probablemente debería ser las herramientas Lighthouse de Google Chrome. Puede encontrar la auditoría de Progressive Web App en la pestaña 'Auditorías'.
Esto es lo que me dijo Lighthouse cuando lo revisé por primera vez.
Al principio, In/Out solo obtenía una puntuación de 55 ⁄ 100 para una aplicación web progresiva. Sin embargo, lo llevé desde allí a 100 ⁄ 100 en menos de una hora.
La conveniencia de mejorar esa puntuación tenía poco que ver con mi habilidad. ¡Fue simplemente porque Lighthouse me dijo exactamente lo que había que hacer!
Algunos ejemplos de pasos necesarios: incluya un archivo manifest.json
(esencialmente un archivo JSON que proporciona metadatos sobre la aplicación), agregue una gran cantidad de metaetiquetas en el encabezado, cambie las imágenes que estaban en línea en el CSS por imágenes con referencia a URL estándar, y agregue un montón de imágenes de la pantalla de inicio.
Crear una serie de imágenes de la pantalla de inicio, crear un archivo de manifiesto y agregar un montón de metaetiquetas puede parecer mucho trabajo en menos de una hora, pero existen maravillosas aplicaciones web para ayudarlo a crear aplicaciones web. ¡Qué bueno es eso! Usé https://app-manifest.firebaseapp.com. ¡Aliméntelo con algunos datos sobre su aplicación y su logotipo, presione enviar y le proporcionará un archivo zip que contiene todo lo que necesita! A partir de ahí, es solo tiempo de copiar y pegar.
Las cosas que pospuse durante algún tiempo debido a la falta de conocimiento, como un trabajador de servicio, también se agregaron con bastante facilidad gracias a numerosas publicaciones de blog y sitios dedicados a trabajadores de servicio como https://serviceworke.rs. Con un trabajador de servicio en su lugar, significaba que la aplicación podía funcionar sin conexión, una característica necesaria de una aplicación web progresiva.
Si bien no está estrictamente relacionado con convertir la aplicación en una PWA, la pestaña "cobertura" de Chrome Dev Tools también fue muy útil. Después de tantas iteraciones esporádicas en el diseño y el código durante meses, fue útil obtener una indicación clara de dónde había código redundante. ¡Encontré algunas funciones antiguas ensuciando el código base que simplemente había olvidado!
En poco tiempo, después de haber trabajado con las recomendaciones de la auditoría de Lighthouse, me sentí como la mascota del maestro:
La realidad es que tomar la aplicación y convertirla en una aplicación web progresiva fue increíblemente sencillo.
Con esa pieza final de desarrollo concluida, subí la pequeña aplicación a un subdominio de mi sitio web y eso fue todo.
Retrospectivo
Han pasado meses desde que aparqué el desarrollo de mi pequeña aplicación web.
He usado la aplicación casualmente en los meses posteriores. La realidad es que gran parte de la organización de deportes de equipo que hago todavía se realiza a través de mensajes de texto. Sin embargo, la aplicación es definitivamente más fácil que anotar quién entra y quién sale que encontrar un trozo de papel cada noche de juego.
Entonces, la verdad es que no es un servicio indispensable. Tampoco establece barras para el desarrollo o el diseño. Tampoco podría decirte que estoy 100% feliz con él. Llegué a un punto en el que estaba feliz de abandonarlo.
Pero ese nunca fue el objetivo del ejercicio. Tomé mucho de la experiencia. Lo que sigue es lo que considero los puntos más importantes.
El diseño es desarrollo
Al principio, no valoré lo suficiente el diseño. Comencé este proyecto creyendo que el tiempo que pasaba dibujando con un bloc y un bolígrafo o en la aplicación Sketch era un tiempo que podría emplearse mejor con la codificación. Sin embargo, resulta que cuando fui directamente al código, a menudo solo estaba siendo un tonto ocupado. Explorar conceptos primero con la menor fidelidad posible, ahorró mucho más tiempo a largo plazo.
Hubo numerosas ocasiones al principio en las que se dedicaron horas a lograr que algo funcionara en el código solo para darse cuenta de que tenía fallas fundamentales desde el punto de vista de la experiencia del usuario.
Mi opinión ahora es que el papel y el lápiz son las mejores herramientas de planificación, diseño y codificación. Todos los problemas significativos enfrentados se resolvieron principalmente con papel y lápiz; el editor de texto es simplemente un medio para ejecutar la solución. Sin algo que tenga sentido en el papel, no tiene ninguna posibilidad de funcionar en código.
Lo siguiente que aprendí a apreciar, y no sé por qué tardé tanto en darme cuenta, es que el diseño es iterativo. Subconscientemente había comprado el mito de un diseñador con una "D" mayúscula. Alguien revoloteando, sosteniendo su lápiz mecánico en los bordes rectos, hablando líricamente sobre los tipos de letra y bebiendo un flat white (con leche de soya, obviamente) antes de dar a luz casualmente la perfección visual completamente formada en el mundo.
Esto, al igual que la noción del programador 'genio', es un mito. Si eres nuevo en el diseño pero estás probando tu mano, te sugiero que no te obsesiones con la primera idea que despierte tu entusiasmo. Es muy barato probar variaciones, así que aprovecha esa posibilidad. Ninguna de las cosas que me gustan del diseño de In/Out estaban en los primeros diseños.
Creo que fue el novelista Michael Crichton quien acuñó la máxima: “Los libros no se escriben, se reescriben”. Acepta que cada proceso creativo es esencialmente el mismo. Tenga en cuenta que confiar en el proceso disminuye la ansiedad y la práctica refinará su comprensión y juicio estéticos.
Eres el otro desarrollador de tu proyecto
No estoy seguro de si esto es particular de los proyectos en los que solo se trabaja esporádicamente, pero hice la siguiente suposición temeraria:
“No necesito documentar nada de esto porque soy solo yo, y obviamente lo entenderé porque lo escribí”.
¡Nada mas lejos de la verdad!
Hubo tardes en las que, durante los 30 minutos que tenía para trabajar en el proyecto, no hacía más que tratar de entender una función que había escrito seis meses atrás. Las principales razones por las que la reorientación del código tomó tanto tiempo fue la falta de comentarios de calidad y variables y argumentos de funciones mal nombrados.
Soy muy diligente al comentar el código en mi trabajo diario, siempre consciente de que alguien más podría necesitar dar sentido a lo que estoy escribiendo. Sin embargo, en este caso, yo era ese alguien más. ¿De verdad crees que recordarás cómo funciona el bloque de código que escribiste dentro de seis meses? no lo harás Confía en mí en esto, ¡tómate un tiempo y comenta eso!
Desde entonces, leí una publicación de blog titulada Su resaltador de sintaxis está equivocado sobre el tema de la importancia de los comentarios. La premisa básica es que los resaltadores de sintaxis no deben desaparecer de los comentarios, deben ser lo más importante. Me inclino a estar de acuerdo y si no encuentro un tema de editor de código pronto que rasque esa picazón, ¡es posible que tenga que adaptar uno para ese fin!
depuración
Cuando encuentra errores y ha escrito todo el código, no es injusto sugerir que el error probablemente se origine entre el teclado y la silla. Sin embargo, antes de asumir eso, le sugiero que pruebe incluso sus suposiciones más básicas. Por ejemplo, recuerdo haber tardado más de dos horas en solucionar un problema que supuse que se debía a mi código; en iOS simplemente no pude hacer que mi cuadro de entrada aceptara la entrada de texto. No recuerdo por qué no me había detenido antes, pero sí recuerdo mi frustración con el problema.
Resulta que se debió a un error en Safari, que aún no se ha corregido. Resulta que en Safari si tienes:
* { user-select: none; }
En su hoja de estilo, los cuadros de entrada no aceptarán ninguna entrada. Puede solucionar esto con:
* { user-select: none; } input[type] { user-select: text; }
¿Cuál es el enfoque que tomo en mi reinicio de CSS "Restablecimiento de la aplicación". Sin embargo, la parte realmente frustrante de esto fue que ya lo había aprendido y posteriormente lo olvidé. Cuando finalmente pude verificar el seguimiento de errores de WebKit mientras solucionaba el problema, descubrí que había escrito una solución en el hilo del informe de errores hace más de un año, ¡completa con una reducción!
¿Quiere construir con datos? Aprenda los métodos de matriz de JavaScript
Tal vez el mayor avance que lograron mis habilidades de JavaScript al realizar este ejercicio de creación de aplicaciones fue familiarizarme con los métodos de JavaScript Array. Ahora los uso a diario para todas mis necesidades de iteración y manipulación de datos. No puedo enfatizar lo suficiente cuán útiles son los métodos como map()
, filter()
, every()
, findIndex()
, find()
y reduce()
. Puede resolver prácticamente cualquier problema de datos con ellos. Si aún no los tiene en su arsenal, marque https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array ahora y profundice en cuanto pueda. Mi propio resumen de mis métodos de matriz favoritos está documentado aquí.
ES6 ha introducido otros ahorradores de tiempo para manipular matrices, como Set
, Rest
y Spread
. Consiénteme mientras comparto un ejemplo; solía haber un montón de faff si quería eliminar duplicados incluso de una matriz plana simple. Ya no.
Considere este ejemplo simple de una matriz con la entrada duplicada, "Mr Pink":
let myArray = [ "Mr Orange", "Mr Pink", "Mr Brown", "Mr White", "Mr Blue", "Mr Pink" ];
Para deshacerse de los duplicados con ES6 JavaScript, ahora puede hacer lo siguiente:
let deDuped = [...new Set(myArray)]; // deDuped logs ["Mr Orange", "Mr Pink", "Mr Brown", "Mr White", "Mr Blue"]
Algo que solía requerir la elaboración manual de una solución o la búsqueda de una biblioteca ahora está integrado en el lenguaje. Es cierto que en una matriz tan corta que puede no parecer un gran problema, pero imagine cuánto tiempo ahorra al mirar matrices con cientos de entradas y duplicados.
Mantenimiento y Seguridad
Cualquier cosa que construya que haga uso de NPM, incluso si solo para herramientas de construcción, conlleva la posibilidad de ser vulnerable a problemas de seguridad. GitHub hace un buen trabajo al mantenerlo al tanto de los problemas potenciales, pero aún hay cierta carga de mantenimiento.
Para algo que es un mero proyecto paralelo, esto puede ser un poco doloroso en los meses y años que siguen al desarrollo activo.
La realidad es que cada vez que actualiza las dependencias para solucionar un problema de seguridad, presenta la posibilidad de romper su compilación.
Durante meses, mi package.json
se veía así:
{ "dependencies": { "gulp": "^3.9.1", "postcss": "^6.0.22", "postcss-assets": "^5.0.0" }, "name": "In Out", "version": "1.0.0", "description": "simple utility to see who's in and who's out", "main": "index.js", "author": "Ben Frain", "license": "MIT", "devDependencies": { "autoprefixer": "^8.5.1", "browser-sync": "^2.24.6", "cssnano": "^4.0.4", "del": "^3.0.0", "gulp-htmlmin": "^4.0.0", "gulp-postcss": "^7.0.1", "gulp-sourcemaps": "^2.6.4", "gulp-typescript": "^4.0.2", "gulp-uglify": "^3.0.1", "postcss-color-function": "^4.0.1", "postcss-import": "^11.1.0", "postcss-mixins": "^6.2.0", "postcss-nested": "^3.0.0", "postcss-simple-vars": "^4.1.0", "typescript": "^2.8.3" } }
Y para junio de 2019, recibí estas advertencias de GitHub:
Ninguno estaba relacionado con los complementos que estaba usando directamente, todos eran subdependencias de las herramientas de compilación que había usado. Tal es la espada de doble filo de los paquetes de JavaScript. En cuanto a la aplicación en sí, no hubo ningún problema con In/Out; eso no estaba usando ninguna de las dependencias del proyecto. Pero como el código estaba en GitHub, me sentí obligado a tratar de arreglar las cosas.
Es posible actualizar los paquetes manualmente, con algunos cambios de elección en el archivo package.json. Sin embargo, tanto Yarn como NPM tienen sus propios comandos de actualización. Opté por ejecutar yarn upgrade-interactive
que le brinda un medio simple para actualizar las cosas desde la terminal.
Parece bastante fácil, incluso hay una pequeña tecla de color que le indica qué actualizaciones son las más importantes.
Puede agregar el indicador --latest
para actualizar a la última versión principal de las dependencias, en lugar de solo la última versión parcheada. Por un centavo…
El problema es que las cosas se mueven rápido en el mundo de los paquetes de JavaScript, por lo que actualizar algunos paquetes a la última versión y luego intentar una compilación resultó en esto:
Como tal, revertí mi archivo package.json
y lo intenté nuevamente esta vez sin el indicador --latest
. Eso resolvió mis problemas de seguridad. No es lo más divertido que he tenido un lunes por la noche, aunque seré honesto.
Eso toca una parte importante de cualquier proyecto paralelo. Ser realista con tus expectativas.
Proyectos paralelos
No sé si a vosotros os pasa lo mismo pero he descubierto que un optimismo vertiginoso y la ilusión me hacen empezar proyectos y si algo me hace, la vergüenza y la culpa me hacen terminarlos.
Sería mentira decir que la experiencia de hacer esta pequeña aplicación en mi tiempo libre estuvo llena de diversión. Hubo ocasiones en las que desearía no haber abierto nunca la boca al respecto a nadie. Pero ahora que está hecho, estoy 100% convencido de que valió la pena el tiempo invertido.
Dicho esto, es posible mitigar la frustración con un proyecto paralelo de este tipo siendo realista sobre cuánto tiempo llevará comprender y resolver los problemas que enfrenta. ¿Solo tienes 30 minutos por noche, algunas noches a la semana? Todavía puedes completar un proyecto paralelo; simplemente no te desanimes si tu ritmo se siente glacial. Si las cosas no pueden disfrutar de toda su atención, prepárese para un ritmo más lento y constante de lo que quizás esté acostumbrado. Eso es cierto, ya sea programando, completando un curso, aprendiendo a hacer malabarismos o escribiendo una serie de artículos sobre por qué tomó tanto tiempo escribir una pequeña aplicación web.
Establecimiento de objetivos simples
No necesita un proceso sofisticado para establecer metas. Pero podría ayudar dividir las cosas en tareas pequeñas/cortas. Cosas tan simples como 'escribir CSS para el menú desplegable' se pueden lograr perfectamente en un espacio de tiempo limitado. Mientras que 'investigar e implementar un patrón de diseño para la gestión estatal' probablemente no lo sea. Rompe las cosas. Luego, al igual que Lego, las piezas pequeñas se unen.
Pensando en este proceso como socavando el problema más grande, recuerdo la famosa cita de Bill Gates:
“La mayoría de las personas sobrestiman lo que pueden hacer en un año y subestiman lo que pueden hacer en diez años”.
Esto de un hombre que está ayudando a erradicar la polio. Bill sabe lo que hace. Escuchen a Bill todos ustedes.
Enviar algo es mejor que enviar nada
Antes de "enviar" esta aplicación web, revisé el código y me desanimé por completo.
Aunque había emprendido este viaje desde un punto de total ingenuidad e inexperiencia, había tomado algunas decisiones decentes en lo que respecta a cómo podría diseñar (si me perdonan un término tan grandioso) el código. Investigué e implementé un patrón de diseño y disfruté todo lo que ese patrón tenía para ofrecer. Lamentablemente, a medida que me desesperaba más por concluir el proyecto, no pude mantener la disciplina. El código, tal como está, es una verdadera mezcolanza de enfoques y está plagado de ineficiencias.
En los meses transcurridos desde que me di cuenta de que esas deficiencias realmente no importan. Realmente no.
Soy fan de esta cita de Helmuth von Moltke.
“Ningún plan de operaciones se extiende con certeza más allá del primer contacto con la principal fuerza hostil”.
Eso ha sido parafraseado como:
“Ningún plan sobrevive al primer contacto con el enemigo”.
¿Quizás podamos reducirlo aún más y simplemente ir con "mierda sucede"?
Puedo suponer que llegué a un acuerdo con lo que se envió a través de la siguiente analogía.
Si un amigo anunciara que intentaría correr su primer maratón, lo único que importaría sería que cruzara la línea de meta; no lo estaría regañando por su tiempo de finalización.
No me propuse escribir la mejor aplicación web. La tarea que me propuse fue simplemente diseñar y hacer uno.
Más específicamente, desde una perspectiva de desarrollo, quería aprender los fundamentos de cómo se construye una aplicación web. Desde el punto de vista del diseño, quería intentar resolver algunos problemas de diseño (si bien simples) por mí mismo. Hacer esta pequeña aplicación superó esos desafíos y más. El JavaScript para toda la aplicación ocupaba solo 5 KB (comprimido con gzip). Un tamaño de archivo pequeño al que me costaría llegar con cualquier marco. Excepto tal vez Svelte.
Si se está planteando un desafío de esta naturaleza y espera "enviar" algo en algún momento, escriba desde el principio por qué lo está haciendo. Mantén esas razones al frente de tu mente y déjate guiar por ellas. Todo es, en última instancia, una especie de compromiso. No dejes que los ideales elevados te paralicen de terminar lo que te propongas.
Resumen
En general, como hace un año desde que trabajé en In/Out, mis sentimientos se dividen en tres áreas: cosas de las que me arrepiento, cosas que me gustaría mejorar/arreglar y posibilidades futuras.
cosas de las que me arrepiento
Como ya se mencionó, me decepcionó no haberme apegado a lo que consideraba un método más elegante para cambiar el estado de la aplicación y representarla en el DOM. El patrón del observador, como se discutió en la segunda parte de esta serie, que resolvió tantos problemas de una manera predecible, finalmente se dejó de lado cuando "enviar" el proyecto se convirtió en una prioridad.
Al principio me avergonzaba mi código, pero en los meses siguientes me volví más filosófico. Si no hubiera utilizado más técnicas peatonales más adelante, existe una posibilidad muy real de que el proyecto nunca hubiera concluido. Sacar algo al mundo que necesita mejorar todavía se siente mejor que nunca haber nacido en el mundo.
Mejorar entrada/salida
Más allá de elegir el marcado semántico, no había hecho ningún lujo para la accesibilidad. Cuando creé In/Out, confiaba en la accesibilidad estándar de la página web, pero no tenía los conocimientos suficientes para abordar una aplicación. He hecho mucho más trabajo/investigación en esa área ahora, así que me gustaría tomarme el tiempo para hacer un trabajo decente para hacer que esta aplicación sea más accesible.
La implementación del diseño revisado de la funcionalidad 'Agregar persona' se apresuró. No es un desastre, sólo un poco más duro de lo que me gustaría. Sería bueno hacer ese impermeable.
Tampoco tuve en cuenta las pantallas más grandes. Sería interesante considerar los desafíos de diseño de hacer que funcione en tamaños más grandes, más allá de simplemente convertirlo en un tubo de contenido.
posibilidades
El uso de localStorage funcionó para mis necesidades simples, pero sería bueno tener un almacén de datos 'adecuado' para que no fuera necesario preocuparse por hacer una copia de seguridad de los datos. Agregar la capacidad de inicio de sesión también abriría la posibilidad de compartir la organización del juego con otra persona. ¿O tal vez cada jugador podría simplemente marcar si estaban jugando ellos mismos? Es increíble la cantidad de caminos que puedes explorar a partir de unos comienzos tan simples y humildes.
SwiftUI para el desarrollo de aplicaciones iOS también es intrigante. Para alguien que solo ha trabajado con lenguajes web, a primera vista, SwiftUI parece algo que ahora estoy animado a probar. Probablemente intentaría reconstruir In/Out con SwiftUI, solo para tener algo específico para construir y comparar la experiencia de desarrollo y los resultados.
Entonces, es hora de concluir y darle la versión TL; DR de todo esto.
Si desea aprender cómo funciona algo en la web, le sugiero que se salte las abstracciones. Deshazte de los marcos, ya sea CSS o JavaScript, hasta que realmente entiendas lo que están haciendo por ti.
El diseño es iterativo, adopte ese proceso.
Resuelva problemas en el medio de menor fidelidad a su disposición. No vaya al código si puede probar la idea en Sketch. No lo dibujes en Sketch si puedes usar lápiz y papel. Escriba la lógica primero. Luego escríbalo en código.
Sea realista, pero nunca desanimado. Desarrollar el hábito de trabajar en algo por tan solo 30 minutos al día puede dar resultados. Ese hecho es cierto cualquiera que sea la forma que adopte su búsqueda.