Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good design pattern to avoid having to use a global variable at the top your main form?

Every time I talk to experienced programmers, they talk about having global variables being a bad practice because of debugging or security exploits. I have a simple List of strings I want to load from a a textfile and access across different methods in my form. Before, I would simply initialize said variable at the top, inside of my form class and use it across methods. I always try to reduce that practice when I can and only initialize those variables when I really need them. Is it a bad practice to do this or do more experienced programmers do this too? Is there a standard design pattern method of doing this so you don't have to use "global variables" at the top of your form?

like image 627
Michael Weston Avatar asked Feb 18 '17 17:02

Michael Weston


1 Answers

As you're talking about C# and it's a fully-object-oriented programming language, there's no way to declare global variables.

In an OOP language like C#, a bad practice can be simulating global variables using static classes:

public static class Global
{
     public static string Value1 { get; set; }
     public static int Value2 { get; set; }
}

...to later get or set these values from other classes. Definitely, this a bad practice because state should be held by specific and meaningful objects.

Usually, in a perfect/ideal OOP solution, you should pass such values from class to class using constructors:

public class X
{
    public int Value1 { get; set; }

    public void DoStuff()
    {
        Y y = new Y(this);
        y.DoChildStuff();
    }
}

public class Y
{
    public class Y(X parent)
    {
         Parent = parent;
    }

    public X Parent { get; }

    public void DoChildStuff()
    {
         // Do some stuff with Parent
    }
}

Or also, you might pass states providing arguments to some method:

public class Y
{    
    public void DoChildStuff(X parent)
    {
         // Do some stuff with "parent"
    }
}

Since you're passing states with reference types, if any of the methods in the chain decide to change Parent.Value1 with another value, all objects holding a reference to the same X object will get the new X.Value1.

Some fellows might argue that we usually build configuration objects which own a lot of properties accessed by other arbitrary objects, right? BTW, configuration is a concept per se, isn't it? And we usually categorize configuration values using composition:

public class ApplicationConfiguration
{
     public DatabaseConfiguration Database { get; } = new DatabaseConfiguration();
     public StorageConfiguration Storage { get; } = new StorageConfiguration();
}

public class DatabaseConfiguration
{
     public string ConnectionString { get; set; }
}

public class StorageConfiguration
{
     public string TemporalFileDirectoryPath { get; set; }
     public string BinaryDirectoryPath { get; set; }
}

So later we inject the application configuration wherever we need it:

// Please note that it's a VERY hypothetical example, don't take
// it as an actual advise on how to implement a data mapper!!
public class DataMapper
{
     public DataMapper(ApplicationConfiguration appConfig)
     {
           AppConfig = appConfig;
     }

     public ApplicationConfiguration AppConfig { get; }
     private IDbConnection Connection { get; }

     public void Connect()
     {
           // We access the configured connection string
           // from the application configuration object
           Connection = new SqlConnection(AppConfig.Database.ConnectionString);
           Connection.Open();
     }
}

In summary, and since I love comparing real-world and programming use cases, imagine that you never clean your room and you would use a single box to store every tool you might need some day. One day you need a screwdriver from the whole box, and you know that's inside it... But you need to throw everything in the box to the ground and work out the mess prior to find the priceless screwdriver to complete some home task.

Or imagine that you've bought a toolbox to store your tools in order, and once you need a screwdriver, you know that's in the toolbox and in the section where you store your screwdrivers.

You know that the second approach is the most mind-friendly. That is, when you develop software, you need to design mind-friendly architectures rather than a big mess of unrelated data and behaviors working together.

like image 93
Matías Fidemraizer Avatar answered Oct 03 '22 14:10

Matías Fidemraizer