Control de código fuente (Compilar aplicaciones en la nube del mundo real con Azure)

por Rick Anderson, Tom Dykstra

Descargar proyecto Fix It o Descargar libro electrónico

El libro electrónico Compilar aplicaciones en la nube del mundo real con Azure se basa en una presentación desarrollada por Scott Guthrie. Explica 13 patrones y prácticas que pueden ayudarle a tener éxito en el desarrollo de aplicaciones web para la nube. Para obtener información sobre el libro electrónico, consulte el primer capítulo.

El control de código fuente es esencial para todos los proyectos de desarrollo en la nube, no solo para entornos de equipo. No pensaría en editar el código fuente o incluso un documento de Word sin una función de deshacer y copias de seguridad automáticas, y el control de código fuente proporciona esas funciones en un nivel de proyecto donde pueden ahorrar aún más tiempo cuando algo va mal. Con los servicios de control de código fuente en la nube, ya no tiene que preocuparse por la configuración complicada y puede usar el control de código fuente de Azure Repos gratuito para hasta 5 usuarios.

En la primera parte de este capítulo se explican tres procedimientos recomendados clave que se deben tener en cuenta:

En el resto del capítulo se proporcionan algunas implementaciones de ejemplo de estos patrones en Visual Studio, Azure y Azure Repos:

Tratar los scripts de automatización como código fuente

Cuando trabaja en un proyecto en la nube, cambia cosas con frecuencia y quiere poder reaccionar con rapidez a los problemas que le comunican sus clientes. Responder rápidamente implica el uso de scripts de automatización, como se explica en el capítulo Automatizar todo. Todos los scripts que se usan para crear el entorno, implementarlos en él, escalarlos, etc., deben estar sincronizados con el código fuente de la aplicación.

Para mantener los scripts sincronizados con el código, almacénelos en el sistema de control de código fuente. Después, si alguna vez necesita revertir los cambios o realizar una corrección rápida al código de producción que es diferente del código de desarrollo, no tiene que perder tiempo intentando realizar un seguimiento de qué configuración ha cambiado o qué miembros del equipo tienen copias de la versión que necesita. Tiene la seguridad de que los scripts que necesita están sincronizados con la base de código para la que los necesita, y tiene la tranquilidad de que todos los miembros del equipo trabajan con los mismos scripts. A continuación, si necesita automatizar las pruebas y la implementación de una corrección activa en producción o desarrollo de nuevas características, tendrá el script adecuado para el código que debe actualizarse.

No insertar secretos en el repositorio

Normalmente, un repositorio de código fuente es accesible para demasiadas personas para que sea un lugar seguro adecuado para datos confidenciales, como contraseñas. Si los scripts dependen de secretos como contraseñas, parametrice esos valores para que no se guarden en el código fuente y almacene los secretos en otro lugar.

Por ejemplo, Azure permite descargar archivos que contienen los valores de publicación para automatizar la creación de perfiles de publicación. Estos archivos incluyen nombres de usuario y contraseñas que están autorizados para administrar los servicios de Azure. Si usa este método para crear perfiles de publicación e inserta estos archivos en el control de código fuente, cualquier persona con acceso al repositorio puede ver esos nombres de usuario y contraseñas. Puede almacenar de forma segura la contraseña en el propio perfil de publicación porque está cifrada y se encuentra en un archivo .pubxml.user que de forma predeterminada no se incluye en el control de código fuente.

Estructurar ramas de origen para facilitar el flujo de trabajo de DevOps

La forma en que implementa ramas en el repositorio afecta a la capacidad de desarrollar nuevas características y corregir problemas en producción. Este es un patrón que usan muchos equipos de tamaño mediano:

Source branch structure

La rama principal siempre coincide con el código que está en producción. Las ramas debajo de principal corresponden a diferentes fases del ciclo de vida de desarrollo. La rama de desarrollo es donde se implementan nuevas características. En el caso de un equipo pequeño, es posible que solo tenga principal y desarrollo, pero a menudo se recomienda tener una rama de almacenamiento provisional entre el desarrollo y la principal. Puede usar el almacenamiento provisional para las pruebas de integración finales antes de mover una actualización a producción.

En el caso de los grandes equipos, puede haber ramas independientes para cada nueva característica; para un equipo más pequeño, es posible que todos los usuarios inserten contenido en la rama de desarrollo.

Si tiene una rama para cada característica, cuando la característica A esté lista, combine su código fuente hacia arriba en la rama de desarrollo y hacia abajo en las otras ramas de características. Este proceso de combinación de código fuente puede llevar mucho tiempo y evitar ese trabajo mientras mantiene separadas las características. Algunos equipos implementan una alternativa denominada activación/desactivación de funcionalidad (también conocida como marcas de características). Esto significa que todo el código de todas las características está en la misma rama, pero puede habilitar o deshabilitar cada característica mediante modificadores en el código. Por ejemplo, supongamos que la característica A es un nuevo campo para las tareas de la aplicación Fix It y la característica B agrega funcionalidad de almacenamiento en caché. El código de ambas características puede estar en la rama de desarrollo, pero la aplicación solo mostrará el nuevo campo cuando una variable esté establecida en true y solo usará el almacenamiento en caché cuando una variable diferente esté establecida en true. Si la característica A no está lista para promocionarse, pero la característica B está lista, puede promover todo el código a Producción con el interruptor Característica A desactivado y el interruptor Característica B activado. A continuación, puede finalizar la característica A y promocionarla más adelante, todo sin combinación de código fuente.

Tanto si usa ramas como alternancias para características, una estructura de ramas como esta le permite fluir el código de desarrollo a producción de forma ágil y repetible.

Esta estructura también le permite reaccionar rápidamente a los comentarios de los clientes. Si necesita realizar una corrección rápida en producción, también puede hacerlo de forma eficaz y ágil. Puede crear una rama fuera de principal o almacenamiento provisional y, cuando esté lista, combinarla con principal y con las ramas de desarrollo y características.

Hotfix branch

Sin una estructura de ramas como esta, con su separación de ramas de producción y desarrollo, un problema de producción podría ponerle en la posición de tener que promover el nuevo código de características junto con la corrección de producción. Es posible que el nuevo código de característica no esté totalmente probado ni listo para producción y que tenga que realizar muchas tareas de respaldo de los cambios que no están listos. O bien, es posible que tenga que retrasar la corrección para probar los cambios y prepararlos para implementarlos.

A continuación, verá ejemplos de cómo implementar estos tres patrones en Visual Studio, Azure y Azure Repos. Estos son ejemplos en lugar de instrucciones detalladas paso a paso; para obtener instrucciones detalladas que proporcionen todo el contexto necesario, consulte la sección Recursos al final del capítulo.

Agregar scripts al control de código fuente en Visual Studio

Puede agregar scripts al control de código fuente en Visual Studio incluyéndolas en una carpeta de soluciones de Visual Studio (suponiendo que el proyecto esté en el control de código fuente). Esta es una manera de hacerlo.

Cree una carpeta para los scripts en la carpeta de la solución (la misma carpeta que tiene el archivo .sln).

Automation folder

Copie los archivos de script en la carpeta.

Automation folder contents

En Visual Studio, agregue una carpeta de solución al proyecto.

New Solution Folder menu selection

Y agregue los archivos de script a la carpeta de la solución.

Add Existing Item menu selection

Add Existing Item dialog box

Los archivos de script ahora se incluyen en el proyecto y el control de código fuente está realizando el seguimiento de los cambios de versión junto con los cambios de código fuente correspondientes.

Almacenamiento de datos confidenciales en Azure

Si ejecuta la aplicación en un sitio web de Azure, una manera de evitar almacenar credenciales en el control de código fuente es almacenarlas en Azure en su lugar.

Por ejemplo, la aplicación Fix It almacena en su archivo Web.config dos cadenas de conexión que tendrán contraseñas en producción y una clave que proporciona acceso a la cuenta de almacenamiento de Azure.

<connectionStrings>
  <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\MyFixItMembership.mdf;Initial Catalog=MyFixItMembership;Integrated Security=True" providerName="System.Data.SqlClient" />
  <add name="appdb" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\MyFixItTasks.mdf;Initial Catalog=aspnet-MyFixItTasks;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
  <add key="webpages:Version" value="3.0.0.0" />
  <add key="webpages:Enabled" value="false" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  <add key="StorageAccountName" value="fixitdemostorage" />
  <add key="StorageAccountAccessKey" value="[accesskeyvalue]" />
</appSettings>

Si coloca valores de producción reales para estos valores en el archivo Web.config, o si los coloca en el archivo Web.Release.config para configurar una transformación de Web.config para insertarlos durante la implementación, se almacenarán en el repositorio de origen. Si introduce las cadenas de conexión de la base de datos en el perfil de publicación de producción, la contraseña estará en el archivo .pubxml. (Puede excluir el archivo .pubxml del control de código fuente, pero luego pierde la ventaja de compartir todos los demás valores de implementación).

Azure le ofrece una alternativa para las secciones appSettings y cadena de conexión del archivo Web.config. Esta es la parte pertinente de la pestaña Configuración de un sitio web en el Portal de administración de Azure:

appSettings and connectionStrings in portal

Al implementar un proyecto en este sitio web y ejecutar la aplicación, los valores que haya almacenado en Azure invalidan los valores que se encuentren en el archivo Web.config.

Puede establecer estos valores en Azure mediante el portal de administración o los scripts. El script de automatización de la creación del entorno que vio en el capítulo Automatización de todo crea una instancia de Azure SQL Database, obtiene el almacenamiento y las cadenas de conexión de SQL Database y almacena estos secretos en los valores del sitio web.

# Configure app settings for storage account and New Relic
$appSettings = @{ `
    "StorageAccountName" = $storageAccountName; `
    "StorageAccountAccessKey" = $storage.AccessKey; `
    "COR_ENABLE_PROFILING" = "1"; `
    "COR_PROFILER" = "{71DA0A04-7777-4EC6-9643-7D28B46A8A41}"; `
    "COR_PROFILER_PATH" = "C:\Home\site\wwwroot\newrelic\NewRelic.Profiler.dll"; `
    "NEWRELIC_HOME" = "C:\Home\site\wwwroot\newrelic" `
}
# Configure connection strings for appdb and ASP.NET member db
$connectionStrings = ( `
    @{Name = $sqlAppDatabaseName; Type = "SQLAzure"; ConnectionString = $sql.AppDatabase.ConnectionString}, `
    @{Name = "DefaultConnection"; Type = "SQLAzure"; ConnectionString = $sql.MemberDatabase.ConnectionString}
)

Observe que los scripts se parametrizan para que los valores reales no se conserven en el repositorio de origen.

Cuando se ejecuta localmente en el entorno de desarrollo, la aplicación lee el archivo Web.config local y el cadena de conexión apunta a una base de datos de SQL Server de LocalDB en la carpeta App_Data del proyecto web. Al ejecutar la aplicación en Azure y cuando la aplicación intenta leer estos valores desde el archivo Web.config, lo que devuelve y usa son los valores almacenados para el sitio web, no lo que realmente está en el archivo Web.config.

Uso de Git en Visual Studio y Azure DevOps

Puede usar cualquier entorno de control de código fuente para implementar la estructura de ramas de DevOps presentada anteriormente. En el caso de los equipos distribuidos, un sistema de control de versiones distribuido (DVCS) podría funcionar mejor; para otros equipos, un sistema centralizado será la mejor opción.

Git es un sistema de control de versiones distribuido popular. Al usar Git para el control de código fuente, tiene una copia completa del repositorio con todo su historial en el equipo local. Muchas personas prefieren eso porque es más fácil seguir trabajando cuando no está conectado a la red: puede seguir realizando confirmaciones y reversiones, crear y cambiar ramas, etc. Incluso cuando está conectado a la red, es más fácil y rápido crear ramas y cambiar ramas cuando todo es local. También puede realizar confirmaciones y reversiones locales sin tener un impacto en otros desarrolladores. Y puede realizar confirmaciones por lotes antes de enviarlos al servidor.

Azure Repos ofrece Git y Control de versiones de Team Foundation (TFVC; control de código fuente centralizado). Empiece con Azure DevOps aquí.

Visual Studio 2017 incluye compatibilidad con Git integrada de primera clase. Esta es una demo rápida de cómo funciona eso.

Con un proyecto abierto en Visual Studio, haga clic con el botón derecho en el Explorador de soluciones y elija Agregar solución al control de código fuente.

Add Solution to Source Control

Visual Studio pregunta si desea usar TFVC (control de versiones centralizado) o Git.

Choose Source Control

Al seleccionar Git y hacer clic en Aceptar, Visual Studio crea un nuevo repositorio Git local en la carpeta de la solución. El nuevo repositorio aún no tiene archivos. Para agregarlos al repositorio, realice una confirmación de Git. Haga clic con el botón derecho en el Explorador de soluciones y seleccione Confirmar.

Commit

Visual Studio almacena automáticamente fases de todos los archivos del proyecto para la confirmación y los enumera en Team Explorer, en el panel Cambios incluidos. (Si hubiera algunos que no quisiera incluir en la confirmación, podría seleccionarlos, hacer clic con el botón derecho y hacer clic en Excluir.)

Team Explorer

Escriba un comentario de confirmación y haga clic en Confirmar y Visual Studio ejecutará la confirmación y mostrará el id. de confirmación.

Team Explorer Changes

Ahora, si cambia algo de código para que sea diferente de lo que hay en el repositorio, puede ver fácilmente las diferencias. Haga clic con el botón derecho en un archivo que haya cambiado, seleccione Comparar con la versión no modificada y verá una comparación que muestra el cambio pendiente de confirmación.

Compare with Unmodified

Diff showing changes

Puede ver fácilmente qué cambios está realizando y comprobarlos.

Supongamos que necesita crear una rama; también puede hacerlo en Visual Studio. En Team Explorer, haga clic en Nueva rama.

Team Explorer New Branch - Image 1

Escriba un nombre de rama, haga clic en Crear rama y, si seleccionó Desproteger rama, Visual Studio extraerá del repositorio automáticamente la nueva rama.

Team Explorer New Branch - Image 2

Ahora puede realizar cambios en los archivos y protegerlos en esta rama. Además, puede cambiar fácilmente entre ramas y Visual Studio sincroniza automáticamente los archivos con la rama que haya desprotegido. En este ejemplo, el título de la página web de _Layout.cshtml se ha cambiado a "Corrección activa 1" en la rama HotFix1.

Hotfix1 branch

Si vuelve a la rama principal, el contenido del archivo _Layout.cshtml vuelve automáticamente a lo que está en la rama principal.

main branch

Este es un ejemplo sencillo de cómo crear rápidamente una rama y pasar de una rama a otra. Esta característica permite un flujo de trabajo muy ágil mediante la estructura de ramas y los scripts de automatización presentados en el capítulo Automatizar todo. Por ejemplo, puede trabajar en la rama Desarrollo, crear una rama de corrección activa fuera de la principal, cambiar a la nueva rama, realizar los cambios allí y confirmarlos y, a continuación, volver a la rama Desarrollo y continuar lo que estaba haciendo.

Lo que ha visto aquí es cómo trabajar con un repositorio Git local en Visual Studio. En un entorno de equipo, normalmente también inserta cambios en un repositorio común. Las herramientas de Visual Studio también le permiten apuntar a un repositorio de Git remoto. Puede usar GitHub.com para ese propósito, o bien puede usar Git y Azure Repos integrados con todas las demás funcionalidades de Azure DevOps, como el elemento de trabajo y el seguimiento de errores.

Esta no es la única manera de implementar una estrategia de ramas ágil, por supuesto. Puede habilitar el mismo flujo de trabajo ágil mediante un repositorio de control de código fuente centralizado.

Resumen

Mida el éxito del sistema de control de código fuente en función de la rapidez con la que puede realizar un cambio y publicarlo de forma segura y predecible. Si tiene miedo de hacer un cambio porque tiene que probarlo manualmente durante uno o dos días, pregúntese qué tiene que hacer en cuanto a procesos o pruebas para poder hacer ese cambio en cuestión de minutos o, en el peor de los casos, en menos de una hora. Una estrategia para hacerlo es implementar la integración continua y entrega continua, que trataremos en el siguiente capítulo.

Recursos

Para obtener más información acerca de las estrategias de rama, vea los siguientes recursos:

Para obtener más información sobre cómo controlar información confidencial que no se debe mantener en repositorios de control de código fuente, consulte los siguientes recursos:

Para obtener información sobre otros métodos para mantener la información confidencial fuera del control de código fuente, consulte MVC de ASP.NET: Mantener la configuración privada fuera del control de código fuente.