Kenneth Ismert
kismert at gmail.com
Mon Apr 11 15:09:32 CDT 2011
John, I understand the reasoning and all however... because the code is no longer > contained within the object that needs it, you now open yourself up to the > old "I need to modify this method... oops... that change breaks something > else that uses the code". > It is always possible to over-factor, and merge two similar pieces of code together that really should be separate. In that case, you factor the code back into multiple pieces, and correct the dependencies. > Class programming exists for a reason. Placing code in the object that > needs the code exists for a reason. Black box programming exists for a > reason. The reason in many cases is to prevent exactly this kind of > interaction when we accidentally change a piece of code used in many places > and break one of those places. > I would submit that calling side-effect free functions from a class does not pierce the black box. The important things, state and access, are protected by the class. But the function can be anywhere: built-in VBA functions, Access application methods, or DAO library calls. You undoubtedly call these functions from within your classes. > Yes, there are instances where lots of different things need the exact same > code, and yes, I have been known to call module functions from classes, but > it truly is a questionable practice in most cases. > Test cases replace questionability with a guarantee of proper function. The function shouldn't define what it does -- the test cases should. If changes to a function break a test, then you know immediately that there is a problem. Functional unit testing guards against changes that would break dependent code. I haven't found a reason why classes can't rely on properly crafted and tested module-level functions. -Ken > > John W. Colby > www.ColbyConsulting.com > > On 4/11/2011 1:10 PM, Kenneth Ismert wrote: > >> John, All: >> >> I'm going to expand a little on what I'm trying to get at. This post >> really >> isn't advice on what you should do. And it certainly isn't criticism. >> >> I have been returning to the old Lisp idea of functional programming: >> libraries of functions that act only on their inputs and only return a >> result. The goal is 'side-effect-free' -- inputs are NEVER modified, and >> external variables are never referenced. If a function needs to return >> complex information, it returns either a type or an object. Database >> functions unavoidably have side-effects, but these are regarded as >> 'external' to the code, and are explicitly documented. >> >> The thing that surprised me was how well libraries play with objects. >> Libraries provide discrete, testable chunks of code that support any >> instance. Libraries separate functions into common-sense groups. Classes >> provide an instance wrapper over the libraries, stringing functions >> together >> to support the application. >> >> Plus, it is pretty easy to convert classes to this scheme while >> maintaining >> compatibility. >> >> The advantages became apparent when I refactored some of my early >> monolithic >> classes. These large, 'kitchen sink' classes had dozens of methods which >> mixed database, business, and application functionality. They were >> unwieldy, >> hard-to-understand, and hard-to-extend. I simply copied the class into a >> module, stripped out the instance stuff (properties and module-level >> variables), and turned the methods into side-effect-free functions. I then >> stripped out the code within the original class methods, turning them into >> wrappers calling library functions with their instance variables. >> >> The result: classes become lightweight, making their functionality much >> more >> obvious. Compatibility is maintained, but the new system is much easier to >> refactor and extend. >> >> The class on-top-of function approach is also a good answer to those who >> want to re-use your code, but can't because they need some method that is >> marked private in a class. They typically demand that all methods be made >> public, which is usually silly because the class designer has good reasons >> for limiting the public visibility of certain methods or properties. >> >> But with a function library, you can have your cake and eat it, too. >> Classes >> hold the instance information, and interact with libraries in an >> instance-safe way, because the functions never modify their inputs. Others >> with different needs can call the functions directly, or write their own >> classes. Heck, I even find myself cramped by my own classes at times, and >> having the option to call underlying functions directly has benefited me. >> >> Writing test code for functions is much easier than for complex class >> systems. Test code provides reasonable proof of reliability. Reliable >> complexity can only be built out of small, simple, understandable, and >> testable pieces. >> >> -Ken >> >>