Refactoring Exercise 77
So I’ve written a somewhat ugly method with the intent of having people clean it up. Want to give it a try? Post your results and then I’ll show what I ended up doing in a few days (or after the activity dies down).
It’s in Java, but feel free to post in other languages. I’d be interested in seeing something in whatever language Michael Feathers happens to be deeply studying right now!-)
Oh, and if you feel like going “overboard” and using a few design patterns just because you can, I’d like to see that as well.
Here it is:
public void take(int v) {
if (currentMode == Mode.accumulating) {
int digits = (int)Math.pow(10, (int)Math.log10(v) + 1);
int x = stack.pop();
x *= digits;
x += v;
stack.push(x);
}
if (currentMode == Mode.replacing) {
stack.pop();
stack.push(v);
currentMode = Mode.accumulating;
}
if (currentMode == Mode.inserting) {
int top = stack.peek();
stack.push(top);
stack.push(v);
currentMode = Mode.accumulating;
}
}
This assumes a fair bit about how much we can change dependent classes, but assuming that
Mode
is specific to whatevertake(int)
is a member of, I’d go with something like this:So
Mode
becomes a strategy and not a state.My initial refactor assumed that the Modes were actually objects, not ints from an enum:
I see some other things, but I’m interested to see what others have. I’m sure some of the stack operations would be clearer in a different language.
My Ruby solution would look like this:
Instead of throwing an exception I could just fallback to a default state. But if someone extends this class it could be interessting to know which method returns an invalid state/method. I would still prefer compile-time errors :-\
After adding some behavior describing tests I refactored to a strategy with some influences from the state pattern. Mostly I was influenced by Refactoring to Patterns on this. On a second note I don’t like the mess I ended up with.
This is C# Refactoring with a focus on readability.
In any event Take itself seems odd in the sense that it does several things (handle v and change the mode) and its name does not say anything on what it does. So there’s probably a need to refactor the stack to remove the take method altogether. It is hard to understand without the full context so I didn’t try to come up with something “smart” instead of the case/if statements
My first thought is that if you’re in accumulating mode then the value on the stack is going to overflow pretty quickly, since “int” isn’t very big, and you’re multiply by powers of ten. Related to that, if the value passed in is negative then you’ll get an error on the log10 call.
Anyway, here’s some C++ code:
Here is a scala version. Structure looks pretty much like ruby but uses pattern matching.
class StackOps {
}
Of course I have tests for this.
Anthony makes a good point regarding handling negative numbers. In practice, the take method (as in take a digit – deliberately a bit misleading for the exercise) could just as easily use a character or verify that the value coming in is a value between 0 – 9. I left it as is to accommodate different kinds of clients, but that’s probably better reserved for the UI (digit accumulation requirements would be different for a GUI versus say a text UI) – it’s probably a bad assignment of responsibility (SRP violation maybe) and certainly could be handled with an adapter of some kind (or the control of an MVC).
Anyway, I’ll keep watching (though I haven’t got anything better than what I’ve already seen!-)
Here’s a C# refactoring with an eye searing dispatch map rather than switch.
Here is mine. Mode class is a State.
Submission is slow. Progress bar needed slow
During my evaluation of the algorithm by bringing in some tests to describe for myself what happens, I realized that the calculation in accumulating mode does the following: - take the top of the stack and assign it to x - calculate the number of digits for the given parameter v - multiply x with the number of digits - add v
Describing this with some tests leads to: x=5, v=5—> 55 x=4, v=23—> 423 x=589, v=1243—> 5891243
The calculation from Brian seems to wrong on this, I think.
My mistake. I misread the log line as operating on x instead of v.
So, we wantWhich does boil down to the original algorithm. I’d like to amend my answer to include the expanded algorithm, since I got confused with the more concise original version.
Note to self: Never trust excel to do integer math. I missed a trunc() the first time around.
I agree with Markus that Brian’s calculation looks wrong. But so far his is what I would consider to be the cleanest solution. It is very straight forward to figure out what is going on.
Some of the others, such as Coda Hale’s approach of embedding the logic into the enumeration is quite a cool idea. But then having to pass the stack into the enumeration seems a little backwards to me.
Likewise with Cory Foy’s overloaded methods, to me this adds confusion. I’m stupid and I want the code to point me at exactly what is happening, not that it makes me have to figure out which method is being called.
I started off following Brian’s approach, but then as I said I’m stupid and couldn’t think out a neat way of coding the calculation. On idea went as far as: But that doesn’t deal with negative numbers as was also pointed out…The obligatory Haskell solution:
Uncle Bob is right. While I did write unit tests first, I was think about the state and not the digit accumulation. I did test that, but I missed an equivalence class. Turns out, the log base 10 of 0 is not a number. The (int) of that is -2 billion and the pow of that is 0 after another cast. I wanted a mess!
On of the .Net solutions used the length of the number, removing that bug. Bob asked me bout and sure enough a quick test ;which he had already created) exposed the problem.
I’m at the airport now wanting to write more buy the iPhone is saying otherwise.
Great stuff so far!
With a pattern. Still ugly though, me thinks, but that’s just how the language rolls…
I didn’t really understand the accumulation calculation, so I had to add a few tests to make sure I didn’t break it. Then it was amazing to watch the duplications appear as I separated the queries from the commands:
oh, good god, allow me to revisit that….
I’d like to play devils advocate and say that the method doesn’t need refactoring, since it is only 13 statements and not hard to understand.
Why should you refactor this method? Note that some of the current refactorings come out to more than 13 statements and don’t necessarily add anymore clarity.
However, this is an exercise so lets assume we have a good reasons to refactor.
For me the code has two responsibilities in one place; the responsibility of the calculation and the responsibility of managing the stack. I’d like to see these concerns separated.
I think Cory Foy’s refactoring is a good start, but I’d change the operations on stack to be methods on the stack. ie: stack.replace(v).
I’d also go further and suggest the following, given I like functors:
Resulting in 4 statements and a flow that is easy to see.
Well let me say I like these ideas.
To those of you refactoring to state/strategy, well done. A little painful, huh? (I think it’s closer to state than strategy, but then they are similar patterns).
Those of you just extracting methods to make it cleaner, good idea. Expressing the intent is a great idea.
I give Anthony +10 points for using pointers to members. And Christian, thanks for the Haskel. I was hoping for an example from that language.
Also, I think James makes a valid point questioning the need to refactor the code in the first place. If this code was already working and not changing, then no need to refactor. Of course, it should never have gotten that ugly in the first place!
So I made some changes per uncle bob’s observation that the calculation was wrong. This did not essentially change my refactoring.
Through some experimentation, I accidentally came up with the following (note that I do nothing, which is special, for inserting mode now):
Then I extracted the calculation and used a looking construct:I certainly like the take method better. I’m not too keen on reassigning to the value parameter (note the change name refactoring), so that’s at least a little dubious. Also, the determineNewTop method both changes the stack (with a pop) and returns a value. Violates command/query separation, but it is also a private method, so I’m not as concerned about that violation.
I like this better. I wanted to use the state pattern, but as the early solutions demonstrate, that makes for a complex result.
FWIW, I also had some FitNesse tests (thanks to Bob Koss): And here’s the Decision Table Fixture to handle this:If you’re interested in the full source, let me know and I’ll make it available.
Brett the final refactoring is very nice and similar to Thomas’.
I think both show a deeper understanding of the stack and hence a simpler approach to using it.
Did separating concerns help with this ?
Note: I would have refactored the original method but wanted to draw out when/why to refactor because as I like to say “One mans hack is another mans quality.”
@Christian Vest Hansen, Srinivas Nandina, and Uncle Bob:
Here is the Scala equivalent of the Haskell version, using Uncle Bob’s magnitude function (not shown for brevity):
James asked:
So separating concerns … As it is, my calculator has a few concerns:
I think it’s OK. While it does have multiple concerns, breaking it out more seems like possible overkill. This is really your original point, right?
Here’s my current calculator: I think there’s more that could be done with this. There are some competing issues:So given this, what next? This “works”, and there’s no changes coming down the pike. Based on that, no need to change anything. But what if there were? What’s next?
How about this for overkill:What about the other suggestion, an input policy. I think this is a bad idea because the input policy is a little too coupled to the input mechanism.
i did get a gist of many posts…obviously could not read them all so i abstain from refactoring (mine was a suggestion on method extraction as the take() method is doing far too many things by itself. others have already made note of it).
Yes, there is a need for refactoring the method because a function must be functional ! And the take() is doing more than what it should. Functionally, its responsibility is to take some value and process it or forward it in a certain manner. In C#, this can be done with Lambda Expressions in a functional approach as demonstrated in the Haskell example, which is by far the most readable code of them all because it is a functional approach.
On the State and Strategy patterns applied, don’t they add up more code than is neccessary? Strategy is probably too specialized a pattern to apply in this scenario and State introduces only more code. If we look at the Haskell example design patterns look ridiculous!
Here is my example in c#, uses the original logic in the post. Also uses the state pattern but each state is just a lambda expression:
using System; using System.Collections.Generic;
public class States { public Action Accumulating { get { return (state, v) => { var digits = (int)Math.Pow(10, (int)Math.Log10(v) + 1); var x = state.Stack.Pop(); x *= digits; x += v; state.Stack.Push(x); }; } }
Here is my example in c#, uses the original logic in the post. Also uses the state pattern but each state is just a lambda expression:
using System; using System.Collections.Generic;
public class States { public Action Accumulating { get { return (state, v) => { var digits = (int)Math.Pow(10, (int)Math.Log10(v) + 1); var x = state.Stack.Pop(); x *= digits; x += v; state.Stack.Push(x); }; } }
Sorry last post got mangled, re posting:
Here is my example in c#, uses the original logic in the post. Also uses the state pattern but each state is just a lambda expression:
Sorry last post got mangled, re posting:
Here is my example in c#, uses the original logic in the post. Also uses the state pattern but each state is just a lambda expression:
Some of the proposed solutions have fifty or sixty lines and add a whole lot of classes and methods. Why make it so complex?
I don’t know about refactoring this short method, but if your goal is an rpn calculator program, you can see mine on my blog of programming etudes at http://programmingpraxis.wordpress.com/2009/02/19/rpn-calculator/.
>@Mike Bria
Neat…I like the fact that you got the actOn methods to shield the reader from the implementation details of stack manipulation….but wait….in Accumulater you didn’t go the whole way… shouldn’t its actOn method be calling something like adjustTopBy(value), rather than stack.push(topAdjustedBy(value))?
@Brett L. Schuchert
You said: the determineNewTop method both changes the stack (with a pop) and returns a value. Violates command/query separation, but it is also a private method, so I’m not as concerned about that violation.
But what does violating command/query separation buy you? Unless the violation pays for itself, how about avoiding it by simply pushing the pop() (pun not intended) out of determineNewTop, and explicitly passing the popped value into the method?:
And maybe, since you tolerated modifying input parameter ‘value’ in the ‘take’ method, you may want to do the same thing in ‘determineNewTop’: drop ‘newTopValue’ and just modify input parameter ‘top’.
Erlang version
obligary use of processes and message passing
and a version without the spawn and messages
Philip Schwarz wrote:
I like it. In fact, I made that change and you’ll see it in the next exercise.
Thanks!
What a coincidence that Uncle Bob’s solution should appear straight after the Haskell one. I say this partly because these are the two solutions that stand out the most (in my view), but more importantly, because while they are so different, they both stand out (again, in my view) as the most readable.
My first reaction when I saw Uncle Bob’s solution, straight after the extreme succinctness of Haskell, was something along the lines of: what a huge contrast…how very long Bob’s solution is compared to the Haskell one…how can it take so much code to implement the same functionality?...
But then I started going back to Bob’s code, again and again, and once I took into account the huge expressiveness gap between the functional and OO paradigms, I have to say that I think that Bob’s solution is just as remarkable as the Haskell one in terms of its extreme readability.
Which of the solutions you have seen would you prefer to maintain?
This is a master at work, producing extremely readable code.
Brett’s original snippet, the one he asked us to refactor, was a single method with 15 lines of code, and a Cyclomatic Complexity (CC) of 4.
Bob has replaced this with 14 methods: nine one-liners, three two-liners, one three-liner, and one six-liner (the magnitude method). While the magnitude method has a CC of 3, all other methods have a CC of 1.
The result is some seriously readable code. No conditionals. Most of the time you are looking at a one-line method! A few times, it is a 2 or 3 line method. Also, while there is still some relatively high CC and high line-count in the system, it has been relegated to a single method (magnitude), which thanks to a very clear name and responsibility, won’t necessarily need to be read to understand all the rest of the code.
James Ladd said:
In my view, while Uncle Bob’s solution is much longer, it is much more readable.
I’ll conclude with a quote from Uncle Bob’s Clean Code:
Sorry, but I just can’t agree with this. Breaking things down into numerous very short methods like that actively harms readability, and it’s long past time people stopped dogmatically repeating “small functions = good” as if it’s some self-evident truth.
Why do we use functions? We use them to define an abstraction, to hide implementation details that are irrelevant to higher-level code. What are you abstracting by writing a single-line function like the ones in Uncle Bob’s example? Probably nothing. The problem doesn’t get any simpler by doing this.
On the contrary, although each individual method becomes trivially simple to follow, a reader now has to laboriously scan through the whole verbose mess to find enough context to understand what is actually happening. This is not an improvement, it makes things much more complicated.
As a result, it took me a couple of minutes just to be sure of the entry point in Uncle Bob’s example that corresponded to the original function. This was not helped by having several methods on different but intimately related types sharing the same name, compounded by virtuality in one case. I’d read and understood the mechanics of the entire original code snippet in far less time.
As for the cyclomatic complexity, of course we want to keep the logic straightforward, but let’s be serious: we’re talking about a single real decision here, a simple dispatch based on what appears to be a choice of three possible modes. The consequences of that decision affect a single piece of shared state (the stack) and are defined by a single extra input value (the parameter to the take function). Distributing such simple logic across 14 different functions over more than 80 lines of code is madness.
Moreover, the decision is based on a simple value, not a type, so obscuring it by using an enumeration/virtuality trick where a simple switch or if-chain would do is unhelpful. Use an enumeration for the possible states, sure. Pull out a function that switches on the current state and dispatches to one function per state accordingly, by all means. But the rest is just trying to be clever, and I don’t see any advantage at all, never mind anything to justify the extra verbosity and clutter introduced.
In a nutshell, this problem isn’t even close to the size and complexity where patterns like State and Visitor pull their weight, nor is there any evidence that it is likely to become so any time soon. If dogma is appropriate to a problem like this, I suggest that You Ain’t Gonna Need It would have been a better choice.
@Chris
Thank you for taking the time to explain why you think that rather than improving readability, breaking code down into many very short methods actually makes it harder to read. I was hoping someone would care enough to respond, and find the energy to do it.
You made several points, which I will tackle in separate posts.
I’ll start with a minor one.
You said: it took me a couple of minutes just to be sure of the entry point in Uncle Bob’s example that corresponded to the original function.
I pasted Uncle Bob’s code, a single class called Register, in an empty Java project in the Eclipse IDE, and opened up the class with the default Project Explorer, which showed the method signatures of the class, and immediately revealed only three public methods: insert(), replace(), and take(int), the latter clearly corresponding to the original function.
@Chris wrote:
Could you please elaborate further?
Do you have a particular time in mind when people dogmatically kept repeating that equation as if it was self-evidently true…was it this decade? was it the previous one?
And who was it that did this?, do you have particular personalities/methodologies in mind?
I am genuinely interested, and would be grateful if you could tell me more about this, or just give me some pointers.
@Philip Schwarz
If you’d like to debate further, I’ll be happy to defend my argument, but please allow me to clarify a couple of things immediately just to avoid talking at cross-purposes.
Firstly, I am not against using small functions in general. However, I think the value of a function, at least from a readability perspective, is dictated by the amount of abstraction it enables rather than by the number of lines of code it contains. A corollary to this is that functions of literally only one or two lines, which don’t have space to raise the level of abstraction very much, are often a warning sign to me, like seeing a class full of direct get/set methods for individual private data items and not much else. Sometimes these mechanics are justified, but often they are clues that the responsibilities and abstractions are broken.
Secondly, regarding my observation about locating the start-up code, of course you can fire up an IDE and use it to help you navigate code. My point was that in the original code I didn’t have to, because I’d comprehended the mechanics entirely just from reading the code, probably in less time than it would take to load that IDE. I find it hard to reconcile this with the claim that the longer code that requires IDE support to navigate with reasonable efficiency is more readable.
Apologies if the first part of this post is a duplicate; I seem to be having some trouble replying here today.
@Philip Schwarz
If you’d like to debate further, I’ll be happy to defend my argument, but please allow me to clarify a couple of things immediately just to avoid talking at cross-purposes.
Firstly, I am not against using small functions in general. However, I think the value of a function, at least from a readability perspective, is dictated by the amount of abstraction it enables rather than by the number of lines of code it contains. A corollary to this is that functions of literally only one or two lines, which don’t have space to raise the level of abstraction very much, are often a warning sign to me, like seeing a class full of get/set methods for individual private data items and not much else. Sometimes these mechanics are justified, but often they are clues that the responsibilities and abstractions are broken.
Secondly, regarding my observation about locating the start-up code, of course you can fire up an IDE and use it to help you navigate code. My point was that in the original code I didn’t have to, because I’d comprehended the mechanics entirely just from reading the code, probably in less time than it would take to load that IDE. I find it hard to reconcile this with the claim that the longer code that requires IDE support to navigate with reasonable efficiency is more readable.
I notice that you’ve just replied again, asking about the “small functions = good” claim I criticised. The first source that comes to mind is Clean Code by Uncle Bob himself, which has this to say on the subject:
Of course, there are numerous other sources, from web sites to in-house style guides, that claim that functions should be no longer than one screen/50 lines/some other arbitrary limit. Googling “functions should be short” appears to turn up plenty of examples.
This is in marked contrast to, for example, Code Complete by Steve McConnell, in which the author describes “a mountain of research” on the subject and cites six distinct sources that do not support the benefits of very small functions.
Apologies if this post is a duplicate; I seem to be having some trouble replying here today.
@Philip Schwarz
Regarding the “small functions = good” claim I criticised, the first source that comes to mind is Clean Code by Uncle Bob himself, which has this to say on the subject:
Of course, there are numerous other sources, from web sites to in-house style guides, that claim that functions should be no longer than one screen/50 lines/some other arbitrary limit. Googling “functions should be short” appears to turn up plenty of examples.
This is in marked contrast to, for example, Code Complete by Steve McConnell, in which the author describes “a mountain of research” on the subject and cites six distinct sources that do not support the benefits of very small functions.
@Chris wrote:
Object Mentor have their own school of thought about clean code. They don’t claim their particular school to be right. They do claim that if you follow their teachings, you will learn to write code that is clean and professional. They say that there are other schools of thought, and other masters, that have just as much claim to professionalism as they do. While they present their opinions as “their” absolutes (the way they practice their art, they acknowledge that many of their recommendations are controversial, and that not everyone will agree with them.
In Clean Code, Uncle Bob kicks off his recommendations for functions with three key principles: they should be small, they should only do one thing, and all their statements should be at the same level of abstraction.
About function size, he says:
His experience has taught him that functions should be very small. Describing a program written by Kent Beck, he says:
Going back to the three principles (Small, Do One Thing, Same Level of Abstraction), you will recognise these as being the three components of Kent Beck’s Composed Method pattern:
Q: How do you divide a program into methods?
A: Divide your program into methods that perform one identifiable task. Keep all of the operations in a method at the same level of abstraction. This will naturally result in programs with many small methods, each a few lines long.
When describing the pattern, Kent Beck says:
And here is Kent Beck’s Intention Revealing Message pattern:
Q: How do you communicate your intent when the implementation is simple?
A: Send a message to “self”. Name the message so that it communicates what is to be done rather than how it is to be done. Code a simple method for the message.
Here is my translation into Java of one of his Smalltalk examples:
When describing the pattern, Kent Beck says:
Brett’s original ‘take’ method is NOT a composed method.
It doesn’t do just one thing (try describing it!): it is checking and modifying some state, doing some maths, manipulating a stack, and doing different things in different states.
Its statement are not at the same level of abstraction: on one line it is doing a low-level computation of the number of digits in a value, in others it using that number to compute a higher level function, in others it is manipulating a stack.
The method is not short: while it is not long, it is not a few lines.
Also, the method does not delegate to intention-revealing methods. It just exposes you in one go to all the gory details of how it does what it does.
If instead you take Uncle Bob’s ‘take’ method for the ‘inserting’ mode:
It is much more composed than the original method, and its calls to r.dup(), r.enter(...), and r.accumulate() (examples of the single-line methods you object to) are very similar in their effect to invocations of intention-revealing methods: by calling them, the ‘take’ method tells you what it is doing, rather than how it is doing it (e.g. by manipulating a low-level stack or setting a class variable).
Regarding your concern about ‘laboriously scanning through the whole verbose mess to find enough context to understand what is actually happening.’, this is acknowledged by the main proponents of small methods as a price worth paying.
In Refactoring, Fowler writes:
In Smalltalk Best-Practice Patterns, Kent Beck writes:
And in Implementation Patterns, Kent Beck says:
@Chris
You said:Thanks for that, I will dig my copy out.
@Chris
OK, so you have a copy of clean code…good…based on your opinion of one-line methods, I suspect that Heuristic G30 (Functions Should do One Thing) will give you a heart attack:
This bit of code does three things…This code would be better written as:
What do you think?
@Chris
I typed in that last method incorrectly…here is the correct version:
@Philip Schwarz
We seem to be overlapping here because of some funny delays in posting, so I don’t know if you’d seen my earlier posts that already addressed some of your points when you wrote your latest contribution. I’ll just briefly comment on a couple of your other points for now.
On the subject of Composed Method:
The first two principles I completely agree with. This is basic functional decomposition advice that has been around since the programming stone age (though alas many professional developers seem to have forgotten it shortly afterwards in their quest to objectify this and higher level language that).
But I can’t agree with the conclusion. I’ve worked on code in several fields, from mathematical modelling to instrument control, where it would be perfectly possible to have a function dozens, perhaps even hundreds, of lines long that did represent a single task with the implementation at the same level of abstraction throughout. Usually the control flow would be quite linear, but subdividing the logic further would just be an artificial break.
In any case, as I mentioned before, my objection is not to small functions as such, just to small functions that don’t really gain us any useful abstraction. To wit, I see a marked contrast between your comments on the Intention Revealing Message pattern with the isEmpty example and Uncle Bob’s take function that you quoted. In particular, I could immediately guess what isEmpty would mean from the calling code, and while it is only a single line long, it does represent a useful abstraction.
On the other hand, despite knowing the general problem area we’re discussing, I still don’t see why the names take, dup, enter and accumulate are particularly helpful here. take seems rather arbitrary: neither it nor the name Register provide enough context for it to be a meaningful concept without further information. dup betrays the underlying implementation, while enter randomly obscures the implementation despite operating at the same level of abstraction. The worst is accumulate, which doesn’t accumulate anything at all, despite having a common meaning along those lines when applied to a sequence in computer science literature; it actually changes the mode (and apparently in a way that only code related to the Register class is permitted to do, though the analogous functions for setting other modes are public). In fact, looking over the entirety of Uncle Bob’s code again, it is littered with one-liners that are never actually used, yet betray implementation details or at best rename something without providing any additional abstraction.
In short, reading Uncle Bob’s take function, I would have had to look up every single function it called anyway, to drop to a useful level of abstraction and work out what the underlying logic was, completely defeating the point of factoring out the individual routines. However, to work out what other code interacted with the take function, I would also have to analyse all code with access to the same instance of Register because the numerous small, public functions effectively expose the implementation anyway. Whatever happened to “Tell, don’t ask”?
As for the small methods vs. increased interactions issue, I don’t have much to add there. A few consultants can repeat the mantra as often as they like, but the evidence simply doesn’t support their conclusion. Increasing complexity is definitely a causal factor in making code harder to understand; this much is well supported by research. Moreover, it seems likely that there is a positive correlation between function length and function complexity, but it doesn’t follow that small functions automatically help readability. It does follow, however, that if the functions get so small that the complexity starts to increase because of all the added interactions, this harms readability.
@Philip Schwarz
I think the code you cited is an excellent example of taking a good rule of thumb to such an absurd extreme that it breaks.
I am amused by the fact that the one function in the proposed rewrite that does do something actually does two things; the name even describes (with no useful abstraction whatsoever) what those two things are. If iteration and alternation violate the Sacred Principle of Oneness enough to justify separating everything inside any pair of {} then surely sequencing does as well? I’m mildly surprised that the person who wrote that originally hasn’t yet died of old age waiting for an infinite recursion to finish! :-/
The tragic thing is that while messing around with dogmatic changes to achieve small functions for no particular benefit, the author has missed the wood for the trees. The first question I would ask about the original function is why this code is messing around so much with the details of another object. Tell, don’t ask:
and on the Employee class:
Then we might consider further improving the function names, but cleaning those up requires knowledge of the context that hasn’t been provided in this example, so there’s not much we can do beyond renaming the calculation function to something more appropriate given that its purpose is defined by the value it returns.
Of course, this whole example is very artificial, as it’s unlikely that in a real system an Employee object would know how to make a payment without depending on other parts of the system anyway…
@Chris
You said:
OK..so while you find ‘isEmpty’ to be intention-revealing, the same is not true for Uncle Bob’s one-line methods.
If you look back 11 posts from Uncle Bob’s, you’ll see Brett’s firts follow-up post, in which he says:
By the way, this is the beginnings of a method to handle input for an RPN calculator. Input is more complex than I first imagined:
Based on that, the following is possible:
So Uncle Bob has created methods that map to problem-domain abstractions and are therefore intention-revealing to anyone who knows enough about the problem domain. To make the code readable, he has hidden code that tells us HOW the problem solution is implemented, behind code that models WHAT happens in the problem domain.
You seem (to me) to be saying that Uncle Bob’s one-line methods make the code harder to read because they are not intention-revealing (to you because you don’t know enough about the problem domain), so the code would be better off (more readable) if instead of telling you about WHAT happens in the problem domain, it just told you HOW the solution to the problem is implemented e.g. using stack operations.
I disagree. Uncle Bob has chunked implementation details and hid them behind intention-revealing method names, so that people who know enough about the problem domain (e.g. anyone intending to maintain the code) can read his code more quickly and accurately.
@Philip Schwarz
The thing is, calling a function “enter” like that isn’t intention revealing. On the contrary, it is describing not what the function does but when it should be called in terms of specific user actions. There is a place for event handlers like that, but it’s in your user interface modules. Why is any code in an internal class like this even aware of what the nature of the user interface is, never mind referring to specific user actions?
Again, there is a not-seeing-wood-for-trees problem here. If we were to expand the scope of the problem to include the user interactions - which is far beyond what the original function covered and not a mere refactoring, of course - then we should be creating an internal class to model the stack behaviour with interface methods representing domain concepts such as pushing a number onto the stack, applying an operator and showing the current top of the stack, and we should also have separate code to handle UI quirks like parsing single keystrokes and evaluating when they become triggers for certain meaningful actions in the problem domain.
Chris wrote:
I think you are a bit off the mark. Ultimately, the underling facade supporting some user interface needs to have the ability to represent logical operations from the perspective of the user.
Sure, this is not always a 1-to-1 mapping (and in fact it should not be so most of the time). However, there is a difference between “entering the digits of the number” and “starting the next number”.
So some questions I might ask:Here is an example I came across on a project in 1997…
The project allowed flight rebookings on Palm 7’s, the web, WAP enabled phones and smart two-way pagers. It worked well, it was ready for use and it was in production (well it was in a beta sense).
Then along came a new 2-way pager that used SMTP as its communication between the pager and the base. The average response time was 1 minute. The minimum was 30 seconds and the max was 3+ minutes.
We had designed several logical steps to change a flight (end to end):Ignoring logout, that’s 7 steps. On this new device, that would, on average, require 7 minutes.
We had a conflicting requirement to make a system that was faster than making a phone call. 7 minutes was off the mark by several minutes.
So we had to adapt the underlying interaction. We left the underlying service as is but we developed an application for the two-way pager. This application maintained a cache of itineraries and credentials.
The new interaction was:So this made it fast enough, but it took away too much from the experience and was rejected. We actually had to bring the manufacturer on site to tell them there really were no other options.
Why do I bring all of this up at all?
When you are building a system, a part of its design is user interaction. Part of that is designing a system that accommodates all of the points of interaction that make the best possible user experience, removing was is not necessary (or relegating it to an alternative).
In this case, enter() is the name given for the logical idea of completing input on one number.
Can this be removed? Yes. Can a calculator designed without this interaction work with many different user interfaces? Yes (I’ve done it). Does it map well to the domain? YES.
The HP calculators have been around since the late 60’s (see http://www.hpmuseum.org/
So to take it away in fact could make the underlying solution less close to the domain and in fact result in a worse solution.
One person’s intention is another person’s “specific user actions”.
Discussing the “enter” function is taking a phenomenological perspective, removing it and discussing “indication completion” is moving towards the ontological.
Context dictates one approach as “better” than another – at least for now.
public void take(int v) {
...
class CurrentModeAccumulating : ICurrentMode {...}
class CurrentModeReplacing : ICurrentMode {...}
class CurrentModeInserting : ICurrentMode {...}
I took a quick look to the current solutions, and it seems mine is veeery close to Peter Bona’s.
The originial take method becomes:
Mode is an implementation of the State pattern. I preffered your initial use of constans and also, I used annonymous classes for conciseness. You could as well have used proper classes, subclassed from Mode base class.
The difference from Peter’s solution are little readability refactorings, like eliminating on of the temps in the accumulating mode with a method.
Two points I’d like to make to your problem: you didn’t specify what the purpose of the refactoring is, so I could well say that the already implemented solution is fine as it is. And second, “using a few design patterns just because you can” is bad! :)
@Brett
I think perhaps we are talking at cross-purposes. I am not objecting to the name “enter” in itself, nor to the subtle distinction between “pressing enter” and “completing an input”. I am objecting to the use of any interface-level concepts in the domain model.
In a RPN calculator, the domain interface requires three basic operations: putting in a number, putting in an operation, and reading out the current value.
Internally, of course, it maintains some sort of stack, but the state of that stack is evident only through operations that implicitly change the values at the top of the stack and through reading the current top value.
Similarly, there is some logic associated with knowing when a sequence of digits typed by the user is a new number ready to put onto the stack, but this matters only to the UI code. We can see that things like typing an individual digit or pushing an enter button are not in themselves meaningful concepts in the domain, because they make a difference only when they result in pushing a new number onto the stack.
This structure would have been immediately obvious had there been separation between the domain model (probably a class with only three public methods plus constructor) and the UI code (with whatever state machine might be appropriate to handle the individual key presses). But because in Uncle Bob’s version there is just the one huge Register class trying to do everything with many tiny methods, there isn’t even this basic separation of concerns and the levels of abstraction are all mixed up.
http://www.superstonejerseys.com
think you ! http://www.yourvoguemall.com
I find it incredible that more blogs and forums are not as pleasant as this one.moncler downOften times when I land on a website page the articles and other content is so deficient that I move on without delay. That is not the case here. Thanks so much.moncler men
What does this picture suggest to you or what can you draw from it, if anything?
white iphone 4 is so charming and chic. As the icon of latest fashion, how can you miss it!
Another fantastic posting here at Object Mentor!! Thanks for sharing and keep up the great work.:)
We are the professional dresses manufacturer, dresses supplier, dresses factory, custom dresses.
website page the articles and other content is so deficient that I move on without delay. That is not the case here.
thank you very much.
internette görüntülü olarak okey oyunu oyna, gerçek kisilerle tanis, turnuva heyecanini yasa.
it needs a bokmark so i can come back to it later ,nice stuff
Great post. It appears that most of the steps are relying on the creativeness factor&.
other content is so deficient that I move on without delay. That is not the case here.beats by dre sale cheap beats by dre
Swarovski crystal jewelry, on top of that also known as these Austrian Swarovski Crystals, is definitely the most beneficial many costly type of Crystals Swarovski uk . As a result, a majority of these Swarovski Uk items need be adopted special care involving to allow them to last perpetually.
I am carrying this bag myself,Herren Winterjacken when I wear very girly stuff, mine is smaller than large,herren winter still can fit lap top and all I need…I had been looking for it for several years until I found it 3 years ago in UK.Belstaff Jacken I saw it for the first time in the movie “Interpreter”, carried by Nicole Kidmann, and then in “I, Legend” carried by Will Smith.http://www.herrenwinterjacken.com/
Slewing bearing called slewing ring bearings, is a comprehensive load to bear a large bearing, can bear large axial, radial load and overturning moment.
The results of ethnic psychology constitute, at the same time, our chief source of information regarding the general psychology of the complex mental processes. Wilhelm Wundt
I liked you blog so im going bookmark it with my prefered websites, you have posted an amazing posts so thank you I liked you blog so im going bookmark it with my prefered websites,
Women today are becoming more and more conscious of their fashion sense. It is not surprising, therefore, that Christian Louboutin black shoes women are investing their money on designer label clothes, accessories, and popular women shoe brands. Women Christian Louboutin wedding who know the value of their money often lean towards designer label items because branded items always offer wedding shoes by Christian Louboutin guarantees and warranties especially in the event of returns or exchanges and most important of all, you can never contest the quality of branded items.