Making complex software, less complex

I’ve spent quite a bit of time dealing and developing complex software. What I mean by complex is not the actual code(though in some cases it has been) I mean that the software itself deals with lots of different things.

For example, something like Twitter would be less complex, where as Facebook would be a great deal more complex, as it deals with not only sharing, but messaging, apps, pages, etc.

So after trail and error, and dealing with complicated systems, and cleaning up complicated code, I’ve came up with a few guidelines that I use in order to make sure the software I work on, while being able to do a myriad of functions, is also easy to maintain and relitivly simple to deal with.

Your Code is Leaking

One of the biggest issues I’ve ran into is leaking code. Here’s a simple example of leaking code.

//This class does everything
public class UberClass : IDisposable
{
	public List<User> Users;
	public DbObject Database;
	Public MessageQueue<User,String> Messages;
	public const String ConnectionString = "local:23;faceroll";
	public UberClass()
	{
		Database.Open(ConnectionString);
	}
	public bool AddUser(string name)
	{
		var u = new User(name);
		Users.Add(u);
		Database.Store(u);
	}
	public User GetUser(string name)
	{
		Database.Retrieve(name);
	}
	public User DeleteUser(string name)
	{
		Database.Remove(name);
	}
	public void MessageUser(string name, string message)
	{
		var u = Database.Retrieve(name);
		if(u!= null)
			Messages.Add(new MessageQueueItem(u,message);
	}
	public String DequeueMessage()
	{
		return Messages.Dequeue();
	}
	public void Dispose()
	{
		Database.Close();
	}
}

This piece should also be segregated from this class. In this example, the messaging is leaking into the database code, which both leak into a class with no real concise purpose.

In an ideal environment, you would have any direct access to your database all wrapped up in a custom class, sitting on top of a cushy interface, and far away from this code.

The reason this is a problem, is consider if you decide down the road that you need to change your database, or the library changes, or you just want to store your data a bit differently. At this point you will be modifying sometimes hundreds of files in order to make the switch, which also brings with it hundreds of chances to get it wrong, and hours or days of time essentially wasted.

Segregation and small concise objects in development are two of your best friends.

API: Internally and Externally

API isn’t just good for web development, it’s good for everything. Essentially the idea here is each piece of your software has a specific task, and not everything is exposed. This is a bad class

public class Users
{
	public List<User>Users;
	public Users()
	{
		Users = new List<User>();
	}
}

You may be thinking “Wow, that’s nice, I can directly access the users, and do anything I want with them from any other spot in my software.” Without taking into account concurrency, the problem becomes, what if you want to store your user list in a database instead of a list? How would you easily transition between the two? Easily, you wouldn’t.

Here is an example of something that’s a little more sane

public class Users
{
	private List<User>Users;
	public Users()
	{
		Users = new List<User>();
	}
	public User GetUser(string name)
	{
		return Users.FirstOrDefault(x=>x.Name = name);
	}
	public void AddUser(User u)
	{
		if(!Users.Contains(u))
			Users.Add(u);
	}
}

Notice now you don’t have direct access to the Users list, instead you have a specific couple methods to interact with it, so if we wanted to change to a system where it was backed by a database instead of a list, we could do this:

public class Users
{
	public Users()
	{

	}
	public User GetUser(string name)
	{
		using(var dbc = Database.GetClient())
		{
			return dbc.Find(x=>x.Name = name).FirstOrDefault();
		}
	}
	public void AddUser(User u)
	{
		using(var dbc = Database.GetClient())
		{
			dbc.Store(u);
		}
	}
}

Catching on? The nice thing is if we try to build our software in a modular way with specific API’s, then we can easily change one file, instead of changing hundreds. Ideally we would create an interface for Users, and then build tests for it, but we won’t get into that here.

I find it best to think that every class has it’s own API(which is one thing I like about Java, get and set functions, as opposed to directly accessing the data).

Use a module based architecture, even if you are the only one developing the modules.

This is something I personally think works wonders. What’s nice is that getting your application off the ground takes substantially less time, and features can be added as needed, as opposed to trying to make everything work at once. Not to mention when you develop in this way, the above two points are almost unavoidable.

When you use a module based architecture, one piece failing brings down only once piece(if done properly), where as if you build it into the actual application it has the potential to bring the whole system down.

Another problem that would come about is adding, updating and removing features. Sure if you make sure to build everything modular, you shouldn’t run into much problems, but using a module architecture, it literally forces that separation, and makes it more difficult to “cheat the system”.

Wrap it up Already

It’s imporant to note that there is not a one size fits all development strategy that we have to work with. There are many types of programming languages, and many different methodologies, but after working on many good and bad projects, I’ve found that when developing using OOP, that this seems to be the best fit for me, and the teams that I’ve led or been a part of.

EDIT: Changed the plugin part to modular, just makes more sense that way.

3 comments

  1. Diego Vieira says:

    Cool, very nice post.

    • kellyelton says:

      Thanks for reading. Don’t write often so I figured I could start writing blog posts to get my chops up.

  2. html6game says:

    Very good method. It is worth learning.

Leave a Reply

Your email address will not be published. Required fields are marked *

*