<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Juan Manuel Ruiz Fernández</title>
    <description>The latest articles on DEV Community by Juan Manuel Ruiz Fernández (@neovasili).</description>
    <link>https://dev.to/neovasili</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1174294%2Fca686599-6c15-47c4-86c7-ac37306d7361.jpeg</url>
      <title>DEV Community: Juan Manuel Ruiz Fernández</title>
      <link>https://dev.to/neovasili</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/neovasili"/>
    <language>en</language>
    <item>
      <title>Ahorrar costes de transferencia con instancias NAT gestionadas en AWS</title>
      <dc:creator>Juan Manuel Ruiz Fernández</dc:creator>
      <pubDate>Thu, 02 May 2024 08:20:11 +0000</pubDate>
      <link>https://dev.to/aws-espanol/ahorrar-costes-de-transferencia-con-instancias-nat-gestionadas-en-aws-492</link>
      <guid>https://dev.to/aws-espanol/ahorrar-costes-de-transferencia-con-instancias-nat-gestionadas-en-aws-492</guid>
      <description>&lt;p&gt;Una de las principales preocupaciones cuando utilizamos la tecnología cloud son los costes y en ciertos casos los costes de transferencia de datos hacia o desde AWS pueden convertirse en una parte significativa de nuestra factura.&lt;/p&gt;

&lt;p&gt;Este hecho se hace particularmente visible cuando utilizamos NAT Gateways y nuestras cargas de trabajo realizan muchas peticiones "hacia afuera", por ejemplo a otras APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NAT Gateway&lt;/strong&gt; es un servicio extraordinariamente potente y resiliente, pero dispone de un &lt;em&gt;pricing model&lt;/em&gt; que puede provocar fácilmente un aumento significativo de los costes de transferencia de datos, ya que &lt;strong&gt;se aplican cargos por cada GB procesado por cada NAT Gateway&lt;/strong&gt;, sin importar si se trata de tráfico de entrada o de salida.&lt;/p&gt;

&lt;p&gt;Sin embargo, usando instancias NAT (usando EC2), sólo incurrimos en costes de transferencia desde AWS hacia internet.&lt;/p&gt;

&lt;p&gt;En este post hablaremos de una solución que implementa el uso de instancias NAT gestionadas en lugar de NAT Gateway de una forma eficiente y resiliente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diseño de la solución
&lt;/h2&gt;

&lt;p&gt;El principal problema de utilizar instancias NAT está en que &lt;em&gt;movemos&lt;/em&gt; la gestión y el mantenimiento de estas instancias de AWS hacia nosotros. Por eso es preferible utilizar servicios 100% gestionados por AWS como NAT Gateway y considerar usar instancias NAT sólo cuando es necesario.&lt;/p&gt;

&lt;p&gt;La idea principal de esta solución es reducir a la mínima expresión la carga de trabajo requerida para realizar esa gestión y mantenimiento, automatizando la actualización regular de las instancias NAT y estableciendo mecanismos lo más automatizados posibles para realizar &lt;em&gt;Failover&lt;/em&gt; y &lt;em&gt;Fallback&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;De este modo, obtendremos una solución que una vez desplegada requerirá de muy poca atención y mantenimiento y que a su vez reducirá drásticamente nuestros costes de transferencia con respecto al uso de NAT Gateway.&lt;/p&gt;

&lt;p&gt;Veamos un diagrama general de la solución:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw0pxayib0dex1oiitpb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw0pxayib0dex1oiitpb.png" alt="Diagrama de solución Instancias NAT autogestionadas" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El diseño de esta solución se basa parcialmente en la que &lt;a href="https://medium.com/@benwhaley"&gt;Ben Whaley&lt;/a&gt; explica en el post &lt;em&gt;&lt;a href="https://medium.com/life-at-chime/how-we-reduced-our-aws-bill-by-seven-figures-5144206399cb"&gt;How we reduced our AWS bill by seven figures&lt;/a&gt;&lt;/em&gt;, aunque contiene algunos cambios significativos respecto a cómo se construyen las instancias NAT y a cómo son reemplazadas en caso de fallo o por mantenimiento.&lt;/p&gt;

&lt;p&gt;Desde un punto de vista general, la solución tiene cuatro partes perfectamente diferenciadas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline de creación de imágenes&lt;/strong&gt; - cómo las imágenes para las instancias NAT son creadas y distribuidas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursos NAT en funcionamiento&lt;/strong&gt; - las instancias NAT en sí mismo y al menos una NAT Gateway en &lt;em&gt;standby&lt;/em&gt; como backup.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;&lt;strong&gt;Connectivity checker&lt;/strong&gt;&lt;/em&gt; - funciones Lambda diseñadas para comprobar que la conectividad dentro de las subredes privadas en nuestra VPC sigue funcionando; también se encargan de activar el proceso de &lt;em&gt;Failover&lt;/em&gt; en caso de fallo y de emitir métricas sobre la conectividad.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;&lt;strong&gt;Workflows&lt;/strong&gt;&lt;/em&gt; - varias máquinas de estado encargadas de manejar el ciclo de vida de la solución.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el repositorio &lt;a href="https://github.com/neovasili/nat-instances"&gt;Nat instances&lt;/a&gt;, podréis encontrar una versión completa en CDK escrita en typescript de la solución aquí descrita.&lt;/p&gt;

&lt;p&gt;Ahora veamos un poco más en detalle cada parte de la solución.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pipeline de creación de imágenes
&lt;/h3&gt;

&lt;p&gt;Precisamos de un mecanismo confiable y seguro para producir nuevas imágenes para las instancias NAT actualizadas y sustituir las instancias en funcionamiento por unas que usen las imágenes nuevas.&lt;/p&gt;

&lt;p&gt;AWS Image Builder es un servicio autogestionado justo para ése propósito. Con él crearemos el pipeline de creación de imágenes NAT.&lt;/p&gt;

&lt;p&gt;Luego veremos cómo disparamos este pipeline desde la máquina de estados de mantenimiento a intervalos regulares.&lt;/p&gt;

&lt;p&gt;El pipeline hace tres cosas diferentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Construir la imagen&lt;/strong&gt; - cogemos la imagen base y aplicamos los cambios para convertirla en una instancia NAT (ver &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_NAT_Instance.html"&gt;documentación de AWS&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testear la imagen&lt;/strong&gt; - con la imagen creada, se crea una instancia que la usa y se realizan varios tests para asegurar que hace lo que tiene que hacer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribuir la imagen&lt;/strong&gt; - se crea una copia de la imagen creada final (y se aplican &lt;em&gt;Tags&lt;/em&gt;) en cada región que designemos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recursos NAT en funcionamiento
&lt;/h3&gt;

&lt;p&gt;Aparte de nuestras instancias NAT creadas y en funcionamiento, necesitaremos tener también NAT Gateways disponibles que actuarán como backup en caso de que las instancias NAT fallen y también para utilizarlas como "puente" durante las tareas de mantenimiento.&lt;/p&gt;

&lt;p&gt;El estado normal del sistema será que nuestras instancias NAT estarán emplazadas en las subredes públicas de nuestra VPC y las tablas de enrutamiento enviarán el tráfico saliente de las subredes privadas a las interfaces de red de las instancias, haciendo de este modo efectiva la traducción de direcciones de red.&lt;/p&gt;

&lt;p&gt;Durante las tareas de mantenimiento, el sistema cambiará este enrutamiento para usar las NAT Gateways mientras que las instancias NAT son reemplazadas por una nueva versión de las mismas para finalmente, volver a cambiar el enrutamiento a las instancias NAT una vez que estén disponibles para su uso.&lt;/p&gt;

&lt;p&gt;En caso de fallo de la conectividad de las instancias NAT, el sistema automáticamente cambia el enrutamiento a las NAT Gateways para que todo siga funcionando.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connectivity checker
&lt;/h3&gt;

&lt;p&gt;¿Y cómo detecta el sistema que la conectividad de las instancias NAT ha dejado de funcionar? Pues para eso tenemos este componente que hemos denominado &lt;em&gt;Connectivity checker&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;En esencia, la solución emplaza una función Lambda en cada subnet privada, la cual se ejecuta de forma periódica y comprueba la conectividad "hacia afuera" de nuestro sistema haciendo peticiones a urls que le proveemos.&lt;/p&gt;

&lt;p&gt;En cada ejecución, las funciones Lambda realizan las peticiones y si dichas peticiones fallan más de X veces (el umbral que definamos), el sistema considera que la conectividad está fallando y dispara el workflow de &lt;em&gt;Failover&lt;/em&gt;, que como veremos en la siguiente sección, es el encargado de enrutar usando las NAT Gateways.&lt;/p&gt;

&lt;p&gt;Un detalle interesante es que dado que las Lambdas están dentro de la red de nuestra VPC y que supuestamente la conectividad está fallando, necesitaremos tener VPC endpoints emplazados para poder "hablar" con el servicio &lt;em&gt;StepFunctions&lt;/em&gt;, sino, el &lt;em&gt;Connectivity checker&lt;/em&gt; no podrá disparar el &lt;em&gt;Failover&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflows
&lt;/h3&gt;

&lt;p&gt;Aquí es donde todo el sistema encierra la lógica que venimos describiendo en las secciones anteriores, esa orquestación y automatismo que nos ayudará a minimizar enormemente la gestión y el mantenimiento del sistema.&lt;/p&gt;

&lt;p&gt;Para orquestar todos estos procesos, hemos elegido StepFunctions y sus StateMachines utilizando siempre que sea posible la integración de StepFunctions con los diferentes servicios de AWS. De este modo, existe mucho menos código propio que mantener, ya que dichas integraciones son gestionadas y mantenidas por AWS.&lt;/p&gt;

&lt;p&gt;La solución define cuatro workflows en cuatro &lt;em&gt;StateMachines&lt;/em&gt; diferentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Failover&lt;/strong&gt;: es la encargada de reemplazar el enrutamiento para utilizar las NAT Gateways de backup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback&lt;/strong&gt;: realiza la operación contraria, reemplaza el enrutamiento para utilizar nuestras instancias NAT.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reemplazo de instancias NAT&lt;/strong&gt;: dispara el &lt;em&gt;Failover&lt;/em&gt;, y en paralelo elimina las instancias NAT actualmente en funcionamiento, mientras que provisiona nuevas instancias usando la última versión de las imágenes NAT creada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mantenimiento&lt;/strong&gt;: es la encargada de mantener actualizadas las instancias NAT, orquestando todos los pasos necesarios para hacerlo posible de forma segura y resiliente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Veamos más en detalle esta última &lt;em&gt;StateMachine&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  State Machine de mantenimiento
&lt;/h4&gt;

&lt;p&gt;La solución propone ejecutar este workflow de forma programada cada cierto tiempo (por ejemplo cada 14 días) para  asegurar que nuestras instancias NAT están debidamente actualizadas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9algzo6111p2e60g9wz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9algzo6111p2e60g9wz2.png" alt="Diagrama de State Machine de mantenimiento" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La idea es bastante simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crear una nueva versión de las imágenes de nuestras instancias NAT usando el &lt;strong&gt;Pipeline de creación de imágenes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Efectuar el reemplazo de instancias NAT disparando el workflow para ello.&lt;/li&gt;
&lt;li&gt;Disparar el &lt;em&gt;Fallback&lt;/em&gt; para empezar a utilizar las nuevas instancias.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Con la StateMachine, nos aseguramos de que cada paso es ejecutado de forma automática y controlando qué sucede si algo falla, evitando así que nuestra conectividad deje de funcionar durante este proceso.&lt;/p&gt;

&lt;p&gt;Además, gracias a StepFunctions, tenemos una forma muy visual de entender qué está sucediendo en cada momento y en caso de fallo dónde puede estar el problema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Hemos visto cómo utilizando varios servicios gestionados de AWS podemos llegar a una solución para automatizar el uso, gestión y mantenimiento de instancias NAT en lugar de NAT Gateways, reduciendo considerablemente los costes de transferencia de datos en sistemas donde se realizan gran cantidad de peticiones externas desde nuestras subredes privadas.&lt;/p&gt;

&lt;p&gt;En ese sentido, necesitaremos conocer nuestro &lt;em&gt;throughput&lt;/em&gt; máximo de red actual en el sistema para elegir un tamaño de las instancias NAT adecuado que permita preservar la mejora de costes pero que asegure el rendimiento del sistema.&lt;/p&gt;

&lt;p&gt;StepFunctions y sus integraciones con otros servicios de AWS juegan un papel fundamental en esta solución, ya que nos permiten reducir casi a cero todo el trabajo de gestión y mantenimiento de código propio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/neovasili/nat-instances"&gt;Repositorio nat-instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/life-at-chime/how-we-reduced-our-aws-bill-by-seven-figures-5144206399cb"&gt;How we reduced our AWS bill by seven figures&lt;/a&gt; por &lt;a href="https://medium.com/@benwhaley"&gt;Ben Whaley&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_NAT_Instance.html"&gt;Instancias NAT - documentación de AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/es/vpc/pricing/"&gt;Costes de NAT Gateways&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Agradecimientos a &lt;a href="https://twitter.com/gonzalocamarero"&gt;Gonzalo Camarero&lt;/a&gt; por su ayuda en la revisión del texto.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>costes</category>
      <category>nat</category>
      <category>cdk</category>
    </item>
    <item>
      <title>Estrategias para manejar dependencias entre stacks en CDK</title>
      <dc:creator>Juan Manuel Ruiz Fernández</dc:creator>
      <pubDate>Fri, 06 Oct 2023 10:38:51 +0000</pubDate>
      <link>https://dev.to/aws-espanol/estrategias-para-manejar-dependencias-entre-stacks-en-cdk-3bjj</link>
      <guid>https://dev.to/aws-espanol/estrategias-para-manejar-dependencias-entre-stacks-en-cdk-3bjj</guid>
      <description>&lt;p&gt;Es bastante fácil crear varios &lt;em&gt;stacks&lt;/em&gt; en CDK y compartir valores entre ellos (por ejemplo el &lt;strong&gt;VPC ID&lt;/strong&gt;), pero estas dependencias nos pueden crear muchos dolores de cabeza si no se gestionan adecuadamente.&lt;/p&gt;

&lt;p&gt;En este post hablaremos de las dependencias entre &lt;em&gt;stacks&lt;/em&gt;, los tipos que podemos encontrar, los problemas que pueden surgir y de varias estrategias que podemos seguir para manejarlas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencias entre stacks en CDK
&lt;/h2&gt;

&lt;p&gt;Podríamos decir que:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;las dependencias entre stacks en CDK surgen cuando se comparten uno o más valores entre uno o más stacks gestionados con CDK&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pongamos un ejemplo muy simple con un primer stack que contiene una VPC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleA&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IVpc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y un segundo stack, que recibe por parámetro una VPC que se utiliza para crear un grupo de seguridad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ExampleBProps&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IVpc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleB&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExampleBProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySecurityGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MySecurityGroup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entonces nuestra aplicación de CDK será algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stackA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExampleA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ExampleA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stackB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExampleB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ExampleB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stackA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Donde usamos la propiedad &lt;code&gt;vpc&lt;/code&gt; de A y las pasamos a B.&lt;/p&gt;

&lt;p&gt;Si atendemos al tipo de valores que podemos compartir entre &lt;em&gt;stacks&lt;/em&gt;, tenemos dependencias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministas&lt;/strong&gt;: donde el valor que compartimos es conocido o puede ser inferido o compuesto por otros valores conocidos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No deterministas&lt;/strong&gt;: donde a priori no conocemos los valores compartidos, generalmente IDs generados por AWS o CDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el ejemplo anterior tenemos una dependencia &lt;strong&gt;no determinista&lt;/strong&gt;, ya que a priori no sabemos el &lt;strong&gt;VPC ID&lt;/strong&gt;, que es el valor que estamos compartiendo.&lt;/p&gt;

&lt;p&gt;Aquí me gustaría señalar algo que probablemente ya sabéis, pero CDK sintetiza CloudFormation utilizando nuestro código y es éste código sintetizado de CloudFormation lo que se utiliza para desplegar.&lt;/p&gt;

&lt;p&gt;¿Por qué es esto importante? porque si sabemos cómo funciona CloudFormation, entenderemos mejor lo que está sucediendo con nuestro código.&lt;/p&gt;

&lt;p&gt;En el ejemplo anterior lo que pasamos de A a B es la propiedad &lt;code&gt;vpc&lt;/code&gt;, pero CDK selecciona sólo el &lt;strong&gt;VPC ID&lt;/strong&gt; porque es el valor que se necesita en el recurso de CloudFormation &lt;em&gt;SecurityGroup&lt;/em&gt; para especificar la VPC a la que pertenece y además la forma de "pasar" este valor entre A y B es creando un output de CloudFormation en A e importándolo en B, es decir, algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;A&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"Outputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ExportsOutputRefMyVpcF9F0CA6FBC8737E9"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MyVpcF9F0CA6F"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Export"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ExampleA:ExportsOutputRefMyVpcF9F0CA6FBC8737E9"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;B&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"Resources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"MySecurityGroupAC8D442C"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWS::EC2::SecurityGroup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"GroupDescription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ExampleB/MySecurityGroup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"SecurityGroupEgress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"CidrIp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow all outbound traffic by default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"IpProtocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-1"&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"VpcId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"Fn::ImportValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ExampleA:ExportsOutputRefMyVpcF9F0CA6FBC8737E9"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Además, si atendemos al origen de la dependencia, tenemos dependencias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Heredadas&lt;/strong&gt;: el valor exportado está en el stack “fuente” y el importado en el stack “destino” - es decir, el output estaría en A y el import en B.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflejadas&lt;/strong&gt;: el valor exportado está en el stack “destino” y el importado en el stack “fuente” - es decir, el output estaría en B y el import en A.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto significa que no siempre veremos el output en el stack "del que salen" los valores en nuestro código CDK. Podéis ver un ejemplo de una dependencia reflejada con estos dos &lt;em&gt;stacks&lt;/em&gt; &lt;a href="https://github.com/neovasili/cdk-day-2023-stacks-dependencies/blob/main/lib/stacks/03-cloudfront-example/stack-a.ts"&gt;stack-a&lt;/a&gt; y &lt;a href="https://github.com/neovasili/cdk-day-2023-stacks-dependencies/blob/main/lib/stacks/03-cloudfront-example/stack-b.ts"&gt;stack-b&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si tenemos por costumbre hacer &lt;code&gt;cdk diff&lt;/code&gt; conforme vamos haciendo nuestros cambios, podemos observar lo que sucede en CloudFormation. Otra opción es revisar directamente los &lt;em&gt;templates&lt;/em&gt; producidos en &lt;code&gt;cdk.out/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potenciales problemas con las dependencias
&lt;/h2&gt;

&lt;p&gt;Por norma general, cuando estamos creando una nueva dependencia no tendremos problemas salvo que estemos intentando introducir alguna dependencia cíclica, que es algo que deberíamos tratar de evitar siempre que sea posible.&lt;/p&gt;

&lt;p&gt;No obstante, sí que podemos encontrar problemas cuando intentamos actualizar alguno de los valores que estamos compartiendo o si intentamos eliminar una dependencia que ya no es necesario. ¿Por qué? &lt;/p&gt;

&lt;p&gt;Porque CDK tiene que establecer un orden a la hora de desplegar con los &lt;em&gt;stacks&lt;/em&gt; que son dependientes y salvo que le especifiquemos lo contrario, usará la "dirección" de la dependencia que definimos en nuestro código para establecer la jerarquía.&lt;/p&gt;

&lt;p&gt;En el ejemplo anterior B depende de A, por tanto la jerarquía es &lt;code&gt;A -&amp;gt; B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esto se traduce en que si &lt;strong&gt;eliminamos la dependencia existente&lt;/strong&gt;, CDK tratará de eliminar primero el output en A y luego la importación en B, pero CloudFormation fallará al tratar de eliminar el output en A porque sigue en uso en B:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flazj16hwbtu3ate6uu1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flazj16hwbtu3ate6uu1a.png" alt="CDK diff cuando tratamos de eliminar una dependencia existente donde CDK trata de eliminar el output de A antes que realizar los cambios en B" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En el caso de que &lt;strong&gt;intentemos actualizar una dependencia&lt;/strong&gt;, pasará algo parecido, puesto que tratará de actualizar un valor que está en uso o incluso puede que trate de eliminar el output original y crear uno nuevo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0l86vmt2ln3t88rhek4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0l86vmt2ln3t88rhek4.png" alt="CDK diff cuando tratamos de actualizar una dependencia existente donde CDK trata de eliminar el output existente y crear uno nuevo antes de realizar los cambios en B" width="800" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podríamos mitigar estos problemas haciendo despliegues parciales o desplegando manualmente en el orden correcto, pero aparte de los riesgos asociados a las operaciones manuales, puede que estos despliegues parciales no sean tan triviales, dependiendo de las dependencias que tengamos u otros cambios que hayamos acumulado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estrategias para manejar dependencias
&lt;/h2&gt;

&lt;p&gt;Considerando el anterior párrafo, podemos idear diferentes formas de gestionar estas dependencias que nos ayuden a evitar los problemas mencionados.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exportación manual de valores
&lt;/h3&gt;

&lt;p&gt;Como su propio nombre indica, en lugar de dejar que CDK cree los outputs y los imports automáticamente, podemos hacerlo nosotros de forma explícita, de esta forma, podemos decidir en el código cuándo actualizar o eliminar los valores según nos convenga.&lt;/p&gt;

&lt;p&gt;Para el ejemplo que veíamos al principio, para A sería algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExportingStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CfnOutput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VpcId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;exportName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVpcId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y en B tendríamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImportingStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImportingStackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVpcId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySecurityGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MySecurityGroup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta forma, en B estamos creando un &lt;em&gt;construct&lt;/em&gt; de una VPC usando el valor importado para poder usarla como si la VPC se hubiese creado en B.&lt;/p&gt;

&lt;p&gt;No obstante, al hacerlo así, CDK no sabe que existe una dependencia entre A y B, por lo que deberíamos hacerlo explícito nosotros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stackA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExportingStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ExampleA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stackB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ImportingStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ExampleB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stackA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;stackB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addDependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stackA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Qué PROs y Contras tiene esta estrategia?&lt;/p&gt;

&lt;p&gt;Pues entre los PROs podemos considerar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Los exports e imports se hacen explícitos&lt;/strong&gt; - lo que antes sólo se podía ver en las templates generadas de CloudFormation ahora está en el código.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evita los problemas de eliminación o actualización de dependencias&lt;/strong&gt; - ya que podemos controlar el ciclo de vida de exports e imports de forma independiente, podríamos primero cambiar unos y luego los otros, evitando así los problemas mencionados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Puede ayudar a mitigar problemas de dependencias ya existentes&lt;/strong&gt; - podemos hacer explícitos exports ya existentes y así controlar su ciclo de vida; eso sí, necesitaremos utilizar exactamente los mismos IDs que ya existen en CloudFormation, para que CDK considere que son los mismos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y ¿qué Contras tenemos?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Require importación y exportación manual&lt;/strong&gt; - añade más código y por ende requiere de más mantenimiento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Puede requerir &lt;code&gt;addDepedency&lt;/code&gt; manual&lt;/strong&gt; - en la mayoría de los casos necesitaremos explicitar la dependencia entre &lt;em&gt;stacks&lt;/em&gt; manualmente con el &lt;code&gt;addDependency&lt;/code&gt; que veíamos antes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Los nombres de los exports son únicos por cuenta-región&lt;/strong&gt; - esto implica que tenemos que evitar las colisiones de nombres de forma manual, usando un inventario o bien convenios de nombres.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Código estático
&lt;/h3&gt;

&lt;p&gt;Se trata de usar métodos y/o valores estáticos definidos en un lugar concreto para compartirlos entre &lt;em&gt;stacks&lt;/em&gt; usando el código. Pongamos un ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommonStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpcName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyEcsCluster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;clusterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CommonStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEcsClusterName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getEcsClusterName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-cluster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getEcsCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ICluster&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Vpc`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpcName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromClusterAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;clusterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEcsClusterName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y en B tendríamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewServiceStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CommonStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEcsCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyCluster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;taskDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateTaskDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyTask&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;taskDefinition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyApp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RepositoryImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEcrRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;ecr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromRepositoryName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyAppEcrRepo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyEcsService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;taskDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;desiredCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando los valores a compartir son valores estáticos, constantes o pueden ser compuestos por valores conocidos, resulta trivial utilizar una solución donde, usando las características del lenguaje, creamos los elementos necesarios para compartir información sin necesidad de exportar ni importar nada.&lt;/p&gt;

&lt;p&gt;En este ejemplo, estamos creando métodos estáticos en A para crear &lt;em&gt;constructs&lt;/em&gt; CDK para un scope pasado por parámetro usando &lt;em&gt;constructs&lt;/em&gt; importados (&lt;code&gt;fromLookup&lt;/code&gt; y &lt;code&gt;fromClusterAttributes&lt;/code&gt;), de esta forma, podemos instanciar fácilmente estos recursos en otros &lt;em&gt;stacks&lt;/em&gt; y operar con ellos como si se hubiesen creado en los &lt;em&gt;stacks&lt;/em&gt; consumidores.&lt;/p&gt;

&lt;p&gt;En lo relativo a PROs y CONs, tenemos como PROs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Al igual que antes, &lt;strong&gt;evitamos los problemas&lt;/strong&gt; de eliminar o actualizar dependencias.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Es más natural para el código de nuestra aplicación CDK&lt;/strong&gt; - en B, podemos ver de forma explícita en el código que la instancia del cluster proviene de A y en B no necesitamos preocuparnos por los detalles de cómo se obtuvo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evita los exports e imports de CloudFormation&lt;/strong&gt; - en este caso no se necesitan los outputs de CloudFormation, en B se utilizarán en la mayoría de los casos directamente los valores que se necesiten.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aporta un motivo para la creación de librerías CDK&lt;/strong&gt; - podemos de forma sencilla llevar las partes comunes más reutilizables a una librería y poder compartir ese código entre otras aplicaciones CDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En cuanto los Contras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Puede requerir &lt;code&gt;addDepedency&lt;/code&gt; manual&lt;/strong&gt; - en la mayoría de los casos necesitaremos explicitar la dependencia entre &lt;em&gt;stacks&lt;/em&gt; manualmente con el &lt;code&gt;addDependency&lt;/code&gt; que veíamos antes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La creación de estos “constructs importados” a veces no es trivial&lt;/strong&gt;- aunque CDK provee de muchas funciones tipo &lt;code&gt;fromXXXX&lt;/code&gt; y &lt;code&gt;lookups&lt;/code&gt; que nos ayudan mucho con esto, a veces puede ocurrir que necesitemos valores que a priori no disponemos de ellos fácilmente y puede requerir adaptar nuestro código para obtenerlos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Uso de parámetros SSM
&lt;/h3&gt;

&lt;p&gt;Esta estrategia es muy similar a la de "exportación manual", pero en lugar de usar outputs de CloudFormation, usaremos parámetros SSM, ya que éstos no crean una dependencia rígida en CloudFormation y además nos permite exponer estos valores a fuentes externas, como otras aplicaciones CDK o el backend de nuestros &lt;em&gt;workloads&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Además, CloudFormation acepta SSM como parámetros de &lt;em&gt;stacks&lt;/em&gt;, y es así como CDK "traduce" esta aproximación para CloudFormation, haciendo que la dependencia también esté en CloudFormation de forma explícita.&lt;/p&gt;

&lt;p&gt;Si tomamos el ejemplo de la estrategia de exportación manual y lo modificamos un poco (podemos aprovechar también para mezclarla con la segunda estrategia) quedaría algo así para el stack A:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NetworkStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;managementSecurityGroupIdSSM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IStringParameter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StringParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VPCIdSSM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;parameterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NetworkStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVpcIdSSMParamName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;stringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getVpcIdSSMParamName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/network/vpc/id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getVpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IVpc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpcIdSSM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringParameter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromStringParameterName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;VPCId`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;NetworkStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVpcIdSSMParamName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpcIdSSM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y para el stack B:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NetworkStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySecurityGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MySecurityGroup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En cuanto a nuestra comparativa, como PROs, podemos señalar, todas las ventajas de los métodos anteriores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Los valores compartidos &lt;strong&gt;se puede leer fácilmente desde otras fuentes&lt;/strong&gt; - es decir, al estar almacenados en SSM, estos valores se podrían leer desde otras aplicaciones no necesariamente en CDK o incluso desde el código de nuestras cargas de trabajo; este sin duda es el mayor beneficio de usar SSM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y en los Contras, básicamente, podemos encontrar casi los mismos que veíamos en las estrategias anteriores y al mismo tiempo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Es fácil perder la trazabilidad de quien está consumiendo los parámetros SSM&lt;/strong&gt; - dado que es fácil consumirlos desde fuentes externas, resulta difícil saber si ya no están en uso, habría que analizar las llamadas a la API y tener muy controladas las políticas de acceso.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Referencias dinámicas de CloudFormation
&lt;/h3&gt;

&lt;p&gt;Por último, vamos a hablar de otra estrategia que es básicamente una evolución de la anterior: el uso de referencias dinámicas a parámetros SSM de CloudFormation.&lt;/p&gt;

&lt;p&gt;Modificamos el ejemplo anterior, en A cambiamos el método &lt;code&gt;getVpc&lt;/code&gt; y añadimos uno nuevo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getReferenceFromSSMParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;ssmParameterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ssmParameterVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnDynamicReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CfnDynamicReferenceService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SSM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ssmParameterName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ssmParameterVersion&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;getVpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IVpc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpcId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CoreStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReferenceFromSSMParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NetworkStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVpcIdSSMParamName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromVpcAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;availabilityZones&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eu-west-1a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eu-west-1b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eu-west-1c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y B permanecería exactamente igual.&lt;/p&gt;

&lt;p&gt;El nuevo método que hemos añadido &lt;code&gt;getReferenceFromSSMParameter&lt;/code&gt;, básicamente es el encargado de crear la referencia dinámica usando el nombre del parámetro SSM y su versión, lo que en CloudFormation sería algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{resolve:ssm:/network/vpc/id:1}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta referencia se resolverá en tiempo de despliegue de CloudFormation y nos permite además consumir una versión específica de un parámetro SSM aportando un grado extra de control en el ciclo de vida de estas dependencias.&lt;/p&gt;

&lt;p&gt;Entre los PROs, vemos todos los mismos que tenía el método de los parámetros SSM y además:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Evita los lookups durante la sintetización&lt;/strong&gt; - usando parámetros SSM CDK comprobará que los parámetros existen o forman parte de la aplicación CDK y puede que haga llamadas a la API de AWS al sintetizar las templates de CloudFormation antes del despliegue, con los parámetros dinámicos esto sucede en tiempo de despliegue, reduciendo el tiempo de sintetización y por ende acortando tiempos de desarrollo y testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permite un control del ciclo de vida de las dependencias mucho más exhaustivo&lt;/strong&gt; - al usar la versión concreta del parámetro SSM, podemos tener &lt;em&gt;stacks&lt;/em&gt; que sólo actualizan a una versión nueva del valor cuando realmente lo necesitan, no antes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Con los Contras, también vemos todos los mismos que tenía el método de los parámetros SSM y además:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requiere la gestión de versiones de los parámetros SSM&lt;/strong&gt; - esto es un arma de doble filo porque si bien representa un beneficio, también añade un extra de esfuerzo en el mantenimiento. Podríamos no especificar la versión, pero entonces CloudFormation calcula la última disponible en el momento del despliegue y nunca detectará un cambio a no ser que explícitamente cambiemos la referencia y usemos una versión determinada.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Hemos visto qué y cómo son las dependencias entre &lt;em&gt;stacks&lt;/em&gt; así como cuatro diferentes estrategias para combatir los posibles problemas inherentes a las mismas.&lt;/p&gt;

&lt;p&gt;Como recomendación final, no os quedéis con una estrategia concreta, utilizad aquellas que más os convengan según la situación, mezcladlas con otras estrategias o prescindid de todas ellas si vuestro caso de uso no tiene la complejidad suficiente.&lt;/p&gt;

&lt;p&gt;Se trata de encontrar el equilibrio adecuado para cada caso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/cdk/api/v2/"&gt;AWS CDK documentación oficial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html"&gt;CloudFormation outputs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html"&gt;CloudFormation import values&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html"&gt;CloudFormation stack parameters&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html"&gt;CloudFormation dynamic references&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/neovasili/cdk-day-2023-stacks-dependencies"&gt;GitHub repository con códigos de ejemplo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Agradecimientos a &lt;a href="https://twitter.com/gonzalocamarero"&gt;Gonzalo Camarero&lt;/a&gt; por su ayuda en la revisión del texto.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>infrastructureascode</category>
      <category>iac</category>
    </item>
  </channel>
</rss>
