[Pregunta] Buenas Practicas de Programacion en VB.NET

Iniciado por OscarCadenas_91, 27 Julio 2015, 00:58 AM

0 Miembros y 1 Visitante están viendo este tema.

OscarCadenas_91

Soy aprendiz en visual basic .net y no sabia como preguntar esto, quería preguntarles a los que tiene mas conocimientos, sobre que buenas practicas se deben tomar para programar en este lenguaje, tengo poca base y estoy aprendiendo de forma autodidacta
Espero que se entienda.

El Benjo

Hola, mis conocimientos en la programación orientada a eventos comenzaron con este lenguaje. Te puedo decir algunas cosas que se aplican a cualquier lenguaje y no algo en específico al VB:

· Indenta el código.
· No pongas todas las funciones en un único archivo o módulo. (En el formulario principal, por ejemplo, intenta dejar únicamente las funciones relacionadas con los eventos o que trabajen directamente sobre el formulario y sus controles)
· Nombra a cada control al que hagas referencia en el código. (Me refiero a que si pones un label sobre el que nunca vas a actuar puedes dejarlo con el nombre de label1, por ejemplo, pero si en tu código haces referencia a él para asignar u obtener una propiedad entonces deberías nombrar al label según su función)
· Comenta las partes de tu código que no sean muy obvias, pero no escribas comentarios innecesarios. El de abajo es un comentario innecesario porque lo que hace la linea de código e bastante obvio.

Código (vbnet) [Seleccionar]
'Incremento la variable Var1.
Var1 = Var1 + 1


Y por el momento creo que es todo lo que se me ocurre. Espero que más de uno de los puntos te fuera de ayuda.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

Eleкtro

#2
Son muchas cosas las que se deberían mencionar como para hacer una alusión a cada una de ellas en unas pocas lineas, pero te diré lo que considero que es más importante en general.




1. Usar las declaraciones Option.

Activa las declaraciones Option (excepto Option Inffer, e ignorando el valor de Option Compare) por defecto para todos los archivos de los nuevos proyectos, accediendo al menú Tools -> Options... -> Projects and solutions -> VB Defaults

También puedes hacerlo manualmente escribiendo lo siguiente en la cabecera de cualquier clase/módulo, los cambios solamente afectaran a ese archivo:
Código (vbnet) [Seleccionar]
Option Explicit On
Option Strict On
Option Infer Off

Class ClassName
' ...
End Class


Esto que he mencionado es lo primero que debes hacer, ya que es una medida que conseguirá que adquieras buenas prácticas de programación desde el principio, ya que, entre otras cosas, evitará que puedas escribir y compilar burradas como esta:
Código (vbnet) [Seleccionar]
Dim form As Object = Nothing
form.Close()


Sin embargo, será algo muy fastidioso si necesitases crear un tipo anónimo como este de abajo, ya que no lo permitirá compilar:
Código (vbnet) [Seleccionar]
Dim colors = From value In [Enum].GetValues(GetType(ConsoleColor))
            Select New With {
                             .Value = value,
                             .Name = value.ToString
                            }


...Pero precisamente este tipo de cosas son las que debes evitar hacer. Siempre puedes rsolver el problema definiendo un Type personalizado:
Código (vbnet) [Seleccionar]
<Serializable>
Public NotInheritable Class ColorThing
   Public Property Name As String
   Public Property Value As Integer
End Class

Dim colors As IEnumerable(Of ColorThing) =
   From value As ConsoleColor In [Enum].GetValues(GetType(ConsoleColor)).Cast(Of ConsoleColor)()
   Select New ColorThing With {
                               .Value = value,
                               .Name = value.ToString
                              }





2. Leer, aprender y practicar las convenciones de código y de nombres.

¿Por qué?, pues ...entre otras razones, por que cada lenguaje tiene su estándar, así que al escribir un nombre preciso y del modo correcto estarás ayudando al compiler a identificar el miembro en cuestión, lo que se puede traducir cmo mayor estabilidad y velocidad en general (por ínfima que sea en la mayoría de casos).

Aquí tienes por donde empezar, aunque aquí se menciona solamente una pequeña porción:
Manuales de .NET

Citar⇲ Estándares / Adquisición de buenas costumbres

Otras convenciones a tener en cuenta:


  • Debes ignorar cualquier uso de los miembros contenidos en el namespace Microsoft.VisualBasic (Microsoft.VisualBasic.Left, Microsoft.VisualBasic.Mid, Microsoft.VisualBasic.IsDate y en fin, cualquier nombre de función vista en VisualBasic 6)

  • Debes evitar usar prefijos como "_" para declarar variables (tanto en VB.net como en C#), esto es una mala práctica que ha sido adoptada de forma muy común, pongamos como ejemplo esta propiedad con un backing field, la mayoría de personas lo harían así:
Código (vbnet) [Seleccionar]
Public ReadOnly Property Thing As Boolean
   Get
       Return Me._thing
   End Get
End Property
Private _thing As Boolean = False


Sin embargo, ya he mencionado que el prefijo no se debe usar, así que puedes optar por escribir por ejemplo una "B" al final del nombre, para saber que se trata de un backing field:
Código (vbnet) [Seleccionar]
Public ReadOnly Property Thing As Boolean
   Get
       Return Me.thingB
   End Get
End Property
Private thingB As Boolean = False


  • Debes escribir los nombres de los métodos, funciones, Classes, Modules, Structures, Properties, y muchos más miembros en Word-Casing, y los nombres de las variables generalmente en Camel-Casing, pero se debe tener en cuenta que el estándar de nombre depende de la visibilidad asignada al miembro (public, private, shared, etc), por ejemplo así es como deberías escribir el nombre de una variable en dos casos distintos:
Código (vbnet) [Seleccionar]
Public MyObject As Object
Código (vbnet) [Seleccionar]
Private myObject As Object


  • Al practicar el P/Invoking (o Platform Invoking), debes comprender que C++ no es C# ni tampoco VB.Net, como ya dije cada lenguaje tiene su estándar de convenciones, y un error muy común en el P/Invoking es copiar o traducir las definiciones de C++ (desde la MSDN o de páginas como www.pinvoke.net) tal y como están escritas para C++, por ejemplo estructuras que llevan nombres completamente en mayúscula, lo que es completamente incorrecto en .Net.

  • Utilizar la directiva Using para asegurarte de que un objeto libera sus recursos cuando ya no los necesita, o en su defecto un bloque Try/Catch/Finally

  • Asignar siempre un valor de retorno al definir la firma de una función.

  • Sustituir a una Class por un Module siempre y cuando sea mejor y óptimo para el compiler, no simplemente para poder usar miembros compartidos/globales.

  • Inicializar siempre las variables con un valor por defecto, excepto en casos innnecesarios donde ya se inicializan con un valor por defecto como por ejemplo variables con un datatype Boolean (False) o Integer (0).

  • Utilizar el keyword WithEvents al declerar una variable que exponga eventos, y en su lugar omitir el uso de AddHandler/RemoveHandler para usarlos solamente cuando realmente sea necesario.

  • Asignarle siempre la firma a un event-handler (un método que controla un evento).

  • No hacer uso de ninguna técnica resursiva, es decir evitar cualquier método o función recursiva, ya que inevitablemente la recursividad implica un desborde de la pila (o Stack Overflow).

  • No hacer uso del keyword GoTo ni por ende de los labels.

  • No utilizar los nombres internos de datatypes como por ejemplo [Int32] en lugar de Integer.

  • Muchas cosas más.




3. Aprender a utilizar las características de Visual Studio para detectar y corregir conflictos.

Aparte de la depuración con el uso de break points, la ventana de Autos, etc, Visual Studio tiene una herramienta llamada Code Analysis a la que puedes acceder en el menú Build -> Run Code Analysis,
como su propio nombre indica, sirve para analizar el código, y al analizarlo detectará y prevendrá posibles conflictos que se te hayan podido pasar por alto, como por ejemplo una fuga de memoria por un objeto sin liberar, un objeto que liberas más de una vez, o cosas tan específicas como un conflicto de portabilización (x86/x64) en una definición de un miembro de la API de Windows.

Es tan imprescindible para desarrollar un buen código como todo lo demás (igual que los tests de unidad), pero lamentablemente pocas personas le sacan provecho a la tan maravillosa IDE que tienen, Visual Studio.

Nota: Creo que esta herramienta no está disponible en las versiones Express y Community de Visual Studio, pero no estoy seguro. Yo uso VS2013 Ultimate, y VS2015 Profesional.

Otra cosa que podrías hacer ...aunque esto personálmente me parece MUY EXCESIVO excepto para proyectos comerciales, ni yo mismo lo practico generálmente, sería crear tests de unidad (o Unit Test).
Una unidad consiste en una porción de código, una porción puede ser una variable, un método individual o una class entera.
El test de unidad, digamos que sería una forma automatizada de llevar a cabo diversos análisis para determinar si las funcionalidades de tu código fuente realmente funcionan como es esperado.

Una buenísima herramienta para los tests de unidad es NCrunch.




4. Utilizar herramientas profesionales para corregir los errores de principiante (y de no tan principiante).

Siempre es bueno utilizar una especie de guía, maestro o ayudante en forma de herramienta digital, la cual te vaya indicando los errores que has cometido en tiempo real, y así aprender de ellos para la próxima vez,
mi herramienta o mejor dicho extensión favorita es Telerik JustCode, aunque hay otras extensiones muy buenas como ReSharper (exclusivamente para C#).




5. Refactorizar el código.

El término Refactorización (o Refactor) consiste en rediseñar un código/algoritmo para simplificarlo y/o para mejorarlo sin que el código pierda su funcionalidad, principalmente para conseguir hacer lo mismo en menos pasos o para aplicar buenas prácticas de programación a un código "feo", pero simplificar no siempre implica escribir menos.

Esto sería un ejemplo de un código que no ha pasado por la etapa de refactorización:
Código (vbnet) [Seleccionar]
Dim value1 As Integer = 1
Dim value2 As Integer = 2
Dim value3 As Integer = 3
Dim result As Integer = (value1 + value2 + value3)

MsgBox(value1 & "+" & value2 & "+" & value3 & " = " & result)


El código refactorizado (tener en cuenta que se le podría dar distintos enfoques):
Código (vbnet) [Seleccionar]
Dim values As IEnumerable(Of Integer) = {1I, 2I, 3I}
MessageBox.Show(String.Format("{0}={1}", String.Join("+", values), Enumerable.Sum(values)))





6. Desarrollar código rehusable.

Deberías tratar de transformar un código hardcodeado en código genérico, rehusable.
(aquí cuidado no confundir el término genérico o Generics, que tiene un significado distinto en lo que se refiere a los Types genéricos de un lenguaje de programación)

Es decir, tratar de evitar escribir un código que haga "X" funcionalidad específica solamente para el proyecto que estás desarrollando, la razón es muy sencilla, si en el futuro necesitas volver a desarrollar un código parecido, probablemente lo empezarás desde Cero otra vez, tal vez tomes ese antiguo código como referencia pero igualmente le harás cambios específicos, y eso se traduce en PERDER tiempo.

Ejemplo de un algoritmo sencillo el cual comprueba si una colección contiene un valor específico:
Código (vbnet) [Seleccionar]
Dim values As String() = {"a", "b", "c", "d", "e"}
Dim exists As Boolean = False

For Each value As String In values

   If value.Equals("C", StringComparison.OrdinalIgnoreCase) Then
       exists = True
       Exit For
   End If

Next value


Como se puede comprobar, el código solo sirve para una colección de tipo String, todo está "pre-establecido" para que funcione así.

Ahora, este sería un ejemplo del mismo código o funcionalidad, refactorizada, documentada, genérica, y rehusable:
Código (vbnet) [Seleccionar]
Dim exists As Boolean = {"a", "b", "c", "d", "e"}.Exists("C", StringComparer.OrdinalIgnoreCase)

Código (vbnet) [Seleccionar]
#Region " Option Statements "

Option Strict On
Option Explicit On
Option Infer Off

#End Region

#Region " Imports "

Imports System
Imports System.Linq
Imports System.Diagnostics
Imports System.Runtime.CompilerServices

#End Region

''' <summary>
''' Contains custom extension methods applicable to <see cref="IEnumerable(Of T)"/>.
''' </summary>
Public Module EnumerableExtensions

#Region " Public Extension Methods "

   ''' ------------------------------------------------------------------
   ''' <summary>
   ''' Determines whether the specified value exists inside the given collection.
   ''' </summary>
   ''' ------------------------------------------------------------------
   ''' <typeparam name="T"></typeparam>
   '''
   ''' <param name="sender">
   ''' The collection.
   ''' </param>
   '''
   ''' <param name="find">
   ''' The value to find.
   ''' </param>
   ''' ------------------------------------------------------------------
   ''' <returns>
   ''' <c>true</c> if value exists, <c>false</c> otherwise.
   ''' </returns>
   ''' ------------------------------------------------------------------
   <Extension>
   <DebuggerHidden>
   <DebuggerStepThrough>
   Public Function Exists(Of T)(ByVal sender As IEnumerable(Of T),
                                ByVal find As T,
                                ByVal comparer As IComparer(Of T)) As Boolean

       If (sender Is Nothing) Then
           Throw New ArgumentNullException(paramName:="sender")

       Else
           For Each value As T In sender

               If comparer.Compare(value, find) = 0 Then
                   Return True
               End If

           Next value

           Return False

       End If

   End Function

#End Region

End Module





7. Documentar el código fuente.

Ser un programador que documenta su trabajo otorga un mayor nivel de respeto o privilegio por aquello que haces de cara al interés o satisfacción del cliente o de las compañias informáticas, el esfuerzo se ve recompensado,
pero además, una razón igual de importante también, es que documentar te obliga a extender tus habilidades de programación, por que documentar un código en muchas ocasiones implica investigar, leer y aprender sobre aquello que estás llevando a cabo, por ejemplo si haces un copy/paste de un código que no entiendes ...pues así no aprendes nada, pero si intentas documentar ese código que no entiendes, probablemente llegarás a entenderlo de principio a fin con la suficiente dedicación,
por supuesto otra razón no menos importante es que mantener una buena documentación del código ...ya sea usando documentación XML o lineas de comentario, te ayudaría a recordar lo que hace un código que dejaste olvidado años atrás, lo que reduciría el tiempo necesario de refactorización o del tiempo invertido en programar en egeneral.

Se mire por donde se mira, la documentación es una práctica muy buena que te podrá llevar a otro nivel superior de entendimiento (bueno, quizás exagero un poco jaja) si la prácticas constantemente con mucha dedicación por lo que haces.

Hay muchas herramientas de terceros que te ayudarán a aplicar la documentación XML, como por ejemplo:
GhostDoc (tiene una versión gratuita, y realmente no necesitas más)
+
[SOURCE] Snippet Tool Extension For Visual Studio (C#/VB)




Vuelvo a repetir que hay muchas cosas más que se deberían mencionar como por ejemplo realizar Profillings de rendimiento y memoria, o todo lo que ha comentado el compañero @El Benjo, pero no se puede hablar sobre todo en un post ...ni en dos.

Creo que con todo esto que mencioné ya es suficiente por hoy, espero que algo de esto le sirva a quien lo lea, por que practicamente (casi) todo lo mencionado es aplicable a C# también.

Saludos!








OscarCadenas_91

 muchas gracias a los dos por responder.
@El Benjo:
      Crees que es mejor colocar las funciones en un modulo o en una Clase que diferencia hay.

@Eleкtro:
Gracias por los consejos, JustCode lo he descargado y se ve buena lastima que sea de pago
Sobre lo de realizar Profillings de rendimiento y memoria, como se lo Hace?

El Benjo

Bueno, la diferencia es la manera en la que accedes a los miembros de la clase. Explico:

Los métodos, variables, propiedades, etc. declarados dentro de un módulo tienen un alcance global dentro del proyecto de manera predeterminada. Además, no puede haber instancias (objetos) del tipo de un módulo; las clases, por otro lado, necesitan ser instanciadas para usar sus métodos, propiedades, etc.

La MSDN explica mejor esto mismo: https://msdn.microsoft.com/es-es/library/7825002w(v=vs.90).aspx

Como dato adicional te puedo decir que puedes hacer que una clase se comporte de manera similar a un módulo si incluyes el modificador shared en una clase. La única diferencia que habría entre ésta y un módulo sería que para acceder a los elementos de la clase tendrías que escribir el nombre de la clase, un punto y el nombre del método, propiedad, variable, etc.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

Eleкtro

#5
Cita de: OscarCadenas_91 en 28 Julio 2015, 18:21 PMCrees que es mejor colocar las funciones en un modulo o en una Clase que diferencia hay.

Aunque la pregunta vaya dirigida a otra persona, te contestaré igual para despejar tu duda.

...¿Class o Module?, depende de tus necesidades.

Class

  • Permite herencia.
  • Permite instanciación.
  • Los miembros definidos existen solamente mientras la clase que contiene dichos miembros esté instanciada.
  • Los miembros públicos son accesibles unicamente desde la instancia del objeto, exceptuando algunos tipos de miembros públicos y cualquier miembro compartido (Shared) que son accesibles por cualquier otra clase o módulo del proyecto.
  • Se suele usar para encapsular todo tipo de miembros. Para casi todo en general.

Module
  • No permite herencia.
  • No permite instanciación.
  • Los miembros definidos existen todo el tiempo hasta que la aplicación finalice.
  • Los miembros públicos son globales, accesibles por cualquier otra clase o módulo del proyecto.
  • Se suele usar para exponer métodos y funciones públicas.

¿Conclusión?:
Yo te diría que generálmente utilices una Class, no un Module, excepto cuando realmente lo necesites por ejemplo para crear extensiones de método o para exponer un par de métodos y funciones que no requieran marear la perdíz instanciando una class, ya que de otro modo, si le dieses un uso muy frecuente a los módulos, entonces la visibilidad de los miembros definidos podría derivar de forma despistada en desambiguaciones de nombres con algún Namespace, aunque por otro lado, es algo que siempre puedes corregir.




Cita de: OscarCadenas_91 en 28 Julio 2015, 18:21 PMJustCode ... lastima que sea de pago

Si, es una lástima ...siempre que no lo encuentres craqueado (es bien facil si buscas en Google).

Por ejemplo en este mismo foro:
Microsoft Visual Studio 2013 Ultimate + Resource Pack (Actualizado 09-Oct-2014) - By Elektro




Cita de: OscarCadenas_91 en 28 Julio 2015, 18:21 PMSobre lo de realizar Profillings de rendimiento y memoria, como se lo Hace?

Beginners Guide to Performance Profiling - MSDN
How To: Use CLR Profiler - MSDN

CLR Profiler for .NET Framework 4 - Microsoft Download Center
PerfView - Microsoft Download Center

Telerik Just-Trace
RedGate's ANTS Performance Profiler
RedGate's ANTS Memory Profiler

PD: Respecto a los profillers de Telerik y RedGate, ambas herramientas se pueden integrar en Visual Studio y también se distribuyen en versión standalone.

Saludos