This morning I was provoked by Seth Bienek to rant a little more than Twitter would allow about getters and setters. You see this all started when Brian Rinaldi made the mostly innocent statement, "90% of the time, writing getters/setters is a stupid, annoying and utterly useless task." So my question is simple why the hell are we writing these getters and setters?
Now before you go off on your happy Groovy has, or ColdFusion 9 will have, or Action script as implicit getters and setters kick maybe I should reword my original question to provoke some more thought. Why the hell is your code written in a way that you need useless getters and setters? This just smacks of a poor design, probably a data centric design. I know there are some valid reasons why we need them, transfer objects for over the wire communication is a great example of when you might need objects with useless getters and setters (though I would argue in this case they really aren't useless now are they??). Please stop justifying your obsession with getters and setters, chances are if you are using tons of getters and setters your design sucks. Now don't get all offended your design could be perfectly fine, but think about it objectively.
We all need to realize how much crappy code we have laying around that we think (or thought) is good code. I mean we did pushed it into CFCs so it's good code right? Yeah not so much. Take some of those objects you have laying around and give em a good looksee. You know that one that has 25 properties and 52 methods, 25 of which are getters and 25 of which are setters. Yep that ultra important one that you spent half a day debating if it should have a DAO or a gateway. Alright now that you have your steaming pile of dung do a search on "variables." and replace it with "this.". Hey look no more useless getters and setters! I can hear you blindly complaining about encapsulation from here. Bluntly put, who gives a flying pig's ass about encapsulation here? You are getting zero, zero, value from your methods and really all your are doing is freeing yourself to rename your internal variables later, yippie. Besides, how many times have you looked at a variable and said that name sucks I want to change it? Okay so maybe a couple of times. Well good thing it was so encapsulated behind that method, it made that variable change so easy... except now the method name is different from the variable it affected. Every time you look at that object now it's like a game of guess who trying to remember what methods match to the [better named] variable. The whole point here is think about what you are doing and think about your design before you blindly make a variable private and put useless getters and setters in your code*.
At this point you're either drinking the cool aide or really wanting to punch me. Hopefully you are drinking the cool aide. Wait you are still not sold on this? Okay listen dude[t] if all your are doing is writing getters and setters and not doing anything in those getters and setters it's freaking pointless. Don't give me this whole "well what about the future" crap either. We can speculate all day about the future of our applications. As developers we love puzzles but we need to be pragmatic and ask what does the current design need. If we speculated all day we wouldn't ever get anything done, trust me I've been here unproductive and hating life. Remember "What's the simplest solution right now?" Don't introduce unnecessary complexity. Just access the variable directly or just replace it with what your object most likely is anyway...a structure.
Hopefully most of you are not satisfied with this uber structure idea. Trust me, I am not overly thrilled with it but given the choice between useless getters and setters or public variables I'll vote for public variables each time, until someone convinces me why to not. Besides for some it will save them a whole bunch of typing and they can still go to bed at night happy they are using CFCs. If you are truly interested in why I think you should not waste time on getters and setters that are useless it's because getters and setters are mostly well useless. I know there's some circular logic in there we'll work through it here in a second bear with me.
When you design your objects, and more importantly object interaction, try to avoid objects that are data consumers or providers. If the majority of your objects are data consumers or data providers then you have successfully taken something that is probably simple and best suited for something with much less OO overhead and made it complicated and less maintainable. Congratulations for getting your CFC check mark for the resume! Objects should be behavior driven, asking each other for favors. Does that mean applications I write do not have getters and setters? Hell no! I am just as guilty as the next person for writing Data Driven OO. I've got over my OO kick though I am comfortable with knowing where the rigors of OO makes sense and where they make waste, finding that balance isn't easy and its hard to teach. I'm writing this article as much as a reminder to myself to not be an idiot as I am for anyone else. Just because you have getters or setters does not mean your objects are not doing something, they just aren't doing enough probably. Sometimes getters and setters are important. For example, maybe we pop data off a stack on a get or validate data as we pass it into our object. Another example might be we went ask an object to do something but creating objects internally is bad so we provide a setter to inject the object into ours. Don't get confused with this whole encapsulation when you don't need to leverage it though. If you don't do anything that requires encapsulation don't get all complicated on me. Thanks for sticking it out to the end, enjoy the cool aide.
*As an aside in Adobe's ColdFusion each method is an inner class in Java so all of these useles getters and setters are also forcing the JVM to load bunches and bunches of useless classes as well. Generally I don't like to focus on things like this but I figured it would be a good mention for folks.
Monday, October 06, 2008
Subscribe to:
Post Comments (Atom)
20 comments:
Hear fucking hear!
So many developers go overboard on this (you almost never *need* to use them).
I use public variables if I don't need something in the class to update when I set/get it. If I'm building my classes correctly, I don't need many public variables anyway.
I often use implicit getters and setters if the class needs to run code on the value before returning it.
That's it. I use public properties on my event classes, I use public properties on my value objects. I use public properties, and I'm proud to say it!
I totally disagree because although useless getters and setters are at first stupid. My experience is that it is in the long run easier to have them (Why can't Flex Builder generate them :s).
Let me explain, public variables can be changed without the class knowing, this is the same with useless setters, I agree. But rewriting a public var to a getter/setter is more work if you want to expand the functionality. Even worse, because the getter/setter is not there the dissision to make an update with this construction is hardly seen.
If there is a need for "not" critical data to store somewhere I use an storage class with a getValue and a setValue method that can store data with a unique key. But crtical data always gets getters and setters in my designs!
I said 90% for a reason (though its probably more like 95%). There are times when your setter or getter does more than just a simple cfset or cfreturn. Your strategy would not not really seem to handle those situations since it doesn't encapsulate access to the value.
Encapsulation is still the key benefit, but it has to do with accommodating future change more than anything else. By using a getter and setter, you are free to add additional BEHAVIOR to the method in the future. If you use public properties, this is going to be a lot harder to do and is probably going to involve a lot of extended replace. It certainly would be wonderful if CF had implicit getters and setters, but since it doesn't, and since generating getters and setters is so utterly trivial, I still think it's better to use them.
That said, the related issue of focusing too much on data-centric objects is completely valid. Getters and setters does not equate to OOP.
I see we still can not get over the in the future I will need it hump. Now if we are talking pragmatically I am going to have a feature before release that needs it yes getters setters are good, then they are not useless lets move on. If this release, THIS RELEASE, does not need it don't bother with it. There are exceptions to this, as with everything. An exception to this is if you are providing a public API (by public I mean outside of your source tree you are controlling)that needs to be defined and rigid. Again be honest with yourself and don't go thinking well someone might want to use this. Don't be afraid of refactoring code (you have tests right?), I know it sucks a bit in CF but I am confident that will improve. If refactoring is your biggest fear so you generate/write your getters and setters I can accept that fear and happily say I do not live with that fear.
@Brian Yes I totally agree with what you are saying. I was focusing on those 90% that are a waste. The other 5-10% certainly are not useless. I did not use enough words to try to express I did not think wrongly of your comment. I just trying to give my rant some context. I hope I did not misrepresent you, if you feel I did let me know I'll edit the post.
It really has nothing to do with fear. If it takes me 30 seconds to write out 10 the properties in the THIS scope and it takes me 40 seconds to instead generate 10 getters and setters, what, exactly, is the issue? I'm losing nothing, but gaining flexibility and ease of maintenance down the line. If I was typing these out by hand that would be one thing, but I'm not. We're talking about the exact same effort. It will take far longer to track down any place in the code that references the property and change it to a method call later on, especially if you've moved on to another project or someone else is doing the work.
There is also a valid argument to be made regarding consistency. Rather than seemingly random (from the perspective of external code) references that are to properties sometimes and to methods sometimes, using getters and setters provides a consistent way to interact with the object.
I appreciate your opinion and can see why someone would choose to disregard getters and setters, but to me, because the difference in effort is practically zero and there are indeed some benefits to using the getter/setter approach that are worth considering. This all really comes down to personal preference as far as I'm concerned.
Brian Kotek
@The other Brian :)
At this point I do think we are entering the ever dangerous preference zone. Not to mention spending entirely too long discussing something that means very little (there are implications to overall design here which is indeed the bigger issue). That being said I did want to respond to your points, because I think they are valid to an extent and it also points out a weakness in ColdFusion as it stands today.
"There is also a valid argument to be made regarding consistency. Rather than seemingly random (from the perspective of external code) references that are to properties sometimes and to methods sometimes, using getters and setters provides a consistent way to interact with the object."
This is very true and something I thought about addressing but I didn't have a great retort to this so I left it out. I still wanted to rant and wasn't going to let this stop me from doing it. You could look at consistency in a different respect in that getters/setters indicate behavior happening and public ones (obviously) indicate there is not. My problem with this (and why I did not bother with getting into it originally) is why the heck should my object's consumer care if other things are going on or not? They probably shouldn't! Again it is a great point.
"It will take far longer to track down any place in the code that references the property and change it to a method call later on"
This is so very much a limitation of our IDEs for CFML. I'd like to think in a couple of weeks after Max we can all agree this will not be an issue, but maybe Adobe plans on something else to make a developer's life easier. Really a solid IDE should be able to refactor code like this in no time, and my unit tests should point out any stragglers. Is it much effort to just write out the getters and setters? Nah not really, maybe I should have a follow-up rant more about designing objects. Object design and the need for useless getters and setters in the first place is indeed the real issue.
Really excellent post. You make a lot of points that I think are hard to argue with because so much of the benefit of OO seems to be about the future, which hasn't happened.
I am not a fan of explicit getters and setters. Rather, I like using the OnMissingMethod() to dynamically access Get/Set generic methods. I think this is truly the best of both worlds.
On one hand, your method names dynamically reflect your variable names, so if you want to change the names, that trickles down to the getters/setters as well.
On the other hand, your CFC can literally be a list of property variables and it will automatically have getters and setters.
You can also override the generic getter/setters by creating actual functions that override the dynamic functionality when necessary.
To me, I don't see why any one would hardcode a getter / setter that literally returns am uncalculated value.
.... best of all worlds.
I have a number of concerns with using onMissingMethod for getters and setters is the same problem I have with generic getters and setters: the object has no API. If were to look at such a CFC in the component explorer or run it through an API docs generator, it would basically be empty.
Second, if you're actually writing out cfproperty tags on top of the actual code (in the THIS or VARIABLES scopes) you've already written nearly as much code as it would take to just do proper getters and setters.
Third, I can quite easily imagine situations where having the method names automatically change in response to a change in a property name could be a disaster. Part of the point of an API is that it should be stable. If the method names suddenly alter because I changed a property name, that could break a lot of code in other places.
Consistency again comes to mind as well. Folks relying on ColdSpring's autowiring, for example, (which require setters to determine what to inject) must have those, so now we're talking about a situation where "sometimes" there's a real setter and "sometimes" there isn't. The only way to tell is to actually open the file and look.
And finally, there's the logic required in the OnMissingMethod in order to handle this. I have to assume this means parsing metadata, checking for existing methods, invoking them, etc. It's likely to be fairly complex. So in my mind one is trading an extremely simple, if mundane, task for a more complex solution that does the same thing with less clarity.
My opinion of course, but again, since I can spit out a series of getters and setters in just a few seconds I feel like it's easier, more clear, and more flexible just to do that.
Regards,
Brian
I use getValue/setValue for most things, though I added an onMissingMethod() recently for folks who prefer getXXX() and setXXX(). I don't use it because I don't think it's necessary, and in many cases getValue/setValue is a lot easier. When you want to set multiple properties for example, it's easier to set then in a loop with setValue() than with individual functions. The special handling is done dynamically within setValue().
Actually I wrote a fairly long article about duck typing a little while ago that talks about that as part of my explanation of how to be more productive with duck-typing style development.
Ducks Are Loosely Coupled
http://ontap.riaforge.org/blog/index.cfm/2008/5/19/Ducks-Are-Loosely-Coupled
The places where I don't use getValue/setValue are generally where I'm setting a composed object. There's a setDatasource() method on many of my DataFaucet objects for example, because the datasource is an object (not a string) and I don't want it lumped into the "instance data" (which in my case are generally strings). I tend to have very few of those.
Totally agree that an object should be behaviour based not data based, but don't like the idea of breaking encapsulation.
@BK To answer the point you raised about no API with onMissingMethod (and I agree an object should have an API) you can overcome this by using cfproperty. I blogged about this a while back and I doubt I'm to only one to have thought of this.
www.aliaspooryorik.com/blog/index.cfm/e/posts.details/post/cfproperty-onmissingmethod-and-data-type-validation-140
*red koolaid mustache dripping down chin*
I love this discussion. I think a lot of people's preferences are driven by who/what is consuming their objects.
If I am writing a bean to use myself in my own little internal app (arguably a large percentage of reality), I really don't care if it has no documented API that CFC explorer can show me.
If I am writing a web service, or a black box for another team of external programmers, I'm going to be a lot more concerned about internal changes not breaking external interaction.
A lot of OO best practice seems to be aimed at the latter.
I use an ORM so I dont care either way about getters and setters.
But I do believe you hit the nail on the head when talking about how people spend too much time trying to "future-proof" their applications. I cant tell you how many times I heard, "well, what if we want to change from mssql to oracle down the road?"!! It seems like there are CF developers who either just write code to get the app to work (usually ends up as spaghetti!) or they totally over-engineer their applications to future-proof or pre-optimize the app when its not needed. There really doesnt seem to be a group in the middle of that, well there is but albeit a very small group.
Matt Quackenbush and I had this discussion a few weeks ago. I dont understand why developers spend weeks pre-optimizing their apps to serve 500 concurrent users when they wont reach that level of service for years, if at all. The same goes for writing gobs of code just in case we want to do something in the future... I just dont get it!
I think some people are missing Adam's real point here... See this article and see if it helps:
http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
The point is not encapsulation vs no encapsulation, it's about whether you should even expose your data at all in any sort of per-item format.
I agree that code that relies on getters and setters is indicative of questionable design choices. As far as I'm concerned, in an ideal app no object would need per-property access (either via methods or via properties) at all.
However, the reality is that data has to get into the object somehow. And in that case, in my opinion, setters are preferable because they allow you to add additional logic later for no cost now. And data has to come out of the object in order to display it, where getters are preferable for the same reason. Even if one takes the route of having objects that can render themselves, a composed rendering object still has to be able to get at the data in order to do anything with it. These are the only two cases where this should even be an issue, but they are two cases that must be accommodated, and until we see implicit getters and setters in CF, I still feel that having actual getters and setters is the better option. They take no extra work to generate (there are countless tools or snippets that will do this at a keystroke) but offer substantial advantages.
I am of the mindset that taking a step back and approaching the complexity of your application's design as a whole is very much one of the most significant factors in determining how 'strict' you have to be with your approach to getters/setters.
Brian made a good point earlier about the ColdSpring framework and by choosing it, having an implied dependency on your design, but that doesn't necessarily have to be the same approach you use for a three-template, two-CFC comprised app.
As a concrete example, we're in the midst of a project built on top of ColdSpring that is interfacing with a Java engineering team for the middle tier. Their business objects drive their administrative tools *and* business logic in our app. They expose those objects via WebServices. As you might expect, there is a lot of VO transmission across the wire. Yes, their VOs are getter/setter ready.
The problem faced was that our CF team was beating them to the finish-line and, in order to stay on schedule, we changed our CS wireup to stop pointing to a WSDLDao and start pointing to a SQLDao, wherein our CF-based VOs were responsible for data transmission.
The dependency on getter/setter implementation for our VOs is vital in this example, because when we eventually throw the switch and point back to their WSDL, we expect the remaining app to continue to function as normal (in theory!), as the app already has ingrained within it the getter/setter mentality.
An agreed-upon standard methodology of VO data access was appropriate here. Since both the Java team and our CF team implement getters/setters for access, swapping out an entire DAO or Gateway later on down the road provides a means to remain consistent.
Holy Crap! I haven't read a rant with which I agreed so wholeheartedly in a long, long time.
That said, and having spent most of the last month buried in a Flex/AIR project, I've come to learn about a couple things that CFers who've never worked outside ColdFusion would understand:
1) Refactoring tools
2) The fact that AS3 can go from this:
package foo {
public class Foo {
public var foo:Foo = new Foo();
public function Foo() {
}
}
}
to this:
package foo {
public class Foo {
private var _foo:Foo = new Foo();
public function Foo() {
}
public function get foo() {
return foo;
}
[Bindable]
public function set foo(newFoo:Foo) {
this._foo = foo
}
}
}
For the lack of these tools, for now, I prefer to use getter/setter pairs in my CFCs... so yeah, future proofing is the name of the game, but between my CFEclipse snippet and the extra 2 or 3 characters required to use a method instead of a property, I'll stick with my get/set pairs until we have a wider variety of options.
I just don't see using methods as any more time-consuming than properties, especially since the variable still exists as a dependency within the application... and get/set methods need to be limited just like public properties do.
I love what you said, though... seriously! The focus, however, is more on the fact that objects with lots of properties OR lots of get/set methods are poorly designed. OO is about behavior, not about data. Switching from get/set pairs to public properties does nothing to minimize the data-centricity of a design if the developer doesn't understand that "tell, don't ask" is what this is really all about.
I suppose I should have specified that consistency in the API of an object is an important consideration for me... once we have the ability to swap a property for a getter for a property, or to refactor, that's no longer a consideration. Until then, though, I'mma stick with what's most stable where an object's API is concerned and continue to focus on behavior as the key factor in development.
lol, how many of you actually program in at least 2 other languages (and at least one of those being not like C)?
Post a Comment