Porqué es bueno eliminar la refencia al ensamblado Microsoft.VisualBasic.dll en nuestros proyectos (I)
Introducción
En la última entrada de mi blog, escribí acerca de como eliminar la referencia al ensamblado Microsoft.VisualBasic.dll de nuestros proyectos.
En esa entrada, hubo algunas personas que dieron sus opiniones dentro del apartado de comentarios, algo que agradezco muchísimo, ya que siempre es importante la interactuación de la gente en un blog donde no suele haber un diálogo, sino un intercambio de opiniones o puntos de vista, y los razonamientos y pensamientos se hacen a trompicones.
Las dudas razonables…
Dentro de esos comentarios hubo uno iniciado por delm en el que afirmaba que le daba mucha lástima que se gastara energía en investigar cosas como la que indicaba en mi entrada, y dudaba que esos esfuerzos sirvieran para algo.
Desde luego, que cualquier investigación o análisis sirve, incluso si las conclusiones de esos estudios son nulos. Es positivo que se realicen estudios de todo tipo (con cierto criterio claro está) con el fin de aprender más acerca de las tecnologías y su uso.
Pero no solo es positivo en el campo de la investigación y su uso, sino que a veces es incluso hasta importante u obligatorio.
Por esa razón supongo, delm nos comentaba igualmente que se fundamentara las afirmaciones que se realizan en mi entrada con estudios o profiling en una o varias aplicaciones de un tamaño decente para ver si realmente vale la pena.
A mí me gustaría por otro lado, que delm también realizara esos estudios para fundamentar sus opiniones contrarias. Así nos enriqueceríamos todos.
No obstante, yo ya hice algunos estudios sobre esto hace tiempo, pero ni los tenía a mano, ni sinceramente, me encontraba con ganas de repetirlos debido al poco tiempo libre que tenía para hacer unos estudios concienzudos. Sin embargo, he sacado algo de tiempo para escribir esta segunda entrada y comentar un pequeño y espero que simbólico estudio que he hecho con el fin u objetivo de demostrar el porqué puede ser interesante eliminar al referencia de Microsoft.VisualBasic.dll y usar en su lugar las librerías de .NET.
Lo más sensato es hacer un estudio muchísimo más riguroso, pero espero que este pequeño estudio ofrezca algo de luz a quienes dudan de si es positivo o no eliminar la referencia a Microsoft.VisualBasic.dll.
Recordando…
Recordad, que cuando se llama a un método o función de Microsoft.VisualBasic.dll, ésta se convierte a su método o función equivalente dentro de .NET, lo cuál genera de alguna manera ciertas penalizaciones en el rendimiento de nuestras aplicaciones.
Demostrando…
La pequeña demostración (siento mucho no haber podido hacer una demostración mucho más completa como me hubiera gustado) es la siguiente:
He creado dos clases exactamente iguales en funcionalidad, aunque distintas en cuanto al código escrito, ya que una de ellas se basa en las funciones de VB 6 de Microsoft.VisualBasic.dll y el otro código, se basa en las funciones propias de .NET.
Para estudiar el profiling, me he apoyado en la herramienta JetBrains dotTrace.
Y así, empezamos a codificar la primera clase que he llamado WithReference.
El código de esta primera clase con funciones típicas de VB 6 para .NET es el siguiente:
WithReference.Class1 (Class1.vb):
Namespace WithReference Public Class Class1 Public Function DeleteSpaces(ByVal data As String) As String Return Trim(data) End Function Public Function TakeLeftRightText(ByVal data As String) As String Return Left(data, 1) & Right(data, 1) End Function Public Function TransformTextMid(ByVal data As String) As String Dim auxiliarText As String = «» For I As Byte = 1 To Len(data) auxiliarText &= Mid(data, I, 1) Next Return auxiliarText End Function Public Function TransformTextReplace(ByVal data As String, _ ByVal findCharacter As String, ByVal replaceCharacter As String) As String Return Replace(data, findCharacter, replaceCharacter) End Function Public Function TransformTextReverse(ByVal data As String) As String Return StrReverse(data) End Function Public Function TransformTextUpper(ByVal data As String) As String Return UCase(data) End Function Public Function TransformTextLower(ByVal data As String) As String Return LCase(data) End Function Public Function GetCharacterPosition(ByVal data As String, ByVal searchText As String) As Byte Return InStr(data, searchText) End Function Public Sub TestConversion() Dim auxiliarText As String = «» For i As Integer = 0 To 10000 If i Mod 2 = 0 Then ‘ Convert to String auxiliarText &= Conversion.Int(i).ToString Else ‘ Convert to Integer (Int32) auxiliarText &= Conversion.Str(i) End If Next End Sub End Class ‘ Class1 End Namespace ‘ WithReference |
A la segunda clase la he llamado WithoutReference.
El código de la segunda clase con funciones propias de .NET equivalentes a las usadas en la clase anterior es el siguiente:
WithoutReference.Class1 (Class1.vb):
Namespace WithoutReference Public Class Class1 Public Function DeleteSpaces(ByVal data As String) As String Return data.Trim End Function Public Function TakeLeftRightText(ByVal data As String) As String Return data.Substring(1, 1) & data.Substring(data.Length – 1, 1) End Function Public Function TransformTextMid(ByVal data As String) As String Dim auxiliarText As String = «» For I As Byte = 0 To data.Length – 1 auxiliarText &= data.Substring(I, 1) Next Return auxiliarText End Function Public Function TransformTextReplace(ByVal data As String, _ ByVal findCharacter As String, ByVal replaceCharacter As String) As String Return data.Replace(findCharacter, replaceCharacter) End Function Public Function TransformTextReverse(ByVal data As String) As String Dim charArray(data.Length) As Char For i As Byte = 0 To data.Length – 1 charArray(i) = data(data.Length – (i + 1)) Next Return New String(charArray) End Function Public Function TransformTextUpper(ByVal data As String) As String Return data.ToUpper End Function Public Function TransformTextLower(ByVal data As String) As String Return data.ToLower End Function Public Function GetCharacterPosition(ByVal data As String, ByVal searchText As String) As Byte Return data.IndexOf(searchText, 1) End Function Public Sub TestConversion() Dim auxiliarText As String = «» For i As Integer = 0 To 10000 If i Mod 2 = 0 Then ‘ Convert to String auxiliarText &= Convert.ToInt32(i).ToString Else ‘ Convert to Integer (Int32) auxiliarText &= Convert.ToString(i) End If Next End Sub End Class ‘ Class1 End Namespace ‘ WithoutReference |
Finalmente he compilado las clases. WithReference con Visual Studio 2008, y WithoutReference siguiendo el patrón de la entrada anterior donde mostraba como compilar una clase con .NET eliminando las referencias a Microsoft.VisualBasic.dll.
La diferencia de tamaños entre las clases son:
- WithReference.dll (11,5 Kb)
- WithoutReference.dll (4,5 Kb)
Además de los tamaños de las clases, existen más diferencias en tiempo de ejecución tal y como veremos a continuación.
Para este experimento, he iniciado una aplicación Windows con C# y con un control Button, al que he agregado una referencia con el ensamblado WithReference.dll.
Dentro del código del formulario windows he escrito el siguiente código:
Aplicación Windows (MainForm.cs):
private void btnTestProfiler_Click(object sender, EventArgs e) { this.Text = «Proceso iniciado…»; this.Enabled = false; WithReference.Class1 classTest = new WithReference.Class1(); for (int i = 0; i < 100; i++) { string result; result = classTest.DeleteSpaces(» Testing «); byte position; position = classTest.GetCharacterPosition(«Testing», «i»); result = classTest.TakeLeftRightText(«Testing»); classTest.TestConversion(); result = classTest.TransformTextLower(«ReSuLtS»); result = classTest.TransformTextUpper(«ReSuLtS»); result = classTest.TransformTextMid(«Text to extract letter by letter»); result = classTest.TransformTextReplace(«This is a sample text, to replace it by other different text.», «a», «n»); result = classTest.TransformTextReverse(«This is a sample text, to do the reverse of this text.»); } this.Text = «Proceso finalizado.»; this.Enabled = true; } |
He generado el fichero ejecutable y he copiado el ejecutable y la librería en un directorio aparte.
Una vez hecho esto, he repetido el proceso quitando la referencia a WithReference.dll y agregando una referencia al ensamblado WithoutReference.dll.
El código de la aplicación para este segundo caso es el siguiente:
Aplicación Windows (MainForm.cs):
private void btnTestProfiler_Click(object sender, EventArgs e) { this.Text = «Proceso iniciado…»; this.Enabled = false; WithoutReference.Class1 classTest = new WithoutReference.Class1(); for (int i = 0; i < 100; i++) { string result; result = classTest.DeleteSpaces(» Testing «); byte position; position = classTest.GetCharacterPosition(«Testing», «i»); result = classTest.TakeLeftRightText(«Testing»); classTest.TestConversion(); result = classTest.TransformTextLower(«ReSuLtS»); result = classTest.TransformTextUpper(«ReSuLtS»); result = classTest.TransformTextMid(«Text to extract letter by letter»); result = classTest.TransformTextReplace(«This is a sample text, to replace it by other different text.», «a», «n»); result = classTest.TransformTextReverse(«This is a sample text, to do the reverse of this text.»); } this.Text = «Proceso finalizado.»; this.Enabled = true; } |
He vuelto a compilar el proyecto y lo he apartado en otro directorio junto a la librería del ensamblado WithoutReference.dll.
De esta manera, tengo los dos programas listos para ser procesados con la herramienta de rendimiento y profiling.
Estudiando comportamientos…
He arrancado la herramienta JetBrains dotTrace y he ejecutado el primer ejecutable (con el ensamblado WithReference.dll) y he obtenido unos datos muy diferentes a los que muestra el segundo ejecutable (con el ensamblado WithoutReference.dll).
Los datos obtenidos del uso de WithReference.dll los he denominado DatosCon.
Los datos obtenidos del uso de WithoutReference.dll los he denominado DatosSin.
En este punto, lo que tenemos que hacer es estudiar los comportamientos de los dos ensamblados.
En el caso del uso del ensamblado con referencias a Microsoft.VisualBasic.dll, vemos que el proceso de ejecución nos ha durado 24.445 ms, y el proceso principal del control Button, 20.292 ms.
Por su parte, el ensamblado sin referencia a Microsoft.VisualBasic.dll, ha tardado en el proceso general 17.877 ms, mientras que en el proceso principal del control Button, el tiempo que ha tomado es de 15.827 ms.
Algunas conclusiones…
Las conclusiones a simple vista son bastante claras.
El ensamblado que no tiene referencia a Microsoft.VisualBasic.dll, tiene un menor tamaño en su ensamblado y es más rápido en su ejecución.
De todos los modos, tengo pensado agregar alguna entrada más que tendrá por objetivo estudiar algunos de los resultados obtenidos en estas pruebas, y mirar un poco el código intermedio de ambos ensamblados.
Espero que esto, ayude a clarificar aún más mis afirmaciones, las cuales no son verdades absolutas, pero sí pueden ser consideradas por algunos con un poco más de fundamento.
9 Responsesso far
Muy buen aporte nuevamente Jorge, voy a ir practicando con las clases .NET para ver las diferencias en mis proyectos.
Por cierto el software para Checkear el comportamiento de ambos ensamblados muy bueno voy a echarle un vistazo.
Saludos.
Francisco J.
Solo puedo decir que…. muchas gracias..
Con gente como tú aprendemos TOD@S
Excelente, Jorgito!
Esto más o menos coincide con lo que yo pensaba sobre el tema: una capa intermedia que no aporta más que malas prácticas de programación!
Abrazo – Octavio
Me ha gustado tu enfoque empírico. Para los programadores de gestión (contabilidades, facturación) no viene a deciornos mucho, pero una cosa está clara, para los programadores que no sean de gestión y que usen VB.NET y necesiten de una optimización del entorno (rendimiento, buenas practicas, etc…) este artículo tiene mucho que decirles.
Felicidades Jorge.
PD No me deja evaluarte el articulo pasando el mouse por las estrellitas, tengo iexplorer 8.0 por si te sirve, pero la calif para mi son 4 estrellas
Hola Julio,
es extraño que no se pueda votar.
Sobre tu comentario, te debo decir que esto que comento puede afectar a cualquier tipo de programador. No es necesario ser programador de gestión o no para que esto nos pueda afectar.
Date cuenta que dentro de Microsoft.VisualBasic.dll hay instrucciones que afectan no solo a campos texto, sino también a cálculos matemáticos, por lo que sí podría afectar a soluciones Software de tipo contrable, administrativo o de facturación.
Muchas gracias por comentar Julio. 🙂
No entiendo por qué un programador de gestión no puede hacer las cosas bien y optimizar sus aplicaciones y ofrecer un buen rendimiento en éstas…
Gracias por este «manual de buenas prácticas para usuarios de VB6″… 😉
Muchas veces, el mantener una compatibilidad hacia atrás nos ayuda a «ir más rápido» y comenzar con un nuevo soporte o lenguaje, pero a la larga realmente nos «retrasa» y nos mantiene con extructuras y funciones anticuadas.
Creo que no es cuestión de optimización para software de Gestión o no, es simplemente una optimización y buenas prácticas de uso de un lenguaje de «última generación» (observa que lo he puesto entre comillado).
Ahora, lo que tenemos que hacer es quitar la referencia a esta DLL e ir adaptando el software y esperar que para futuras ediciones de VS se pueda eliminar del compilador.
PD: Sería bueno hacer un manual de correspondencia entre las funciones más utilizadas de VB6 y su equivalente en VB.Net, para que todos los anticuados (yo me incluyo) del VB6 sepamos como sacar el máximo provecho a .Net y olvidar esta DLL.
Esta bien el ejemplo siempre una capa intermedia penaliza el rendimiento.Pero, solo haces comprobaciones con cadenas y estas en .Net estan muy mal optimizadas de ello la existencia de stringbuilder. No puede ser que sea la mala optimizacion de las cadenas de caracteres las que penalizan el rendimiento no el uno de la la funcion de vb clasica. Seguramente los metodos de la clase de .net intentan paliar el mal rendimiento de la clase string.
El hombre es un animal de constumbres y cuesta cambiar pero ahora sabe lo que penaliza y cada uno decida si prefiere mas rendimiento o mantener las herramientas que hasta hace poco usaba.
Os diré que es muy saludable para un programador de VB6 (like me) meterse a aprender C#, se eliminan costumbres un poquillo obsoletas, se aprende bien la plataforma .Net y de paso se aprende un C.
¿Qué más se puede pedir?
😀 😀 😀
(bueno, debo admitir que antes de aprender VB6 ya había pasado por C++ programando programitas para consolas, lo malo del C# es que no le gustan los punteros, son muy «unsafe»)
D: D: D: