«« Band-Aids to Brilliance No www DNS Entry »»
blog header image
Roy Learns the Easy Way

Roy is learning about software development the easy way, by making mistakes. The downside is that making all of these mistakes is time consuming. People have made them a million times over. So Roy, let me give you a few tips ...

First of all your observations about event-driven software are correct but it can be cleaned up. The solution involves a strict separation of GUI and logic code. Sometimes this can look strange -- why am I making another function way over here when I can just plop the two lines in that call the database? But you can't have UI code and logic tangled (coupled) like that. Every time you want to make a change to either, you break the other. Bad, bad news for maintainability.

So here's what you do -- make one or several APIs (a fancy word for a group of methods or functions) that your UI can call. Never pass UI objects to this API directly, only the information contained in them. A trivial example would be instead of passing the UI object that was clicked, pass its label or value. Another would be instead of passing a SelectBox back up to the UI, pass back an array of Strings that the UI can make a SelectBox from instead. BTW, I don't remember the exact names of UI elements in VB but they are simple things like that.

Your database problem has the same sort of solution. If your application has many defined layers, you don't have to worry about other people being done -- you can fake it by returning dummy data that works in the UI. This is called stubbing.

So you have at least three layers in this situation: the UI, the logic and a layer to talk to the database. SQL code and recordsets never leave the database layer, just like UI widget objects never leave the UI layer. Your UI never knows about SQL, it just deals with arrays. If you design this way, your coupling is low -- you could replace your UI without touching your logic layer, for example. You could optimize your database queries without touching your logic layer as well.

This solution has one drawback however: you may need an intermediate data object -- it depends on what type of data you are passing between the UI and the database. If you are just doing simple String arrays then no problem. If you are returning multi-row recordsets from the database to the UI, these have to be converted to arrays of Objects that can hold all of the recordset data.

Of course, software engineering is about trade-offs. You could, as a compromise, use the recordset format as the transport format. The risk you take is that the guy doing the GUI has to deal with a recordset instead of objects, and if you ever change the columns in the database -- which changes the recordsets that are returned -- you may break the GUI. Yeah, ick.

UI
Logic Layer
Database Layer
SQL Database


So back to stubbing. If you're in the sitation where the guy doing the SQL backend isn't done you can write a method in the database layer that returns some generic/default/dummy data arrays to the logic layer. The method should take the same input variables and return the same type as the final version of the method. Now you can test this database function from the UI via the logic layer: the dummy data appears in some UI element.

When the SQL database stuff is done, you rewrite the stub so that it works using the data in the database. Since you already wrote the connecting code from the UI down to the database layer everything is already connected and should *just work*. Stubbing works really well when different team members are working on different layers and the people at higher layers want to keep going when the lower layers aren't complete. You can even unit test stubbed functions to be clear about what they actually do.

Which reminds me -- unit testing. With the logic carefully separated from the UI like this, more of the application's logic can be unit tested. In fact it's not unreasonable to expect that all code from the logic level down should be completely unit tested. If you have logic poluting your UI, you cannot test it as easily and that could lead to bugs and regressions. Keep the UI code as simple as possible.

I'm glad you realised that letting the "QA department" find bugs is not the answer. Developers don't learn to code better that way. Write your own tests, find your own bugs and learn from them. More importantly, the time (=MONEY) to fix a bug that a developer finds himself is several orders of magnitude faster than if a QA department has to find it, report it and verify that it is fixed. I can't stress that enough, it's ridiculous to do it any other way.

Bad code treated badly only gets worse. You can't make a mansion out of band-aids and popsicle sticks. You need some cement (tests) to hold the structure up. Good luck Roy!

Posted at August 12, 2003 at 09:46 PM EST
Last updated August 12, 2003 at 09:46 PM EST
Comments

Excellent advice Ryan! Infact, I've already started writing some stored procedures on SQL Database side so that I can pass up some data to populate my UI to see if my logic is massaging the data correctly and passing it up to the UI...I can fake the data no problem.

One super good point you made is that I totally didn't realize that my UI code should be free of Logic Code. I think I did that subconsciously, but I'ld better double check that.

Hopefully by this week, I will start incorporating vbUnit into some of my code, if not, then some sort of unit test code.

Else
I would go insane().

» Posted by: roy at August 13, 2003 12:56 AM
Google
 
Search scope: Web ryanlowe.ca