This week's book giveaway is in the Spring forum.
We're giving away four copies of Spring in Action (5th edition) and have Craig Walls on-line!
See this thread for details.
Win a copy of Spring in Action (5th edition) this week in the Spring forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Devaka Cooray
  • Liutauras Vilda
  • Jeanne Boyarsky
Sheriffs:
  • Knute Snortum
  • Junilu Lacar
  • paul wheaton
Saloon Keepers:
  • Ganesh Patekar
  • Frits Walraven
  • Tim Moores
  • Ron McLeod
  • Carey Brown
Bartenders:
  • Stephan van Hulst
  • salvin francis
  • Tim Holloway

Game of Life Lessons: Detecting Code Smells  RSS feed

 
Bartender
Posts: 9493
184
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I forgot what I did half a year ago when I attempted this, but I found the documentation and I'm pretty pleased with it:

https://nibsi.github.io/Evolution/core/target/site/apidocs/nl/nibsi/evo/MutableGeneration.html
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I still have to find a good name for IndirectlyMutableGeneration though. I wasn't happy with it then and I'm not happy with it now.

It's not really a ReadOnlyGeneration, because it can be mutated indirectly. I'm considering MutableGenerationView, but then I have to ask myself if it makes sense for MutableGeneration to extend MutableGenerationView.

I just came up with TrackableGeneration, because the only things it adds are methods to add and remove listeners. Thoughts?
 
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:I forgot what I did half a year ago when I attempted this, but I found the documentation and I'm pretty pleased with it


signature: flipCellAliveAt​(Position position) description: Flips whether the cell at the specified position is alive or dead. If the cell was alive, it will be dead. If the cell was dead, it will be alive.

flipCellAt() is what I'd expect it to be. Probably copy/paste stuff?
 
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:signature: flipCellAliveAt​(Position position) description: Flips whether the cell at the specified position is alive or dead. If the cell was alive, it will be dead. If the cell was dead, it will be alive.

flipCellAt() is what I'd expect it to be. Probably copy/paste stuff?


It's pretty amazing how Liu seems to have developed a nose for code smells that rivals that of a bomb-sniffing dog overnight. I would have pointed out the same thing.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:I just came up with TrackableGeneration, because the only things it adds are methods to add and remove listeners. Thoughts?


Seems good. I think it tells me what its purpose in life (pun intended) is. What do you think about ObservableGeneration?
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:flipCellAt() is what I'd expect it to be. Probably copy/paste stuff?


I also thought about that one after this discussion. I will probably change it to just that. The interesting this is that I'm still stuck with setCellAliveAt(), which is basically the same as the example presented earlier in this thread. After some thought, I think the problem stems from the fact that boolean is a very poor data type with little semantic value. Better would be to introduce an enum:

Example of a hardcoded action then looks like this:

Pretty expressive.

Junilu Lacar wrote:What do you think about ObservableGeneration?


*smacks forehead*

It's so obvious.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:

Junilu Lacar wrote:What do you think about ObservableGeneration?


*smacks forehead*

It's so obvious.


When we stare at code long enough, these kind of things get lost in our peripheral vision's blind spot. It's the "other pair of eyes makes it obvious" phenomenon. Don't feel bad, it happens to all of us.
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:The interesting this is that I'm still stuck with setCellAliveAt(), which is basically the same as the example presented earlier in this thread.


But you have already quite good names for killCellAt​(Position position) and reviveCellAt​(Position position) where both uses setCellAliveAt() as a base functionality. Maybe nothing bad if such method stays private instead being part of public API? Personally for me when it is wrapped by other two expressive names, it's kind of clear what it does + helps with some labour work removing code duplication.
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:I just came up with TrackableGeneration, because the only things it adds are methods to add and remove listeners. Thoughts?


Junilu Lacar wrote:Seems good. I think it tells me what its purpose in life (pun intended) is. What do you think about ObservableGeneration?


Stephan van Hulst wrote:*smacks forehead* It's so obvious.


Junilu Lacar wrote:When we stare at code long enough, these kind of things get lost in our peripheral vision's blind spot. It's the "other pair of eyes makes it obvious" phenomenon. Don't feel bad, it happens to all of us.


Just love reading all this, guys. Close to tear of happiness. Such healthy conversations what makes this community spinning.
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I considered making it protected, but in my experience it's not uncommon for code to naturally want to call the "real thing" rather than convenience methods based on it. As an example, consider a game of life in which cells become alive if the majority of their neighbors is not alive, and vice versa:
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:it's not uncommon for code to naturally want to call the "real thing" rather than convenience methods based on it.


I love it when people talk about code like that, like it's a thing of its own. I don't know if you did that consciously, Stephan, but it's awesome to see!  
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I didn't when I wrote it, but when I previewed my post I noticed it fit in well with the whole Egoless thing. :P
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:Just love reading all this, guys. Close to tear of happiness. Such healthy conversations what makes this community spinning.


With everybody in the right mindset and taking the proper tone, even passionate disagreements can be part of a lively but healthy conversation. #8 and #10 of Jeff Atwood's 10 Commandments of Egoless Programming are very important.
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:After some thought, I think the problem stems from the fact that boolean is a very poor data type with little semantic value. Better would be to introduce an enum:

Pretty expressive.


After Junilu gave a suggestion in the thread I've created about the GoL, since then I'm looking to that part of the code in my github several times a day and have a joyful time. Following same idea perhaps would improve expressiveness even more.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:


That's cool but I'd like to see if you could find a way to make that more succinct so it doesn't stutter so much. By "stutter" I'm referring to the multiple times position is referenced in those two lines of code.
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Since I first proposed that enum, I decided that the name Aliveness is more appropriate, going by the definition that the dictionary gives. Another reason to use Aliveness rather than Liveness is that the word "liveness" is already used in the context of multi-threading to indicate whether a thread is doing useful work.

I associate the name "flip" with an action that mutates the state of something, as demonstrated by the flipCellAt() method. However, flip() doesn't mutate an enum constant. This could lead to the same kind of confusion that beginners have when they call replace() on a String or add() on a BigInteger and expect it to mutate the object they called it on. Instead, I would name the method something like inverse() or opposite() to clearly indicate that it returns a different object.

It's not clear what at(position) returns. That's why I would call at() alivenessAt() or getAlivenessAt().
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:That's cool but I'd like to see if you could find a way to make that more succinct so it doesn't stutter so much. By "stutter" I'm referring to the multiple times position is referenced in those two lines of code.


Not possible, unless you encapsulate the position and the flipping operation in another class, which would violate the guideline I laid out on the previous page of this topic that says that you shouldn't modify a shared object through a different one. I prefer 'stutter' over indirect modification.
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:Not possible, unless you encapsulate the position and the flipping operation in another class


After thinking a while came to same thought.

That may look like:

So that would let have similar to:

Reads better in my opinion, but we end up with presumably lots of Aliveness objects.
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ew. We're basically wrapping a mutable object around an enum just for the sake of fluidity. Not very functional.

I wonder what Junilu has in mind.
 
Master Rancher
Posts: 3001
105
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just reading the latest developments, I get the feeling things are not going the right way, at least not for me.
Is there in all the theory about Expressive Coding a rule or measure that determines when enough is enough?

This topic started with a simple example and a simple question about a code smell. Now, as I wrote, I did not get one, but as some made clear, there is one. Okay, I am willing to accept that, although I think the arguments are a bit subjective.

However, now I am reading about things like Liveness or Aliveness, terms that do not ring a bell for me, as non native English speaker. Aliveness, what is that, and aliveness of what? Looking at the code, I see that it is an enum, with values LIVE and DEAD. Is that to replace the Cell, I wonder? Well, no, since we have the method 'setCellLivenessAt(Position position, Liveness liveness);'. Does a Cell now have this enum as field? Is Cell still an enum? If so, of what?

Also, we are talking about the flipping of a State. Never heard that term when it comes to the GoL.

My fear is that this is getting a little out of hand. Perhaps the code as we have it now is the summum of expressiveness for the specialist, but then I must conclude that I am very far away from being a specialist.
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:Just reading the latest developments, I get the feeling things are not going the right way, at least not for me.
Is there in all the theory about Expressive Coding a rule or measure that determines when enough is enough?


I guess we more of experimenting here. Trying code under the hard pressure and seeing whether it survives. I too thought why to write code if you know it won’t work well probably, but it has been mentioned that not a bad idea is to try out ideas in code rather than talks regardless how they look at first.

Now that some time passed after the GDCR, I think I was pushing my ideas too strongly onto the table. Why not to try other suggested approaches even if you are close to being certain they don’t make much sense. Doing own way you just repeat what you know already, while trying others you may learn something new, even if that is not optimum approach.
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:Not possible, unless you encapsulate the position and the flipping operation in another class...


I see that I misread Stephan’s post and experimented with a code construct which is absolutely different from what Stephan actually suggested.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
To Piet's point, were any of those designs arrived at after being driven by tests?

That's kind of what I was getting at. I may have led the way in going astray but those "I wonder what would happen if I designed it this way..." posts assumed that code would be written as tests and that's what would drive the implementation.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:Now that some time passed after the GDCR, I think I was pushing my ideas too strongly onto the table. Why not to try other suggested approaches even if you are close to being certain they don’t make much sense. Doing own way you just repeat what you know already, while trying others you may learn something new, even if that is not optimum approach.


Again, I'm excited to see Liu say things like this and I find it validating since I say things like "If you're the driver, just try out the ideas that your navigator(s) throw out there. Your job as driver is not to question the direction the navigator is taking you. Your job is to make sure you get to wherever they're navigating you to safely and in one piece."
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Since nobody answered my question about the absence of a set_dead_at(location) method in Corey's code, I'll give you my thoughts. I should go back and re-read the book to make sure I don't take anything out of context but we'll see where this gets us without a re-read.

My thoughts:

1. From Corey's book: Test names should influence object's API.

I take that a little farther. Test code should influence the object's API. If you take test code to be examples of how your object's API is used, then that API should be limited to what the test code documents. Use POLA to your advantage. If someone uses your API in some way that aligns with the usage shown in your tests, that's great. However, if they use it in some way that is unique and isn't illustrated in some kind of test you wrote, then your code breaks, you know exactly what kind of test you missed writing.

When designing at the unit level, you have to be careful not to lose sight of the big picture. Don't forget, a class has to be used by someone/something. Go back to Andy Hunt's Rule #1: Always consider context. So when designing, don't forget the context in which your class API will be used. Is there going to be any use for set_dead_at(location)? Where's the test code that shows that? Is that a reasonable test? Is there production code that reflects the same kind of usage the test illustrates?

2. The high-level context for designing the Cell class and the Location class is the World "game loop". What would this loop look like? I'd want to have a test that illustrates that.

I might start with something like this:

I would also have a test that says a new World is always empty. So if a new World is always empty and world.nextGeneration() creates a new World instance (to be more functional), then given the cell transition rules, why would you need to set a Location in World to "dead" if it's already dead? You would only want to set a location in the new World to "alive" if a rule in the current world applies to making or keeping a cell "alive" in the next generation. If a cell dies in the current generation, then you don't have to do anything to the next generation world because that cell is already dead to begin with.

So, taken from the context of the World game loop, you should realize that there is no need for set_alive_at(location) to have a symmetrical set_dead_at(location) method. Adding the latter would be over-engineering.

 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:... were any of those designs arrived at after being driven by tests?

... I may have led the way in going astray but those "I wonder what would happen if I designed it this way..." posts assumed that code would be written as tests and that's what would drive the implementation.


It just shows how our minds are not there yet. For instance myself, instead of writting one test case with few lines in it, I wrote full block of “production” code. It certainly will take some time to get there.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A more functional implementation of GoL has some interesting effects on the direction your design goes. One is that it seems to drive you to a sparse matrix representation of the playing surface. When you do this, you have to look for clumps of live cells to determine whether cells get born in the next generation, a very different approach to applying the B3 part of the rules.

That is, given the standard rules of B3/S23 (Born when 3 live neighbors / Survives when 2 or 3 live neighbors) and a standard "grid" implementation of the playing surface, you normally iterate over all your cells and count neighbors. When you come to a dead cell, you simply see if you can apply the B3 rule and move on.

With a sparse matrix, however, there are no "dead" cells per se. A dead cell simply means that a Location is not included in the sparse matrix. What you have to do instead is to watch for clumps of cells and see what dead cells are around those clumps where the B3 rule applies. Again, it's quite an interesting problem to solve.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

I wrote:A more functional implementation of GoL has some interesting effects on the direction your design goes. One is that it seems to drive you to a sparse matrix representation of the playing surface.


This isn't just me either. There was one group at GDCR last Saturday that came up with the same idea. They were actually pretty excited because it seemed like they had discovered this through test-driving and it was a very new approach to them. It also opened up the possibility of having a practically borderless playing surface.

I don't think they were influenced by me either because while one of the people in that particular group was an engineer who had worked with me before, it was someone else in his group who came up with the idea of using a sparse matrix.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Have we digressed enough from my original question to warrant splitting off some of the discussion into a different thread or several different threads?

The original question I asked was, "Do you think this API has a smell to it?"


I don't know if we have agreement on whether this smells or not but I think we've seen enough posts giving opinions on both the yes, it smells and no, it doesn't smell side to maybe say that we can agree to disagree.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:It just shows how our minds are not there yet. For instance myself, instead of writting one test case with few lines in it, I wrote full block of “production” code. It certainly will take some time to get there.


Liu, from your responses in this thread, I think you are on your way there. It's really rewarding for me to see that some of the ideas I have been spouting for so long in these forums seem to have taken root in your mind and influenced the way you are thinking about design now.

I told one guy at GDCR who had thanked me for facilitating the event that my motivation was partly selfish as well. I want to get a chance to work with developers who take design seriously and really think deeply about it. While you and I will probably not get a chance to work together IRL, just kind of playing around with ideas here, having these kinds of discussions, and getting a sense that we're on the same wavelength is close enough to what I'm looking for IRL at work. So thank you, too, for taking part and sharing your thoughts.
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for kind words Sensei, not to confuse with Master
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:...
Not possible, unless you encapsulate the position and the flipping operation in another class, which would violate the guideline I laid out on the previous page of this topic that says that you shouldn't modify a shared object through a different one. I prefer 'stutter' over indirect modification.
...
I wonder what Junilu has in mind.


I would think something like this:

However, I have to go back to my point about keeping the big picture in mind. What kind of higher-level code would require calling the flip(Position) method?
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

I wrote:What kind of higher-level code would require calling the flip(Position) method?


I ask this because I can't imagine the next generation can be calculated in place. That seems like what calling flip(position) would be doing. As far as I know, two World objects are required for GoL: one to represent the current generation and the other to represent the next generation. Therefore, it seems the only high-level operations needed are World.setAlive(Position) and World.isAlive(Position). Maybe World.next(Position)
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:... Therefore, it seems the only high-level operations needed are World.setAlive(Position) and World.isAlive(Position). Maybe World.next(Position)


Junilu, don't you see method isAlive() smelly in general?

I currently think that way, that isAlive() in case cell is represented as boolean value - it reveals implementation details, in case of not boolean - as bringing yet another representation of a cell, i.e: ALIVE, DEAD, true (as a result of call isAlive()) false (sames as in true).

Doesn't make sense to defer  such knowledge about the cell's so called state to a latest stage/lowest level, i.e.: GameRules or Cell itself, and not pollute world with such extra responsibility? Why world would need to know each and every tiny detail?
 
Liutauras Vilda
Marshal
Posts: 6257
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Another moment is, that world goes from generation to generation until previous generaion isn't equal to current.

Seems that decision about the game of life lifecycle is being made at a much higher scale of knowledge.

What do you guys think?
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think we are getting close to the point that Piet was asking about earlier: when do we know that enough is enough?

There are levels of smells and levels of sensitivity to smells. There is also a mix of subjectivity and objectivity when evaluating smells. I won't deny there's always some level of "I don't like that as much as I like this..." (subjective) but there's also the addendum to that statement of "...because (of this/these) reason(s)..." (objective).

Liutauras wrote:isAlive() smelly in general... isAlive() in case cell is represented as boolean value - it reveals implementation details, in case of not boolean - as bringing yet another representation of a cell, i.e: ALIVE, DEAD, true (as a result of call isAlive()) false (sames as in true).


Is isAlive() smelly? No, I don't find it to be smelly by itself. (Subjective part). Perhaps in some context it might smell (Keeping an open mind part) . However, the fact that it returns boolean is natural and intuitive because it matches its name. The method equals() returns a boolean. That's not smelly. The List.isEmpty() method returns a boolean. It's not smelly either. None of these actually reveal implementation at all, not even isAlive(). I think you think it does because you know that the actual implementation is a boolean. What if the implementation was something like this though:

The boolean return value does not reveal that some kind of collection is involved in the evaluation of whether some Position contains a live cell.

That's the kind of objectivity you have to apply to the subjectivity of the "I think this smells" or "I don't think this smells" part.

I think this shows that we can also get carried away with chasing down code smells and take things too far. Experience ultimately tells us when enough is enough and perhaps sensing where that line lies also has some subjectivity involved. We can fine tune that sense through practice, practice, and more deliberate practice.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras wrote:...as bringing yet another representation of a cell, i.e: ALIVE, DEAD, true (as a result of call isAlive()) false (sames as in true).


The question is, are you exposing ALIVE and DEAD to external code or is the scope of these values limited to code behind the isAlive() API method? If you expose these values outside of isAlive(), then yes, that might be a violation of DRY. If not, then you are only answering a question logically: Is the cell at that location alive? It's only logical that you answer either true or false to that question, right? And I have already explained why that's not a leaky abstraction.
 
Junilu Lacar
Sheriff
Posts: 12747
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The smell that I can agree with you though: maybe isAlive() is not a high-level API method after all. It's only a slight smell though. You also have to think about testability. There has to be a way to query an object to check whether something actually happened with it. If anything, I might want to reduce the scope of isAlive() to being package-private, so that at least a test can get to it. Maybe that's as widely accessible isAlive() really needs to be. Again, you have to go back to the big picture and declare your intent (i.e. document your design) with a test.
 
Stephan van Hulst
Bartender
Posts: 9493
184
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:What kind of higher-level code would require calling the flip(Position) method?


A user interface where you press a cell and it toggles from its current state.
 
Forget this weirdo. You guys wanna see something really neat? I just have to take off my shoe .... (hint: it's a tiny ad)
Download Free Java APIs to Work with Office Files and PDF
htttp://www.e-iceblue.com/free-apis.html
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!