[wip][Article] Multi-tiered programming and how it ties to OOP
I have slowly been chipping away at this article for a very long time now. I initially wanted to make a video tutorial out of it, but that became impractical due to my lack of video editing skills, a place to film it and a video camera. So an article it will stay. I am not sure that I am doing a good job conveying everything here, so I want it reviewed before I put it on the article system. Please give me any critique on things I do not explain well or otherwise did wrong.
The primary purpose of objects is to be a part of a multi-tiered architecture. While this is nearly never needed in smaller programs, designs like this are absolutely imperative to large systems. I will be talking about a very simple approach to multi-tiered architectures, there are far more complicated ones.
For purposes of analogy, we will look two stories about cars:
1. Bob needs to go to his friend’s house which is 1.2 miles down 4th street and 3 miles down main. To complete this task, he goes into his car and builds a car that is engineered to get out of his driveway, drive 1.2 miles down 4th, take a 90 degree turn then go 3 miles down Main. Bob did get to his friends house, but has to re-engineer his car to drive the way back. To Bob’s dismay, his mother gives him a call and wants him to visit. While Bob loves his mother, he does not remember the way to her house, he can not remember if he needs to take a right at Maple or a left at Maple. He will know once he gets there though because there is an ugly tree next to where he needs to turn. So Bob will have to re-engineer his entire car on the road when he knows which way to go.
2. Frank wants to his friend’s house. Frank, like bob, does not remember the exact way. To get around this solution frank builds a car with wheels that move forward when a pedal is hit, they can also turn when a wheel inside the car is turned. This way Frank can use the car to go exactly where he tells it to. And when he gets home, he can use it again!
Both Bob and Frank got to their destination, but Frank did it far more efficiently because he designed a module that did not complete a specific task, but completed a generic task. He then told his generic module exactly what to do in a way that would only be used once. This way, his module could be used over and over again to complete various specific tasks without redoing the same things over and over again.
Your programs should work in a similar way; there are two layers that complete similar tasks to the analogy above. Your core classes and functions are the car; they compute the core logic and do the core tasks but do not actually execute any of it in your program. The layer that executes it is what is often called the scripting layer (which in the story is you while driving). The scripting layer does not compute logic, but it uses the resources given to it to complete the task you want.
To put this in a practical example, I will use a project I recently completed at work (I can’t give you any actual code, its Visual Basic anyways). The purpose of the program was to query a certain feed, get the real estate data, download the photos off of their server and update our database with its information. The feed could also indicate that a listing has been taken off the market, so I would have to remove those listings from our server. Each real estate listing has a unique seven digit unique listing number (LN) associated with it. Each listing also has up to nine photos associated with it
I started by writing a set of functions that could download all the photos of a given LN to our server. I then wrote the functions that copied the necessary data to our database. I also wrote functions to delete anything I could create. I decided to place these in an object because they needed to use many of the same resources. So at the end what I had was an object who’s members could update or delete everything we needed in regards to the RETS data.
However, I did not have a working program yet; all those functions need something to use them. This is where the script layer came into the picture. In this part I queried the RETS database and compiled a list of new/deleted listings. I then ran though this list and executed the processes that needed to be done (add or delete).
You might be asking “why did I run the query and compile a list in the script layer?” The answer to that is because it was simply too specific to put in an object or function. The query was very narrow in use and relied off of a number of command line parameters, the list I compiled was equally narrow in use. It would have been inefficient to place it in the core since they were not in any way generic. There is no solid line to where to place code, some code obviously belongs to a certain layer, but you will often be confronted with code that can be in either layer and not be a significant breach of logic. This I where you come it, you are the only one who can say where to put it. Just do what makes the most sense to you and it will be fine. If you realize you made a mistake, learn from it and better your ability for next time.
Back to my story, about a week later the unexpected happened: I was asked to make a web application where staff could browse listings and manually administer them if needed. This required functions that could grab or delete data based off the LN of a particular listing. Sounds a lot like what our automatic updater does, except a person is calling the shots based off of website forms opposed to a generated list from a feed. Because I abstracted my generic action code, I was able to make it into a DLL* and share the functions between the program and the webpage. Instead of querying the RETS database, I had wrote a web interface where they could find listings and click buttons to do things to them. These buttons triggered off the exact same command from the exact same file for the exact same results. The best part is that I did not have to touch a single line of my original update/delete code.
Should I have programmed my entire application as a script, I would have had to dig though the entire program finding the specifics I needed, I would have also had rewrite a lot. But since I used a multi-tiered architecture I was able to cut my second project into a fraction of what it would otherwise have been. This is just one example of how multi-tiered architectures can help you. This program was rather small (<700 lines) so nothing too fancy was needed, I just needed to abstract my core functions from the code that runs them.
To give a visual diagram, this is the basic layout:
How do classes tie into this? The simple answer is that they make your live far easier. Class functions can share variables that are not available anywhere else; they also give you a straight forward way of knowing what is what. Another up is that when a class has been properly written it can simply be copied and pasted since all its dependencies are within it or clearly stated. If you use global scope variables to share with functions, it is far hard to find everything that it needs. Furthermore, defining loose things are bad when you are working with code that is supposed to be generic. Variables defined at the global scope can be readily modified by anyone at any layer of the programming, making your multi-tiring little more than fancy file naming.
*DLLs are files that contain pre-compiled classes and functions for other programs to read, they do not run by themselves. This means that one set of functions can be shared by as many programs as you want as long as they make a reference to it.