Back home

Swift Package Manager Series 03 | Conceptos clave en Package.swift

Lo realmente difícil es comprender qué significan los productos, los objetivos y las dependencias en los límites del proyecto.

Cuando abra Package.swift por primera vez, su primera impresión será: el archivo no es largo y la sintaxis no es complicada.

Pero es fácil confundirse una vez que realmente comienzas el proyecto, porque la dificultad no está en absoluto en “si la sintaxis se parece a Swift”, sino en el hecho de que varios conceptos centrales en realidad corresponden a la estructura del proyecto, no a elementos de configuración ordinarios.

Si lo considera simplemente como una “lista para completar algunos campos”, a menudo sentirá que conoce cada palabra, pero fácilmente se volverá confuso cuando la cambie. Lo que realmente hay que entender es qué preguntas responden estos conceptos.

Lo más importante es capturar primero estos roles centrales:

  • paquete
  • productos
  • dependencias
  • objetivos

1. Package.swift describe las relaciones de los módulos

Este es el primer paso para entenderlo.

Una situación común es que inconscientemente piensas en ello como:

-Archivo de configuración del proyecto

  • Depende de los archivos de instalación
  • o “Podspec para Swift”

Pero desde una perspectiva de ingeniería, Package.swift se parece más a una especificación de relación de módulo. Le está diciendo a la cadena de herramientas:

  • ¿Qué aporta este paquete al mundo exterior?
  • ¿De qué paquetes externos depende?
  • ¿De qué objetivos se componen internamente?
  • Cómo se relacionan estos objetivos entre sí

Por lo tanto, se centra en “cómo este código debe organizarse en módulos y ser utilizado por otros”.

2. products responde: ¿Qué capacidades quiere brindar este paquete al mundo exterior?

Este es el punto que más fácilmente se pasa por alto cuando se trata inicialmente de este tipo de problema.

target es la unidad de construcción interna y product es el resultado consumible externo.

En otras palabras, la pregunta respondida por product es:

¿Qué pretende en última instancia este paquete exponer a sus usuarios?

Detrás de esto hay una señal de diseño muy importante. Si no tiene idea acerca de product, es fácil confundir la estructura interna del paquete con su uso externo.

Por supuesto, puede haber múltiples objetivos dentro de un paquete, pero el exterior no necesariamente necesita conocer todas estas divisiones internas. Entonces, product básicamente empaqueta la interfaz externa.

Si lo entiendes desde esta perspectiva, pensarás con mayor naturalidad:

  • ¿Qué objetivos internos son detalles de implementación?
  • ¿Qué habilidades es realmente necesario exponer?
  • ¿Qué nivel deberían ver los dependientes externos?

3. dependencies responde: ¿Qué capacidades toma prestado este paquete del mundo exterior?

Cuando vi esta situación dependencies, pensé en “instalar una biblioteca de terceros”.

Pero desde una perspectiva de ingeniería, su significado más importante es:

Fuera de los límites de este módulo, ¿de qué mundo externo depende?

Esto afectará directamente:

  • ¿El módulo es lo suficientemente iluminado?
  • ¿Es caro compilarlo?
  • ¿Es fácil de reutilizar en el futuro?
  • ¿También vinculará el proyecto anfitrión a algunas dependencias externas?

Si un módulo tiene demasiadas dependencias externas, a menudo causará dos problemas:

  • Ya no es liviano
  • Sus límites también empiezan a volverse confusos.

Entonces, cuando mire dependencies, no piense solo en “se puede instalar”, sino también en “por qué este módulo necesita depender de estas cosas”.

4. targets responde: ¿Cómo se debe organizar y compilar el código interno?

Esta es la parte de Package.swift que se considera más fácilmente como “mapeo de carpetas”, pero en realidad es mucho más que esto.

target realmente corresponde a:

  • Un grupo de códigos que se compilan juntos.
  • Una unidad de dependencia explícita
  • un límite de módulo interno

Cuando defines el objetivo, estás decidiendo:

  • ¿Qué códigos deberían evolucionar juntos?
  • Qué implementaciones deben colocarse en la misma unidad de compilación.
  • ¿Qué pruebas deberían corresponder a este límite?

Entonces Target es una de las unidades portadoras más pequeñas de modularidad interna.

Si rompes el objetivo en demasiados pedazos, el proyecto se volverá más pesado. Si el objetivo se hace demasiado grande, los límites se difuminarán. Esto también muestra que Package.swift parece ser solo una configuración, pero en realidad conlleva muchos juicios arquitectónicos.

5. Confundir product con target

Porque en paquetes simples, a menudo se corresponden uno a uno.

Por ejemplo:

  • un objetivo
  • un producto de biblioteca

En este momento, es fácil pensar erróneamente que los dos conceptos son similares. Pero una vez que el proyecto se vuelve un poco más complicado, encontrarás:

  • Un paquete puede tener múltiples objetivos.
  • Múltiples objetivos pueden servir un producto
  • Algunos objetivos son solo implementaciones internas y no deben exponerse directamente

Entonces mi experiencia es: **Entender destino como la estructura interna y producto como la salida externa. **

De esta manera el pensamiento se volverá mucho más claro de inmediato.

6. El objetivo de la prueba también es muy importante

Cuando vea Package.swift por primera vez, considerará el objetivo de prueba como una configuración de accesorios. Pero desde la perspectiva del pensamiento modular, en realidad es muy importante.

Debido a que el valor de un módulo no merece una existencia independiente, también se refleja en gran medida en:

  • ¿Se puede probar de forma independiente?
  • Si sus límites de dependencia son lo suficientemente claros
  • Si puede verificar el comportamiento principal sin depender de la aplicación host

Si un módulo tiene que depender de la mitad del proyecto host para cada prueba, aunque sea un paquete en nombre, los límites pueden no ser independientes de hecho.

7. Un orden de lectura más práctico

Si abro Package.swift para un proyecto desconocido por primera vez, normalmente lo miro en este orden:

1.products Veamos primero lo que expone al mundo exterior. 2. dependencies Veamos lo que tomó prestado del mundo exterior. 3. targets Por último, veamos cómo se desmonta el interior.

Los beneficios de esta secuencia son: Mire primero los límites y luego mire hacia adentro, en lugar de empantanarse en los detalles de implementación.

8. Conclusión: La dificultad de Package.swift no está en la sintaxis, sino en que realmente describe los límites del proyecto.

Para decirlo en forma más breve, diría:

Package.swift Lo más importante es si puede comprender la relación de límites detrás de product, dependency y target.

Una vez entendido desde esta perspectiva, este archivo ya no es sólo una configuración, sino una expresión condensada del diseño del módulo.

FAQ

What to read next

Related

Continue reading