Let’s talk about Functions again, when I am looking through code, I find it extremely frustrating that I have to roam all throughout the class or file for every couple of minutes and that there is no logical flow or position of the position of the different functions.
There are two general types of functions, the Graphical User Interface (GUI) Functions and the Non-GUI Functions. The GUI Functions are those that are initiated from an action the user does, such as the Form events or controls like buttons and tool bars, these functions should be extremely small containing a Try…Catch block and the Non-GUI Layer Function Call or sometimes laundry list of calls. The Non-GUI Layer Functions are everything else…
Let’s first talk about Non-GUI Layer functions, typically, Non-GUI Layer Functions should be categorized with other similar Non-GUI Layer Functions and supporting functions under the same class, allowing the easy access and finding of what you are trying to do. For instance, any process that interacts with disk management (i.e. managing files, directories, etc), or configuration settings should be under a class object with each other. Each Entry Point into that class should be organized either as a Alphabetical, as a Most Expected to be Managed prospect or as an Usability Process (this works extremely well within the constructs of events, where the form load event is the first thing, then the toolbar function clicks, in the order that the menu options are presented to the user, etc). Personally, I prefer the later of the three, this allows me to look at the GUI interface and then quickly guesstimate whereabouts in the code I am expecting to find it. Personally, I also find that I like to have the Shared (or Static) Private Variables then Shared Methods located at the top of the class, and then the Instantiated Private Variables, Properties and Methods underneath that.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
Public Class GeneralClassName #Region "Shared Variables" Private Shared _CalculationValue As Object Private Shared _DoubleCalculationValue As Object Private Shared _ExtraCalculatedValue as Object #End Region #Region "Shared Methods" Public Shared Function CalculateSomething(ByVal Parameter1 As Object) '... End Function Public Shared Function DoubleCalculation(ByVal Parameter1 As Object) '... End Function #End Region #Region "Private Variables" Private _CalculationValue As Object Private _DoubleCalculationValue As Object Private _ExtraCalculatedValue as Object #End Region #Region "Properties" Public Property CalculationValue As Object '... End Property Public Property DoubleCalculationValue As Object '... End Property Public Property ExtraCalculatedValue as Object '... End Property #End Region #Region "Methods" Public Sub New() '... End Sub Public Sub New(ByVal Parameter1 As Object) '... End Sub Public Function CalculateSomething(ByVal Parameter1 As Object) '... End Function Public Function DoubleCalculation(ByVal Parameter1 As Object) '... End Function Protected Overrides Sub Finalize() '... End Sub #End Region End Class |
I have heard from two different camps on the usage of regions and how they flow within the code, and arguably, I can see some benefit and some detriment. For instance, with Regions, you are confined to a certain area and if there are to many regions it makes it extremely difficult to locate what you are looking for, especially when the region is closed. While on the other hand, if the regions are limited and are presented as “categories” of the type of code that is expected, it allows the developer an easy way to jump directly to what type of code they are looking for.
Each supporting function should be presented below the last function that uses it in the order that it is used… for instance lets assume that I have a function that calls three other functions (not used in any other function), I would expect that the first function that is called be directly underneath the calling function, kind of like a book sections, chapters, topics, sub-topics, points, etc. If that function is used by multiple functions, I would expect it to be underneath that last function that called it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
Public Shared Function CalculateSomething(ByVal Parameter1 As Object) CalculateCalledFirst CalculateCalledSecond CalculateAndDoubleCalledThird End Function Private Shared Sub CalculateCalledFirst() '... End Sub Private Shared Sub CalculateCalledSecond() '... End Sub Public Shared Function DoubleCalculation(ByVal Parameter1 As Object) DoubleCalledFirst DoubleCalledSecond CalculateAndDoubleCalledThird End Function Private Shared Sub DoubleCalledFirst() '... End Sub Private Shared Sub DoubleCalledSecond() '... End Sub Private Shared Sub CalculateAndDoubleCalledThird() '... End Sub |
Now, lets talk about the GUI Layer Functions, these are the form events, control events that are generated for when the user does something. These should be laid out in a manner as the controls are laid out, these functions shouldn’t really be calling anything within the same form; however, there are times when it is appropriate and then it should be that they are also laid out as directly underneath the calling function in the order called.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
Imports System.ComponentModel Public Class FormGeneral Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load '... End Sub Private Sub NewToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles NewToolStripMenuItem.Click '... End Sub Private Sub OpenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click '... End Sub Private Sub SaveToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SaveToolStripMenuItem.Click '... End Sub Private Sub SaveAsToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SaveAsToolStripMenuItem.Click '... End Sub Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged '... End Sub Private Sub TextBox2_TextChanged(sender As Object, e As EventArgs) Handles TextBox2.TextChanged '... End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '... End Sub Private Sub Form_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing '... End Sub Private Sub Form_Closed(sender As Object, e As EventArgs) Handles Me.Closed '... End Sub End Class |
In essence, the main goal of organizing our functions is to make it easier to determine where it is for future readers of our code. If there is some logic behind it, then it is more likely that the next person won’t be screaming your name and punching the voodoo doll that has a piece of your hair on it. This also makes it so much easier for debugging purposes as we aren’t racing from one end of the class to the next trying to figure out what is going on.
Until next time, Happy Coding and may you be blessed!