• 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

My version of Conway's Game of Life  RSS feed

 
Master Rancher
Posts: 3002
105
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
About #1: what exactly is the problem?

My idea about handling gamerules, is as I suggested. In my GameRules class a List<Integer> becomeAlve and dito stayAlive. That gives me all the flexibility I need (so far, that is...).

Then, I can create some instance, like

Then I can have a testmethod like: boolean becomeAlive(nrOfNeighbors, GameRules), leading to tests like

et cetera.

By the way: I did not test my GoL in this way, so I might be talking complete nonsense here      
 
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
At coderetreat, you have to delete everything you did after 45 minutes. A lot of people have a problem with this but it does one useful thing, as far as I can tell: It helps you focus on the techniques rather than delivering something that's finished. This is actually very liberating when you're practicing. I like to think of it as developing "programming muscle memory."

If you think you did something well, then why should you worry about keeping your code? Delete the code and try to replicate what you did well. If you come up with something different, then maybe that was an improvement. You can usually sense if it is, in fact, an improvement because things will feel like they're going better than the last time.

If you think you could improve on something, delete the code, too! Then try again and see if you get something you feel is better. No need to compare versions side by side. It's kind of like the blindfolded exercise they do in Wing Chun. You have to learn to sense when the code is going in a good direction and when it's going in a bad direction.
 
Ranch Foreman
Posts: 39
8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This piqued my interest so I've been poking at it off and on the past few weeks. This is what I came up with:

https://github.com/Gerardwx/conway/
 
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
#2 (by Junilu)

Junilu Lacar wrote:Do you see how the test code tells a story of how a World and Location objects are related?


Yes, that test seem to be more explicit than what I have, as it exactly tests which cell is meant to be alive, while mine tests that world has population. What I don't like about your test though, that I need to introduce particular method "isAlive" which has no use in my current design (I did further refactoring based on yours #1 given comment).

What do you think about having such method "isAlive()" in general in a World?

Let's assume for a moment there were monster cells and brick cells. Would you still favor the idea of such method along with isMonsterCell() and isBrickCell() methods? Indeed in my earlier version I had also such method, but later my thinking grew to a state not to pollute world with cell's regeneration process outcome, but have this check in ex RegenerationRules, currently just have a function in a Cell type.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
#3 (by Junilu)

Junilu Lacar wrote:I'd like to see you work on refactoring the LocationTest and Location classes a little bit...

I get what you're trying to say here but it raises at least one question about the design: Does the Location.of() factory method guarantee that discrete instances of Location will be returned? That seems to be the tacit/implied assumption made by this test.


If I read your comment correctly, in general you are happy with such method existence, except that in method I pulled Location(0, 0) indices out from the thin air, and implied that exactly these are equal, which in turn doesn't make test explicit enough and does not demonstrate that any two given same locations represent same location within a map.

Fully agree with that your comment. Sounds like a great improvement of a test. Documenting is something I still need to work on. Maybe having documentation from start would have shown more lapses in my thinking process.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Once again. I'm very happy I've started this thread. Sometimes it isn't easy to hear criticism, even though it is constructive. But what is for certain, I've learned a lot already from your comments/critiques (which earn cows for you all of course)!

Will get back to left out comments later, got to go now.
 
Junilu Lacar
Sheriff
Posts: 12748
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:Once again. I'm very happy I've started this thread. Sometimes it isn't easy to hear criticism, even though it is constructive. But what is for certain, I've learned a lot already from your comments/critiques (which earn cows of course)!


Egoless programming does take a while to get used to. I think the other important aspect of requiring participants at Coderetreat to delete their code is to instill that egoless mindset. We programmers easily get attached to our code. That's something that small incremental steps and the Red-Green-Refactor cycle of TDD also addresses. You don't get too attached to code that you've only just written so it's easier to refactor and maybe even delete it and try another approach. Code you've spent a longer time tending and nurturing starts to grow attached to you, or rather, you grow attached to the code. You somehow feel the need to defend the decisions you made. I can still see hints of that in some of your latest replies. Be cognizant of when you're defending a decision based on good rationale versus you not wanting to be seen as having made a poor choice.

Egoless programming requires us to "embrace the suck," as Northwestern University coach Pat Fitzgerald said very nicely this weekend. If there's a good reason for saying that some code sucks, then embrace the reason, not the code. Learn from the code and move on from it. I suggest you delete your code and start over. It may be painful but once you get over it, it's very liberating.
 
Junilu Lacar
Sheriff
Posts: 12748
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
More about egoless programming.

There's a duality in the nature of code. On the one hand, whether or not you are conscious of it, the code is reflection of your style as a programmer, the way you think, and the way you express yourself. Consciousness of this builds as you gain experience and gain mastery of the mechanics of the medium. When you're a beginner, you just want to make it work. This is the Shu stage of learning. As you gain experience and get better with the mechanics of the language, you can start freeing yourself from having to think about form and think more about how all the elements come together to express ideas better. These are the Ha and Ri stages of mastery.

I reference Shu-Ha-Ri again because to me, the progression I described has many parallels to what I see in my martial arts practice. Beginners in Aikido just want to get the mechanics down. They just want to learn the moves. They are in Shu. As students progress through the ranks to black belt and beyond, their own style starts to emerge. I watch many high-ranking practitioners demonstrate Aikido and each one has a slightly different way of doing the same technique. They have found their style, a "signature" to their Aikido, so to speak. Even my sempai, the senior black belt in my dojo, has a signature to his technique. I suppose it's the same for other martial arts. It's the same for music, where you can immediately guess who sang the new song you just heard on the radio. It's because the singer's unique style is apparent. It's the same in art, where you can pretty much recognize works by the likes of Dali, Picasso, Rembrandt, Jackson Pollock, and Andy Warhol.

So, yes, code often reflects parts of our selves.

On the other hand, you shouldn't attach code to your competence. Code is a reflection of our understanding of a problem. When we don't have a clear vision of how to solve a problem, we experiment. Sometimes those experiments go bad. Sometimes they don't come together well. We shouldn't think that this failure to become a beautiful, coherent work is a reflection of our abilities to make beautiful, coherent work. Most of the time, our first few tries are ugly and deserve to be criticized. We should embrace this because only from doing so will we learn what we need to do to make something that better reflects our abilities.

So once again, embrace the suck. Embrace the lessons you learn from the code, not the code itself.
 
Junilu Lacar
Sheriff
Posts: 12748
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
One critical component to egoless programming is trust. Trust creates safety (or is it the other way around?). Since there is trust between the participants in this thread, a discussion about the code can be safely had without fear of offending or being seen as anything other than having the other person's interests in mind, that everyone wants to learn and help each other learn.

The person putting themselves and the code they wrote out there for others to see and critique deserves the utmost respect. They are the most vulnerable in this exchange so everyone else must do their best to put the author of the code under review at ease and to help them see that they have absolutely nothing to lose and everything to gain.

That's why the cow, Liu, and the kudos for sharing.
 
Junilu Lacar
Sheriff
Posts: 12748
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:What I don't like about your test though, that I need to introduce particular method "isAlive" which has no use in my current design (I did further refactoring based on yours #1 given comment).


If not with an isAlive() method, how do you express the idea that a live cell lives on in the next generation in your current design?

Liutauras Vilda wrote:What do you think about having such method "isAlive()" in general in a World?


I don't see any problem with it.  

Liutauras Vilda wrote:Let's assume for a moment there were monster cells and brick cells. Would you still favor the idea of such method along with isMonsterCell() and isBrickCell() methods?


Why would those be related? The names isMonsterCell and isBrickCell are smelly because they have type names. I don't consider those as having any relevant relationship to being able to tell if a particular cell is alive or not. I tried reasoning for a name of isOccupied but being occupied means the same as being alive and not occupied means the same as not alive in the context of GoL.

Liutauras Vilda wrote:but later my thinking grew to a state not to pollute world with cell's regeneration process outcome, but have this check in ex RegenerationRules, currently just have a function in a Cell type.

I think you are complicating things too early. The World class is made up of Cells so I don't see how an isAlive() method would "pollute" the class. It seems an inherent responsibility of World to know which of its cells are occupied. What other class would that responsibility belong to then? You also have to watch out for Anaemic Domain Model. If a World is simply a container for cells and has no interesting behavior, then it is anaemic.

The state of being occupied or not is not the same as calculating the next generation. If you really needed the responsibility for determining survival/birth to be encapsulated by a Pure Fabrication type object (see GRASP) like RegenerationRule, I think that would be fine but I would refactor to that only if there was a compelling code smell, not before.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Apparently agree with everything what you just said about egoless programming.

Junilu Lacal wrote:You somehow feel the need to defend the decisions you made. I can still see hints of that in some of your latest replies.


Couldn't disagree with that either, you developed this sensor it seems well However, I do think that almost everybody feels attached tightly to their code, the difference is how they react to criticism. What worst could happen, is to ask for code review AND to expect to get replies: "well done, great code". That means nothing gets improved, and there IS always something to improve.

I'm a bit upset that not all commits history retained in my repository, so good portion of them are not recorded. But to compare what I had initially and what all of your (contributors in this thread) comments lead me to, is like a day and night.

Also what is important I think, that every change code owner does based on the given critique, needs to be treated by the owner as an improvement rather than a blind change. If code owner doesn't go with such change, doesn't mean that suggestion weren't an actual improvement, but simply just explains that owner of the code isn't at that level yet to understand the implications of current and suggested design. And that is fine, because code owner will need to live with his decisions. But the comments/criticism never get trashed, they land somewhere in the mind, and they do their job even if that is for future.

This thread also helped me to understand when I/we comment newcomers code when they ask about assignments or so, and they don't even ask for throughout review, just to help to solve problem at hand. So I do understand why sometimes they get upset. Don't understand me wrong, I didn't get upset about any comment here in this thread (completely opposite), but we are humans, and the feelings are close to such sequence (at least it was for me like that) :

[1] you are happy about your code -> [2] you go to sleep -> [3] and all that just to find out that somebody on the following day says your design sucks -> [4 you are sad for a moment -> [5] you start agreeing -> [6] do refactoring -> [7] back to [1]

But that's normal!
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:About #1: what exactly is the problem?


Well, as you mentioned right from the beginning. It is too complicated and really for no actual reason. So you were right, thanks!
I've taken out only the function (Function -> BiFunction this time) and moved to Cell as an experiment and removed Regenerable interface altogether. It seems code became simpler, really just 3 quite concise classes (not the amount of classes counts for simplicity though) along with the test suite.

Piet Souris wrote:Then I can have a testmethod like: boolean becomeAlive(nrOfNeighbors, GameRules)...


These method names puzzling me a bit. Names becomeAlive(), stayAlive() sounds to me like a command (insists to become alive), which means I'd expect it to happen ragardless what parameters are. Or could be that arguments act as a feature unlocking-keys which enables procedure to becomeAlive or stayAlive. that sounds too confusing what I wanted to say. But I think I understand what you are trying to point out here. Will experiment with that, it really targets at my current regenerationRules() function within the Cell.
 
Junilu Lacar
Sheriff
Posts: 12748
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 the phrasing of "your design sucks" is fraught with landmines, whether that was the actual phrase used or that's how it comes across.

Let's all agree right now to separate "you" the author from "the design," which even though it came from you, should not be attached to your competence, intelligence, or whatever it is that you consider part of "you."

When we talk about the design, let's treat it as a separate entity that stands by itself and on it's own merits. Feel free to speak for or against the design as you feel is necessary but don't attach the merits of the design to the originator of the design.

Can we agree on this?
 
Piet Souris
Master Rancher
Posts: 3002
105
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:
Egoless programming does take a while to get used to. (...)


Never heard of that, but beautifully worded. However, I have the feeling that most (well, me anyway) will never get used to that. After all, who the heck is that bloke who dares to question my code!      

So I have much respect for Liutauras, publishing his code and undergoing all of our critiques. It deserves a follow up: two weeks ago I heard from the game '2048' that I programmed according to the MVC pattern. After this discussion has finished, I will have it revised as well. Maybe it is a very useful addition to this Ranch' projects, now started with the Black Jack project.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:When we talk about the design, let's treat it as a separate entity that stands by itself and on it's own merits. Feel free to speak for or against the design as you feel is necessary but don't attach the merits of the design to the originator of the design.

Can we agree on this?


Sure Junilu. Just once again, I did not take any offence with any of your or other contributors comments. Good that you started this side (related though) discussion about the egoless programming. That IS and WILL BE useful for other topics when users ask for code reviews. I think that's an easy thing to slip on, even though person is aware about such thing.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:Never heard of that, but beautifully worded. However, I have the feeling that most (well, me anyway) will never get used to that. After all, who the heck is that bloke who dares to question my code!


Piet, that made me laugh
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
#1 (by Junilu)

Junilu Lacar wrote:...
I also sense a mis-assigned responsibility here. Why do you need a separate class to encapsulate the rules of the game? I don't understand the semantics of this: rules.withLivingNeighbors(2).build().apply(Cell.ALIVE) -- reading the test code doesn't tell me a story about this call. The call just seems to come out of nowhere in the test.

When I want to get familiar with some code, the first thing I look at are the tests. I expect the tests to start telling me a story about the design. I don't get what story these names are trying to tell:

rules_with_two_alive_neighbors_applied_to_alive_cell_returns_alive_cell()
rules_with_three_alive_neighbors_applied_to_alive_cell_returns_alive_cell()
rules_with_three_alive_neighbors_applied_to_unpopulated_cell_returns_alive_cell()
...


These names seem to have a heavy focus on implementation. Why would a Rules object have alive neighbors? That's the meaning I get from "rules with X alive neighbors." And why would a Rules object return a Cell? The semantics just aren't that intuitive to me.


I concede that really I went wrong path here. I was keeping this class for quite long as believed in its usefulness. Again, let me explain my ground thoughts about it, so you better understand why and where I slipped.

As mentioned earlier, my idea was (somehow bogged to a thinking that system's extension will be new types, whether a Cell.Monster, or other custom type Lion() or similar), and thought will have an interface Regenerage and RegenerationRules. So whenever new type appear, user would need to implement Regenerable interface so it would belong to a common type and would need to update RegenerableRules with some extras, i.e.: withLivingNeighbours(...); withMonsterStrength(...); withBricksWallHeight(...); etc...

The root problem was that I indeed tried to foresee the future, and got connected to an idea, that if the system extension takes place, that extension must be about the new types, and ruled out fully the possibility that system might need an update only for let's say coordinates system, i.e.: 2D -> 3D, or something else.

So these were my thoughts in my head which apparently pushed me to a situation where I was. About the Builder pattern, yes, I know builder pattern, but I didn't try to use it there, some of the ideas just got very similar to it, and in fact made it look as anti-pattern, which probably really is/was as you mentioned to me.

You mentioned mis-assigned responsibility. Probably yes too, and my thinking was to have separated Rules completely from the Cell class, but again, probably wasn't a good decision of mine here. Currently I got regeneration function within Cell class - it is a big chance I didn't improve much with this decision either, might even made worse, well, future will show me.

The good moment was, that I started this project with tests, wanted to practice TDD, but at some point lost the track and tests were abandoned. So I need to work more on these now, and expect that I'll see more deficiencies. Obviously I don't have that much experience as you do, so things go slower for me and the comments you give are priceless, I just need more time to process them and understand.

For instance this your suggested test:

Yesterday I was questioning isAlive() method's necessity, now, this doesn't change much (I think) from system's code perspective (as I have method cellAt(..) and later I do check that in a Cell's regenerationRules() function what cell that is), but it makes tests to read way more fluently. Here is my current test just to demonstrate how it is less expressive/explicit than Junilu's:

First, that method name is poor. "With three inline alive...". At least it could have been: "with two alive neighbors", but then problem comes in, what is the cell we are talking about its neighbors. So I agree and going to implement this change. And now without even implementing it yet, I see how I'll be able to to remove explaining comment from Cell's regenerationRules function about the "null", because I won't pass a cell, but instead whether it simply is alive cell or not. Thank you.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Earlier, I wrote:Yesterday I was questioning isAlive() method's necessity, now, this doesn't change much (I think) from system's code perspective (as I have method cellAt(..) and later I do check that in a Cell's regenerationRules() function what cell that is), but it makes tests to read way more fluently.


Hm.. one thing. Currently I have a method cellAt(Location) within a World class, which I thought I'm going to replace with isAlive(Location). The problem I come across now, that my method cellAt(Location) is private.

Does it make sense to release access modifier just to have test more expressive? Or I should look for other approach, so my design would have a use of isAlive(Location) method not only within the World's class, so it could be justified? Once again, currently I keep game running by having public method hasPopulation(), and I don't need anything else at the moment.
 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
FWIW, cellAt(location).isAlive() seems very expressive to me. Even if you have world.cellAt(location).isAlive() it still makes a lot of sense.

I am traveling (plane is just about to push back now) so will follow up later.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, changing to isAlive(Location) instead cellAt(Location) I think already improves the code without taking into account how tests can be improved if I were release the access modifer (waiting for a response to above question).

So currently replased parts look like:

Function call: Cell.regeneration().apply(isAliveAt(location), numberOfLivingNeighborsAround(location))))

Some said why I don't have boolean, true; false. I personally think code reads more fluently if I have Cell.ALIVE. At least now.

[Edit] Had to revert back to cellAt(Location) method in the meantime..
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Gerard Charles wrote:This piqued my interest so I've been poking at it off and on the past few weeks. This is what I came up with:

https://github.com/Gerardwx/conway/


Gerard, if you'd like to go through similar review process as mine, please do create a new thread. Or, if everybody prefer, all can be discussed within this thread, as it is anyway fairly difficult to follow and discuss particular version of code (mine in this case) as code changes constantly/continuously.

Gerard, anyway, have a cow for attempting this project. There are things I do like about your code, and some that I don't.  But now I'm too biased to my code, so really couldn't tell anything constructive. However, it was mentioned in this thread by somebody about the programming styles, having said that, I wouldn't land up with such version even after 1000 attempts probably.

Think for a moment how would you extend your system with more states than just alive/dead. I'm still bogged with this hypothetical future requirement
 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There is no symmetry in the idea behind Cell.ALIVE. Why isn't there a Cell.DEAD or Cell.EMPTY then?

Also the Cell.regeneration() method still doesn't have great semantics to me. It feels too implementation-y.  I would buy Cell.isBorn() or Cell.survives() or Cell.dies() because those actually tell a story. The word "regeneration" does not fit the logic that is in that method. That's where the disconnect is for me. I would say it is a very smelly name at best.
 
Bartender
Posts: 1983
57
Eclipse IDE Google Web Toolkit Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:...

live_cell_with_three_neighbors_lives_on_in_next_generation()
live_cell_with_two_neightbors_lives_on_in_next_generation()
empty_cell_with_exactly_three_neighbors_comes_alive_in_next_generation()

...


This is really awesome, it does tell a story. I agree with Junilu's description about the Builder pattern as well. The only concept that I am still finding hard to digest is "empty cell". This gives the analogy of a "cell" (like a table cell or a prison cell) as a placeholder instead of a living organism. We're dealing with the creation of life here

I would call Junilu's last test case as :
On second thought, I am now having issues with the rules of the game.. What kind of sick ritual requires 3 members to mate !!?!
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:There is no symmetry in the idea behind Cell.ALIVE. Why isn't there a Cell.DEAD or Cell.EMPTY then?


Let me tell some history. I did have initially ALIVE; DEAD, and in some later version after rename indeed ALIVE and EMPTY, and at that time all looked fine. Then at some point I got comment about an EMPTY cell not making sense, as such cells occupy world with some prior cell slots. I took this thinking further.

So, ALIVE is an instance of a Cell, an existing cell, which actually lives/exists, otherwise, simply there isn't any cell, unpopulated cell (null/nothing/non-existing thing). I look at it now as not just on/of, true/false, live/dead states, but as an existing thing or non existing, currently there is an ALIVE cell which may exist and its possible existence is defined by the rules.

Does it make any sense to you?

Junilu Lacar wrote:Also the Cell.regeneration() method still doesn't have great semantics to me. It feels too implementation-y.  I would buy Cell.isBorn() or Cell.survives() or Cell.dies() because those actually tell a story. The word "regeneration" does not fit the logic that is in that method. That's where the disconnect is for me. I would say it is a very smelly name at best.


I see what you mean. Actually you are quite accurate. The regeneration() or RegenerationRules() names came to me because of the fact of having immutable cells, so in my head they don't become alive/come to live/die/born... Everytime they are new, hence regeneration(). And that is what you don't buy probably. Hm... I need to dive into tests and spend more time to see if I can find at least a more expressive name or a better name + some changes of an actual code.

But personally for me this test reads quite well and fairly understandable:


Note:
I need to apologise all if you think at some point that I disagree with your comments and don't proceed with some changes or ignore them, that's simply not true. It could be well that I already tried such approach, then somebody suggested differently, so I tried different approach too, then somebody says other way is possibly better, which I tried already too, so that would result in back-and-forth changes. Since I'm not trying to replicate GDCR event flow, I'm actually trying to arrive to a point of working system (it works already actually and has some very primitive gui) where I could enjoy the look in the end and along the way experiment with different approaches. I need to say, I tried quite a few approache, including having a habitual array with true/false states.
 
Piet Souris
Master Rancher
Posts: 3002
105
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If a Cell is alive purely because it is part of the world, then why is the 'ALIVE' necessary? An enum with only one state does not make much sense to me.

Then: why return a Bifunction that completely answers the question? Why can't the Cell return that answer itself? You would not need the 'apply' then.

In fact: your Cell now performs as if it represents the GameRules class. That is fine to me, but then why the enum?

And lastly: I loose a bit oversight. Have you tested the regeneration method of Cell? It returns a method that has a boolean and a long as parameter, and returns a Cell, that might be null.
But your test

does not have a boolean as first argument of the apply.

I think your world could simply exist of Locations, that take over the intended role of the Cell, including the regeneration part.

 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

salvin francis wrote:The only concept that I am still finding hard to digest is "empty cell". This gives the analogy of a "cell" (like a table cell or a prison cell) as a placeholder instead of a living organism. We're dealing with the creation of life here
...


This is the kind of conversation that a pair or mob should have. It's conversations like this that can lead to a shared understanding and rich semantics in the code. You're right, there's something off in the symmetry of "live_cell" and "empty_cell".

How about using the concepts of "occupied/empty" or "live/dead" instead?
 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"Regenerate" is defined as:

verb
/rəˈjenəˌrāt/
1. (of a living organism) regrow (new tissue) to replace lost or injured tissue.
"a crab in the process of regenerating a claw"

adjective
/rəˈjen(ə)rət/
1. reformed or reborn, especially in a spiritual or moral sense.

Neither of those meanings fits the "live cell survives to the next generation" scenario. So, if you consider the meaning that the word "regenerate" carries for most people, it's a misleading name. The cognitive dissonance you create with that name in this context is the same as the Stroop Effect.
 
Junilu Lacar
Sheriff
Posts: 12748
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

Piet Souris wrote:If a Cell is alive purely because it is part of the world, then why is the 'ALIVE' necessary? An enum with only one state does not make much sense to me.

Then: why return a Bifunction that completely answers the question? Why can't the Cell return that answer itself? You would not need the 'apply' then.


I have exactly the same issues with the design as Piet has explained here.

Returning a BiFunction from the static regeneration() method seems forced and it smells of a hammer looking for a nail to pound. In this case, it looks like the author was experimenting with higher order functions and lambdas and thought this might be a good application. It isn't.

(I say "the author" to avoid "you" -- trying to be as objective as possible. That's meant to stay "egoless" although it's harder when you have to discuss the author's intent. Here we have to treat the author's intent as a separate entity from the author's "self")
 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The only way I can imagine the higher order function make sense is if there was a situation where you have a working Game of Life that implemented the basic rules and said, "What if we were to change up the rules?"

To be able to switch out one set of rules for another, the rules themselves need to be reified. That is, they need to be turned into objects themselves.

And you know what, that actually gives me an idea for a challenge I can give for GDCR!

"How would you design a GoL implementation that allowed you to easily change the transition rules without editing any existing classes?"

BTW, "transition" is the word used in the Wikipedia article so I think you should at least consider renaming regeneration to transition.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:(I say "the author" to avoid "you" -- trying to be as objective as possible. That's meant to stay "egoless" although it's harder when you have to discuss the author's intent. Here we have to treat the author's intent as a separate entity from the author's "self")


I think I also need to refer to it as to a "code" at a given point in time, to which I appear to have credentials to do changes, and not "my code", because "my code" insists me to defend myself and my decisions, and that prevents from easy changes, it makes me feel connected with it too much, so I can't free up my minds. Since saw your messages early in a morning, been thinking about what you guys wrote all way long to work, and I'm driving...

Piet, Junilu, I see your points about returning a function (as an unnecessary step) and I agree with that, in this code it is really not necessary.

Will get back to your comments once get a bit time (it will be today).
 
Piet Souris
Master Rancher
Posts: 3002
105
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:(...)
Piet, Junilu, I see your points about returning a function (as an unnecessary step) and I agree with that, in this code it is really not necessary.


But another important goal of this project is to gain experience! I've so far never written a method that returns a method (as far as I can remember), so useful or not, do go on using it, is my advice.

Since a cellexists by the mere virtue of being part of the World, I would rename the first parameter of the regenerate method to something like: (boolean cellExists, long nrOfExistingNeighbors) {...}.
Since you want to invoke this method even if the Cell does not exist yet.

But I must admit: your project made me rethink about my own code, and I certainly have gained some ideas how to improve it.

Junilu wrote:"How would you design a GoL implementation that allowed you to easily change the transition rules without editing any existing classes?"


I have some ideas, but that'll be for after the GDCR. Knowing you a little, I expect nothing less than a comprehensive report    
Can't wait!
 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Phrases for effective egoless programming:
"the code" instead of "your code" or "my code"
"the design" instead of "your design" or "my design"
"the intent" instead of "your intent" or "my intent"
"the choice/decision" instead of "your choice/decision" ...

We get *the idea*... right?
 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I love seeing Liu embrace change and the idea of egoless programming. It is wonderful to see the growth spurt when people let go of their attachment to code and step into the Agile/growth mindset needed to be a ruthless refactorer.
 
Piet Souris
Master Rancher
Posts: 3002
105
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote: (...) Egoless programming[/google] does take a while to get used to. (...)


Junilu Lacar wrote: (...) We get *the idea*... right?


as said, gonna take a while
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tried to improve a given code based on the most recent comments about the Cell.regeneration().

Please find the corresponding diffed commit here or fresh Cell.java and CellTest.java files view.

In the World, the call reads as:

I renamed also World.nextGeneration() to World.tick(), which is a trial to see how reads. I'm personally neutral about this particular rename.
 
salvin francis
Bartender
Posts: 1983
57
Eclipse IDE Google Web Toolkit Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:How about using the concepts of "occupied/empty" or "live/dead" instead?


That sounds good.
My thought process was "exists" or "isPresent" as a method instead of a property. These are more in line with something exists or is present at a certain location in our world. I love that piet too is thinking in my way that a cell simply is there or is not there, there is no state to it.
 
Junilu Lacar
Sheriff
Posts: 12748
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:
In the World, the call reads as:

I renamed also World.nextGeneration() to World.tick(), which is a trial to see how reads. I'm personally neutral about this particular rename.


nextGeneration or tick, I could go with either, too.

The other call, however, still does not speak well to me. Shouldn't a Cell know it's own Location within World? What smell does the design avoid by not giving Cell that responsibility?

What is the flow of logic that calculates one generation to the next? It seems like the design was arrived at coming from a different perspective, one that was more speculative.
 
Piet Souris
Master Rancher
Posts: 3002
105
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

salvin francis wrote:(...) I love that piet too is thinking in my way that a cell simply is there or is not there, there is no state to it.


Yes, the world does not have a limit other than memory allows, and it would make a Cell class redundant (apart from the Business Rules, that is)
But the current set up is also fine, via a Map<Location, Cell>. Liutauras (alias the author) uses both techniques: the World having Locations that by that virtue exist, and the associate Cells have a status of Alive or Dead. That is the prerogative of the coder, choosing what suits/likes him/her best.

I'm happy with the code, only things missing is something that sets the world to moving/ticking, and a colorful gui (like you showed us in your GoL, some time ago!).

But one thing is sure: I know one who is going to the GDCR coming saturday, prepared to the teeth!
 
Junilu Lacar
Sheriff
Posts: 12748
210
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:That is the prerogative of the coder, choosing what suits/likes him/her best.


I disagree. I like to think that l listen to the code. I like to think that the code tells me what it wants to be. The design tells me what it wants to be. When people say they don't understand the code, that's the design saying it's not quite what it wants to be. To me, my job as a programmer is to figure out what the design wants to be, not what I want it to be.

I guess I've been influenced by ideas like "The sculptor is simply revealing the statue inside the block of marble. The sculptor's job is to remove the marble that isn't part of the statue." I see design as being a very similar effort.

Seen in a slightly different way, design is a solution and the solution is what the problem needs it to be. It's the problem that dictates what the design should be. Again, your job as a programmer is to discover what design the problem needs. That's my way of being egoless when it comes to programming and design. It's not about me and what I want.

Yet another egoless perspective is that I need to make sure the design makes sense to others. That is why I like collaborative methods like pairing and mobbing.
 
Liutauras Vilda
Marshal
Posts: 6263
420
BSD
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


Piet Souris wrote:Since a cellexists by the mere virtue of being part of the World, I would rename the first parameter of the regenerate method to something like: (boolean cellExists, long nrOfExistingNeighbors) {...}.
Since you want to invoke this method even if the Cell does not exist yet.


Yep, I did try to implement that in the code, and well, succeeded (very easy change), but as a result there were 2 things which I didn't like about that code.

1. There were two representations of an alive cell. As an enum constant Cell.ALIVE, and as boolean cellExists, while they aren't exactly the same, but... But I guess at the same time you suggested to remove Cell.ALIVE completely and have only boolean.

2. The biggest problem in that I saw, that Cell tests readability got worse. For example, let's take current look of one of the tests:

So having the boolean representation, the test would read as (unless all would get redesigned):


Piet Souris wrote:I think your world could simply exist of Locations, that take over the intended role of the Cell, including the regeneration part.


Agree, it could. But thinking further I don't see in current Map having Location and Cell (in particular cell) as a significant complexity increase, while I think having Cell gives some extra flexibility.


I think the next interesting addition would be to all these discussions, that after GDCR, we put the codes on the table (somewhere over here), and randomly pull out from the hat (rabbit's?) some extra random requirements , and try to extend systems, so we could see in real what limitations we face (or don't), how complicated it gets to extend. That would give some facts!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!