Mejores prácticas con Nuget: ¿depurar o liberar?

92

Actualmente, empaqueto las compilaciones de la versión con Nuget para las compilaciones oficiales en nuget.org, pero empaqueto las compilaciones de depuración con Nuget para los empujes de la fuente de símbolos en symbolsource.org.

EDITAR: (Jon Skeet, con algún sesgo del desarrollo de Noda Time)

NuGet ahora admite la inserción tanto en la galería NuGet como en symbolsource.org (o servidores similares), como se documenta . Desafortunadamente, aquí hay dos requisitos contradictorios:

  • Cuando solo usa una biblioteca sin necesidad de depurar, realmente desea una compilación de lanzamiento. Después de todo, para eso son las versiones de lanzamiento.
  • Al depurar en una biblioteca con fines de diagnóstico, realmente desea una compilación de depuración con todas las optimizaciones apropiadas deshabilitadas. Después de todo, para eso son las compilaciones de depuración.

Eso estaría bien, pero NuGet (hasta donde yo sé) no permite que tanto la versión de lanzamiento como la versión de depuración se publiquen de una manera útil, en el mismo paquete.

Entonces, las opciones son:

  • Distribuya las compilaciones de depuración a todos (como se muestra en el ejemplo en los documentos) y viva con cualquier tamaño y éxito de rendimiento.
  • Distribuya las compilaciones de la versión a todos y viva con una experiencia de depuración ligeramente deteriorada.
  • Opte por una política de distribución realmente complicada, que potencialmente proporcione paquetes de liberación y depuración separados.

Los dos primeros realmente se reducen al efecto de las diferencias entre las compilaciones de depuración y versión ... aunque vale la pena señalar que también hay una gran diferencia entre querer ingresar al código de una biblioteca porque desea verificar algún comportamiento y querer para depurar el código de una biblioteca porque cree que ha encontrado un error. En el segundo caso, probablemente sea mejor obtener el código de la biblioteca como una solución de Visual Studio y depurar de esa manera, por lo que no estoy prestando demasiada atención a esa situación.

Mi tentación es seguir con las compilaciones de la versión, con la expectativa de que relativamente pocas personas necesitarán depurar, y las que lo hagan no se verán afectadas mucho por las optimizaciones en la compilación de la versión. (El compilador JIT realiza la mayor parte de la optimización de todos modos).

Entonces, ¿hay otras opciones que no hayamos considerado? ¿Hay otras consideraciones que inclinan la balanza? ¿Enviar paquetes NuGet a SymbolSource es lo suficientemente nuevo como para que no se hayan establecido las "mejores prácticas"?

gzak
fuente
2
Estaba a punto de hacer la misma pregunta, aunque actualmente estoy presionando la configuración de lanzamiento para el origen de símbolos, dado que solo estoy usando nuget pack ... -Symboly presionando los paquetes generados ...
Jon Skeet
1
Siento que debería enviar esta sesión de preguntas y respuestas a la gente detrás de NuGet y ver si pueden opinar sobre ella.
gzak
Hornee el inicio de sesión en su paquete y luego publique solo la versión de lanzamiento. Puede permitir la inyección del registrador, lo que le permitirá al consumidor configurar el registro según sus preferencias.
CShark

Respuestas:

31

Hablando en nombre de SymbolSource, creo que la mejor práctica es:

  1. Envíe paquetes de contenido binario + de lanzamiento solo a nuget.org (o cualquier otro feed de producción)
  2. Envíe paquetes de depuración binary + content a un feed de desarrollo:
    • en la premisa
    • en myget.org
    • en nuget.org como paquetes preliminares.
  3. Envíe los paquetes de liberación y depuración de símbolos + binarios a symbolsource.org o cualquier otra tienda de símbolos.

Ya que estamos en eso, es un error común pensar que las compilaciones de liberación y depuración en .NET realmente difieren mucho, pero supongo que la diferenciación está aquí debido a varios códigos que pueden o no estar incluidos en cualquiera de las compilaciones, como Debug .Afirma.

Dicho esto, realmente vale la pena enviar ambas configuraciones a SymbolSource, porque nunca se sabe cuándo necesitará depurar el código de producción. De forma remota en producción para hacerlo más difícil. Necesitará la ayuda que pueda obtener de sus herramientas cuando eso suceda. Lo que obviamente no le deseo a nadie.

Todavía hay una cuestión a considerar con respecto al control de versiones: ¿es correcto tener 2 paquetes diferentes (compilados en depuración y en versión) que compartan 1 número de versión? SymbolSource lo aceptaría, ya que extrae paquetes y almacena binarios en ramas de modo de compilación separadas, SI SÓLO NuGet tiene permitido etiquetar paquetes en consecuencia. Actualmente, no hay forma de determinar si un paquete está en modo de depuración o de liberación.

TripleEmcoder
fuente
La parte de "publicar dos compilaciones en NuGet" es la parte complicada. Siempre he publicado la versión de lanzamiento de Noda Time, con el argumento de que tenía que elegir entre los dos. (Tengo un archivo nuspec, en lugar de hacerlo solo desde el proyecto C #.) Mencionas depurar el código de producción como si eso fuera significativamente más difícil con solo una versión de lanzamiento, a pesar de la parte anterior de "no difieren mucho". Soy consciente de los NOP en las compilaciones de depuración, y obviamente, Debug.Assertetc., pero ¿podría ampliar (en su respuesta) las implicaciones al depurar? ¿Qué tan malo es usar una versión de lanzamiento?
Jon Skeet
Lo que quise decir es que desea tener símbolos disponibles para todos los binarios en uso: si hay compilaciones de depuración y liberación en la naturaleza, querrá proporcionar símbolos para ambos. No es necesario que difieran mucho en términos de código, pero sí en las sumas de verificación, lo que hace que la carga de símbolos sea imposible sin algún tipo de piratería.
TripleEmcoder
1
Derecha. Mi posible solución es lanzar solo los binarios de la versión, pero me preocupa cuánto va a doler en términos de depuración. Por ejemplo, ¿la falta de NOP significa que no puede agregar puntos de interrupción?
Jon Skeet
El problema radica más en las optimizaciones JIT que en las optimizaciones en tiempo de compilación. Entonces, si empuja paquetes en modo de lanzamiento y recomienda usar COMPLUS_ZapDisable = 1 cuando se necesita depuración, eso sería lo suficientemente bueno para mí. Aún así, NuGet debería permitir la depuración y el lanzamiento juntos de alguna manera.
TripleEmcoder
No tenía idea de que symbolssource.org existe. Como una picazón que tuve muchas veces la necesidad de rascarme, la doy la bienvenida.
Remus Rusanu
4

Estoy completamente de acuerdo con tu conclusión. Paquetes NuGet con RELEASE y SymbolSource con depuración. Parece bastante raro entrar directamente en los paquetes y el paso en falso de depuración ocasional con optimizaciones habilitadas podría ser aceptable.

Si realmente hubiera un problema, creo que la solución ideal sería que NuGet lo admita. Por ejemplo, imagínese si al depurar, pudiera reemplazar la DLL de la versión con la incluida en el paquete SymbolSource.

Idealmente, lo que sucedería entonces es que nuget pack SomePackage -Symbolscontra una versión de lanzamiento se crearía un paquete nuget de lanzamiento, pero un paquete de símbolos de depuración. Y el complemento VS se actualizaría para ser lo suficientemente inteligente como para ver la asociación y extraer los ensamblados de depuración cuando se ejecuta en un depurador y cargarlos en su lugar. Un poco loco, pero sería interesante.

Sin embargo, no veo suficientes personas quejándose de esto como para que valga la pena en este momento.

El equipo de NuGet acepta solicitudes de extracción. :)

Pirateado
fuente
No estoy seguro de entender su segunda oración; sospecho que el OP (antes de editar) estaba haciendo empujes manuales a SymbolSource para las compilaciones de depuración. ¿ Considera problemas importantes si el PDB de la versión de lanzamiento termina en SymbolSource en lugar de la versión de depuración? ¿O es eso lo que estaba defendiendo y yo simplemente lo entendí mal?
Jon Skeet
3
"Sin embargo, no veo suficientes personas quejándose de esto como para que valga la pena en este momento". Quizás no se estén quejando, pero si le preguntaras a una muestra de usuarios qué piensan de esto, apuesto a que encontrarás que la mayoría de la gente admitiría un poco de confusión en este paso en particular (qué publicar en NuGet.org y SymbolSource .org). Si le preguntaras qué terminaron eligiendo, probablemente te darás cuenta de que no hay una práctica única acordada, todos hacen lo suyo.
gzak
7
Quiero quejarme de esto, ¿dónde me registro?
Alex
Una vez que tenga NuGets internos y comience a implementarlos en un servidor de símbolos ... inevitablemente querrá depurarlos ... y aunque puede recorrer el código, terminará con "No se puede obtener el valor del variable o argumento local ... se ha optimizado ". Como menciona Phil ... SI nuget tuviera una forma de cargar dlls de depuración en modo de depuración y liberar dlls en modo de lanzamiento (desde paquetes de nuget), esto sería lo último. Hasta entonces, estamos atrapados con el conmutador de paquetes de
Nuget
1
Estoy de acuerdo, esta sería una buena mejora del producto.
htm11h
2

Han pasado 8 años desde la publicación de OP, así que lo intentaré con lo que se usa hoy en día.

Hay 2 formas de " entrar " en un paquete NuGet:

1. Distribución de AP

.symbols.nupkgLos paquetes de símbolos se consideran heredados y se han reemplazado por .snupkgpaquetes que se publican en Symbol Server . Es compatible con todos los proveedores principales, como NuGet.org, Azure DevOps ( aunque menos fluido ), etc.

Aquí están las instrucciones oficiales . Simplemente agregue estas dos líneas al archivo csproj:

<PropertyGroup>
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>

En el lado del consumidor, asegúrese de que su IDE esté configurado para NuGet.org (o Azure, etc.) Symbol Server para permitir ingresar al código del paquete durante la depuración.

2. Enlace de origen: vincular el código real

En algunos casos, los PDB pueden ocultar algunos detalles del código fuente debido a la optimización de MSIL / JIT. Así que hay una manera de " entrar en " la fuente real de su NuGet durante la depuración. Se llama Source Link de .NET Foundation, " un sistema agnóstico de control de fuente y lenguaje para proporcionar experiencias de depuración de fuente para binarios ".

Es compatible con Visual Studio 15.3+ y todos los principales proveedores (también admite repositorios privados).

Es trivial de configurar ( documentos oficiales ): simplemente agregue una dependencia de desarrollo al archivo del proyecto (depende del tipo de su repositorio) junto con algunas banderas:

<PropertyGroup>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

Obtenga más información sobre este tema en " 5 pasos para mejorar el paquete NuGet ".

Alex Klaus
fuente
1

El ejemplo de Creación y publicación de un paquete de símbolos hace referencia a los archivos de los directorios Debug como fuentes para los archivos dll y pdb.

Especificación del contenido del paquete de símbolos

Un paquete de símbolos se puede construir por convenciones, desde una carpeta estructurada de la forma descrita en la sección anterior, o su contenido se puede especificar usando la sección de archivos. Si desea compilar el paquete de ejemplo descrito anteriormente, puede ponerlo en su archivo nuspec:

<files>
  <file src="Full\bin\Debug\*.dll" target="lib\net40" /> 
  <file src="Full\bin\Debug\*.pdb" target="lib\net40" /> 
  <file src="Silverlight\bin\Debug\*.dll" target="lib\sl40" /> 
  <file src="Silverlight\bin\Debug\*.pdb" target="lib\sl40" /> 
  <file src="**\*.cs" target="src" />
</files>

Dado que el propósito de publicar los símbolos es permitir que otros revisen su código durante la depuración, parece más prudente publicar una versión del código destinada a la depuración sin optimizaciones que puedan afectar el paso del código.

tvanfosson
fuente
Sí, eso es lo que hace el ejemplo , pero prefiero no terminar con la capacidad de depurar anulando el deseo de la mayoría de los desarrolladores de ejecutar la versión de lanzamiento. El problema es que NuGet no tiene una forma de publicar versiones de lanzamiento y depuración, hasta donde yo sé. (También sería un poco doloroso para mí publicar ambos, ya que significa crear otro conjunto de configuraciones, para compilaciones de depuración firmadas ...)
Jon Skeet
Aquí entramos en un poco de subjetividad. Por lo general, mi elección de "mejores prácticas" sería la que el autor recomienda, ya sea explícita o implícitamente, porque supongo que tienen más conocimiento (o supervisión, en el caso de suposiciones que terminan en ejemplos) que yo. Hablando personalmente, Creo que los símbolos deberían coincidir con la versión que estoy usando. Por lo general, no usaría un paquete que pensé que probablemente tendría que depurar, a menos que la fuente fuera pública y pudiera compilar desde cero si fuera necesario, por lo que la falta de una compilación de depuración empaquetada no es particularmente importante.
tvanfosson
En mi caso, si alguien necesita depurar Noda Time porque cree que hay un error en Noda Time, sería mejor que descargaran la fuente (lo que pueden hacer, por supuesto). Sin embargo, sigue siendo útil poder ingresar al código fuente de Noda Time solo para ver qué está pasando. Básicamente, creo que hay (al menos) dos escenarios diferentes para la depuración, con diferentes soluciones ...
Jon Skeet
Una cosa en la que me gusta pensar es en .NET en sí: creo que es seguro decir que Microsoft publica versiones de versiones y no depura las versiones de .NET. Una versión de lanzamiento implica un cierto nivel de calidad y estabilidad, por lo que la idea es que rara vez necesitará ingresar al código para diagnosticar cosas.
gzak
2
Sin embargo, esa es también una mentalidad bastante "de fuente cerrada". Descubrí que en el mundo del código abierto, se espera más poder ingresar al código de "versiones estables" de varias bibliotecas, no porque las cosas estén rotas, sino porque a veces la mejor documentación es simplemente ver qué es la biblioteca. haciendo.
gzak