• 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 Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

How to structure a class with optional parameters

 
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Suppose I have the following interface:


1. What is considered proper practice when structuring a class that has optional parameters? For example, is this how you would structure it?
If the player begins a new game, he/she may not have a weapon to start off with or if I create a class called NPC that implements the Character interface, the NPC may have a game object(ex. coins, potions), but no weapons.

2. Assume my player starts off with nothing(no object or weapons), meaning gameObj and gameWeapon aren't set, what is considered proper practice if the getter is called, in other words, what should be returned if the optional parameters aren't set?
 
Saloon Keeper
Posts: 10687
85
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Starmoon wrote:If the player begins a new game, he/she may not have a weapon to start off with or if I create a class called NPC that implements the Character interface, the NPC may have a game object(ex. coins, potions), but no weapons.


It sounds like you may have more than one weapon or object. In that case I'd suggest a List and if there are none, then return an empty List.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Carey Brown wrote:

Hank Starmoon wrote:If the player begins a new game, he/she may not have a weapon to start off with or if I create a class called NPC that implements the Character interface, the NPC may have a game object(ex. coins, potions), but no weapons.


It sounds like you may have more than one weapon or object. In that case I'd suggest a List and if there are none, then return an empty List.



So, like this:



1. Is what I do in the constructor(creating the arraylists) instead of passing it in as a parameter, okay?
2. Are the add/remove methods okay to have? Is there a better way of doing it?
 
Carey Brown
Saloon Keeper
Posts: 10687
85
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:1. Is what I do in the constructor(creating the arraylists) instead of passing it in as a parameter, okay?
2. Are the add/remove methods okay to have? Is there a better way of doing it?


1. Yes.
2. Add/remove is the better way.

In general, you're on the right track, but you have some syntax errors that would keep it from compiling.

Curious: why "gameWeapon" vs just "weapon" ?
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Carey Brown wrote:

Hank Emery wrote:1. Is what I do in the constructor(creating the arraylists) instead of passing it in as a parameter, okay?
2. Are the add/remove methods okay to have? Is there a better way of doing it?


1. Yes.
2. Add/remove is the better way.

In general, you're on the right track, but you have some syntax errors that would keep it from compiling.

Curious: why "gameWeapon" vs just "weapon" ?



AH! I'm using Notepad++ to write the above code. Don't have an IDE at the moment.

I have some experience with C# and they have a naming convention that just seemed to stick with me, even if I'm writing Java. This project is a hobby project, so yes, weapon would be just fine as well.

Just a small clarification, when you say Add/Remove is better? You mean like this ?


 
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
An interface that defines only getter and setter methods is smelly. An interface should be a contract for behavior or capabilities. The only thing that your interface says its implementations can do is to be told what its attributes are and to be told to share its attributes, so you probably don't have a very good understanding of what object-orientation is about. This interface basically sets up its implementations to have their encapsulation broken from the moment they come into existence.

Defining an interface also says that your design doesn't care about the object hierarchy of the implementation. It says, "As long as you can behave in these ways (the behavior/capabilities that the interface methods specify), you will be treated as such and such."  It's like saying "It doesn't matter what your background is, whether rich or poor, formally educated or self-educated, of nobility or of the gentry, as long as you behave like a gentleman and a scholar, then you will be treated and afforded the office and due deference as such."
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:An interface that defines only getter and setter methods is smelly. An interface should be a contract for behavior or capabilities. The only thing that your interface says its implementations can do is to be told what its attributes are and to be told to share its attributes, so you probably don't have a very good understanding of what object-orientation is about. This interface basically sets up its implementations to have their encapsulation broken from the moment they come into existence.

Defining an interface also says that your design doesn't care about the object hierarchy of the implementation. It says, "As long as you can behave in these ways (the behavior/capabilities that the interface methods specify), you will be treated as such and such."  It's like saying "It doesn't matter what your background is, whether rich or poor, formally educated or self-educated, of nobility or of the gentry, as long as you behave like a gentleman and a scholar, then you will be treated and afforded the office and due deference as such."



How would you then restructure this?
 
Carey Brown
Saloon Keeper
Posts: 10687
85
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:Just a small clarification, when you say Add/Remove is better? You mean like this ?


Here's the javadoc for the remove() method. Note that you don't have to check whether or not the list contains your object before hand.

Also, "remove" is a verb and you want to remove a noun. I.e.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:How would you then restructure this?


Well, first I'd think about what my motivation is for defining an interface for Character. What parts of the program should be able to treat different kinds of objects as one generic Character type? What exactly are the different kinds of objects that should be treated generically as Characters? What are the cases where my code needs to know the specific type of object it's dealing with? Am I going to have to cast a Character reference to a specific implementation type? Why? Are those valid reasons?

These are just a few of the questions I'd have to consider to be able to say, "I'd structure the code this way or that way instead."
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I don't know what it is about how people think but I have found that we don't naturally think in terms of objects, at least not when we're trying to write computer programs. Many of us tend think in a way that's actually opposite of the way we should be thinking when we're trying to write object-oriented programs.

Your initial definition of the Character interface is the perfect example. So is a lot of the other code you've written and statements you've made.

One rule of thumb in object-orientation is to "Tell, Don't Ask" Providing getters in your objects already puts you in a "Ask" mindset, so you have to catch yourself when you do that right off the bat and start writing code that's based primarily on you setting attributes, passing objects around, and then getting their attributes so that you can use them in some kind of calculation that is external to the objects whose attributes you're using.

You have to train your brain to think in the opposite way and try not to use getters and setters so much.

Here's an alternative way to see a Character:

Now you have a Character with a set of capabilities/behaviors defined. Next, I'd go and experiment with what a Character object like this can do in a program where Weapon objects and Money objects are also available. How do these interact? How do I orchestrate the behaviors of Character, Weapon, and Money objects to do something interesting, perhaps within the context of a Game object?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The other thing you have to be mindful of is that of thinking too much about implementation details. When you define a method like

You have to stop and think about a number of things about that code:

1. Why does that code stutter so much? How many times does the word "weapon" appear in that one line of code? If you read the code OUT LOUD, you'll hear yourself stutter. Renaming the parameter to something else might help but it's the method name and parameter type that's really the problem of code stutter. Here's my thinking about this kind of code: why do you have to reinforce the fact that the method parameter is a Weapon by qualifying the method name with the word "Weapon"? What if the standard library did that, let's say with the StringBuffer class. Then you might have methods like appendString(String) and appendInteger(Integer), right? Well, good thing it's not like that. So why would you define your programs like that?

2. Semantics. The method name says "remove". Remove the weapon from what? What is this thing that you imply we're removing the weapon from?  If you called the method as I did, pickUp(Weapon), this is clearly a way for me to have a direct "conversation" with the object I'm calling the method on. There's not much implied in the imperative sentence, "Pick up that weapon."  Whereas when you say "Remove that weapon" it would be natural to ask, "Ok, remove it from where?" You are inadvertently revealing implementation detail with this kind of name, the implementation detail that a Character has some kind of storage where it keeps Weapon objects and now you're asking it to remove the Weapon from that internal collection. Revealing knowledge of internal implementation details is not a good thing. It violates the principle of abstraction.  In fact, I would argue that the method named removeWeapon(Weapon) is a Leaky Abstraction. The boolean return value to indicate success or failure also contributes a little bit to leaking information about internal implementation details.

By contrast, the combination of void drop(Weapon) and boolean has(Weapon) methods gives you an alternative that is more abstract and less leaky than boolean removeWeapon(Weapon).
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Notice that I previously said, "I'd have to go an experiment with a Character that is defined like this."

That's because when you start out with a design, your ideas about how everything works together is very vague and nebulous. You have to write code to see exactly what it looks like "on paper" instead of just in your head. Ideas seem far better when they're just floating around in our heads. It's only when you put those ideas into code and can actually SEE the design as code that your are able to (if you have trained yourself enough) see all the little flaws and gaps that your brain was somehow filling in or ignoring altogether.

Again, this is why I am a firm believer in Jack Reeves' propositions that Code is Design.

(Edit: I said "Again" but if I didn't mention Jack Reeves before in this thread, I must have done it in a post I made today in a different thread).
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And to show I can be direct to the point as much I can be long-winded...

What's wrong with just writing this?
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Notice that I previously said, "I'd have to go an experiment with a Character that is defined like this."

That's because when you start out with a design, your ideas about how everything works together is very vague and nebulous. You have to write code to see exactly what it looks like "on paper" instead of just in your head. Ideas seem far better when they're just floating around in our heads. It's only when you put those ideas into code and can actually SEE the design as code that your are able to (if you have trained yourself enough) see all the little flaws and gaps that your brain was somehow filling in or ignoring altogether.

Again, this is why I am a firm believer in Jack Reeves' propositions that Code is Design.

(Edit: I said "Again" but if I didn't mention Jack Reeves before in this thread, I must have done it in a post I made today in a different thread).



Many thanks for taking the time, and effort to explain this stuff to me.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:And to show I can be direct to the point as much I can be long-winded...

What's wrong with just writing this?



There is nothing wrong with this, but I was reading Effective Java, and it recommends interfaces over abstract classes. It never went in depth as you did, however.

Another question I have is, take this for example:

Lets say I have to create a small program that will handle domestic and international students, now obviously,  attributes such as Student ID, Student First and Last name are going to be common across both types of students, where then should I place the getters?  

Let's say if I have a method that displays student number regardless of student type,



I understand I violated what you just explained when it comes to naming conventions, but it's the only way I could explain my problem.
 
Carey Brown
Saloon Keeper
Posts: 10687
85
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Id, first, and last should all be fields of Student and the getters/setters for them should also be in Student.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Carey Brown wrote:Id, first, and last should all be fields of Student and the getters/setters for them should also be in Student.



I agree BUT, we have violated what Junilu Lacar took time to explain. Using what Junilu Lacar explained, what should be done when we have properties shared across two different classes?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:I understand I violated what you just explained when it comes to naming conventions, but it's the only way I could explain my problem.


Don't take any of my comments about getters and setters violating encapsulation turn into an indictment of those kinds of methods. You have to balance it out. Go back and see where I said something along the lines of "You have to be careful... if you define getters and setters right off the bat and start writing your code and formulating your design around these methods, then you're probably thinking the opposite way of how you need to be when writing object-oriented programs."

In other words, don't let getters and setters be the central focus of your design. If possible, use them only for display purposes. There's another school of thought, or at least experimentation, where you go to the extreme of sticking with encapsulation that you do things like this:

It's not difficult to imagine what the student.displayId() method looks like. Sure, this looks like you've preserved encapsulation and it certainly is an interesting exercise to try to write a lot of code like this. I've done it and it gets to be a pain in the neck. So yeah, I use getters when I need to display things. I'm not crazy dogmatic about object-orientation. But I do find that trying to stay true to the principles does help me a lot as well. You just have to know when it's OK to bend the rules a little bit.

 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:
Let's say if I have a method that displays student number regardless of student type,



Andy Hunt's Rule #1: Always Consider Context.

Where is this code located? What is the larger picture that this code operates within? What's the difference between an International student and a Domestic student and how is that significant to viewing their IDs?

I could certainly imagine something like this (maybe) being a valid responsibility of some class:

It's hard to give an answer to a question where the context is unknown or left to the imagination. So, again, what's the bigger picture of what you're trying to achieve by displaying a Student's id?
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Hank Emery wrote:I understand I violated what you just explained when it comes to naming conventions, but it's the only way I could explain my problem.


Don't take any of my comments about getters and setters violating encapsulation turn into an indictment of those kinds of methods. You have to balance it out. Go back and see where I said something along the lines of "You have to be careful... if you define getters and setters right off the bat and start writing your code and formulating your design around these methods, then you're probably thinking the opposite way of how you need to be when writing object-oriented programs."

In other words, don't let getters and setters be the central focus of your design. If possible, use them only for display purposes. There's another school of thought, or at least experimentation, where you go to the extreme of sticking with encapsulation that you do things like this:

It's not difficult to imagine what the student.displayId() method looks like. Sure, this looks like you've preserved encapsulation and it certainly is an interesting exercise to try to write a lot of code like this. I've done it and it gets to be a pain in the neck. So yeah, I use getters when I need to display things. I'm not crazy dogmatic about object-orientation. But I do find that trying to stay true to the principles does help me a lot as well. You just have to know when it's OK to bend the rules a little bit.



It's going to take some practice, and patience, but I think I'm getting it. How did you come to learn all of this? Years of experience, or school? I "learned" Java in school but never came across what you just demonstrated. There is another thread talking about how universities aren't properly teaching programming, and after what I've seen, and been through, I agree. I used learned in quotes, as they brushed past important topics, and even violated proper practices without any mention. It's only after reading Effective Java that I learned my professor where making mistakes and teaching it as if it was normal. This to me is wrong, and your sending students out into the real world thinking they know how to write proper code. I've seen a professor overwrite the equals method and do everything Effective Java warns against! She didn't even mention this was incorrect. Effective Java wasn't even on the reading list, I found it on Amazon, and after seeing recommendations on SO, I bought it(a quality buy, too!).
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Remember that principles like encapsulation, inheritance, abstraction, polymorphism are guidelines that help you stay out of trouble. Guidelines are only good as they are useful. When you are in a situation where other guidelines are more useful, then you go with that other principle.  Take Bloch's advice to prefer composition to inheritance. Ok, fine. When composition makes sense over inheritance, then use composition. However, you also need to know when Inheritance also makes sense and be able to make the appropriate design decisions that will keep you from getting into the kind of trouble that poor use of inheritance can get you in.

So preferring composition over inheritance does not mean the same thing as "Always use composition, never inheritance."
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Hank Emery wrote:
Let's say if I have a method that displays student number regardless of student type,



Andy Hunt's Rule #1: Always Consider Context.

Where is this code located? What is the larger picture that this code operates within? What's the difference between an International student and a Domestic student and how is that significant to viewing their IDs?

I could certainly imagine something like this (maybe) being a valid responsibility of some class:

It's hard to give an answer to a question where the context is unknown or left to the imagination. So, again, what's the bigger picture of what you're trying to achieve by displaying a Student's id?



Let's say I have a method that displayed an attendance list for a class, regardless of International/Domestic.

My whole point/question is, when it makes sense, it's okay to have getters/setters in the interface correct? but don't get carried away and have that be the only reason why I'm using and interface(just to have getter/setters)?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:
It's going to take some practice, and patience, but I think I'm getting it. How did you come to learn all of this? Years of experience, or school? I "learned" Java in school but never came across what you just demonstrated. There is another thread talking about how universities aren't properly teaching programming, and after what I've seen, and been through, I agree. I used learned in quotes, as they brushed past important topics, and even violated proper practices without any mention. It's only after reading Effective Java that I learned my professor where making mistakes and teaching it as if it was normal. This to me is wrong, and your sending students out into the real world thinking they know how to write proper code. I've seen a professor overwrite the equals method and do everything Effective Java warns against! She didn't even mention this was incorrect. Effective Java wasn't even on the reading list, I found it on Amazon, and after seeing recommendations on SO, I bought it(a quality buy, too!).


Yes, I am coming up to almost thirty years as a professional developer. So I've seen a lot of... well, let's just call it "stuff"... that's just totally messed up. The thread you are alluding to is probably one that I started or am heavily commenting on.

I actually just got back from doing a workshop on trying to figure out how to better align academia and industry because you're right, I do see a lot of schools getting so far behind current industry practices that I'm actually starting to believe Robert "Uncle Bob" Martin's dire prediction that the 50% of the total developer population in the world that has less than 5 years of experience is a dire portent of a disaster or series of disasters that is/are bound to happen in the next few years. Go out on YouTube and watch "Uncle Bob - Future of Programming" - he talks about this impending disaster somewhere in the last 18 minutes of this presentation. I'd encourage you to watch the entire presentation though because Uncle Bob's talks can be quite entertaining as they are educational.

I'm glad there are students like you who think critically and who go out and search for information to supplement what they are learning in the classroom. It's important that you stay in touch with the real world because as far as what I have seen, most professors don't. In fact, the professors I collaborated with at the Charleston Southern University were the first ones to express these same concerns and do something about it with me. Others I have tried to reach out to in other universities were not so open-minded.

You have to start somewhere though and if I can make a little bit of difference to one or two people, my hope is that they will be compelled to make a difference for another two or three people as well. Hey, we're computer folks. We should know how exponential growth works, right?

So, yeah, practice. And practice A LOT.

How do you get to Carnegie Hall? Practice, Practice, Practice!

But practice mindfully because... "Practice only makes habit; only perfect practice makes perfect."—Every music teacher, ever.

So,

Junilu Lacar wrote:Practice doing the right things and doing things right.


 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:My whole point/question is, when it makes sense, it's okay to have getters/setters in the interface correct? but don't get carried away and have that be the only reason why I'm using and interface(just to have getter/setters)?


And I think my point is that an interface that has getters and setters is kind of smelly. Look at the interfaces defined in the Standard Libraries: How many of them have mostly getters and setters in them? I can't think of any. Interfaces define contracts for behavior. Getters and setters, on the other hand, are about data and attributes. So, you have to go deeper in thought and justification to figure out if an interface that's loaded with getter/setter methods is really a good design choice. I would lean towards "It's not" and try to find another way / other ways to organize my ideas.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Hank Emery wrote:
It's going to take some practice, and patience, but I think I'm getting it. How did you come to learn all of this? Years of experience, or school? I "learned" Java in school but never came across what you just demonstrated. There is another thread talking about how universities aren't properly teaching programming, and after what I've seen, and been through, I agree. I used learned in quotes, as they brushed past important topics, and even violated proper practices without any mention. It's only after reading Effective Java that I learned my professor where making mistakes and teaching it as if it was normal. This to me is wrong, and your sending students out into the real world thinking they know how to write proper code. I've seen a professor overwrite the equals method and do everything Effective Java warns against! She didn't even mention this was incorrect. Effective Java wasn't even on the reading list, I found it on Amazon, and after seeing recommendations on SO, I bought it(a quality buy, too!).


Yes, I am coming up to almost thirty years as a professional developer. So I've seen a lot of... well, let's just call it "stuff"... that's just totally messed up. The thread you are alluding to is probably one that I started or am heavily commenting on.

I actually just got back from doing a workshop on trying to figure out how to better align academia and industry because you're right, I do see a lot of schools getting so far behind current industry practices that I'm actually starting to believe Robert "Uncle Bob" Martin's dire prediction that the 50% of the total developer population in the world that has less than 5 years of experience is a dire portent of a disaster or series of disasters that is/are bound to happen in the next few years. Go out on YouTube and watch "Uncle Bob - Future of Programming" - he talks about this impending disaster somewhere in the last 18 minutes of this presentation. I'd encourage you to watch the entire presentation though because Uncle Bob's talks can be quite entertaining as they are educational.

I'm glad there are students like you who think critically and who go out and search for information to supplement what they are learning in the classroom. It's important that you stay in touch with the real world because as far as what I have seen, most professors don't. In fact, the professors I collaborated with at the Charleston Southern University were the first ones to express these same concerns and do something about it with me. Others I have tried to reach out to in other universities were not so open-minded.

You have to start somewhere though and if I can make a little bit of difference to one or two people, my hope is that they will be compelled to make a difference for another two or three people as well. Hey, we're computer folks. We should know how exponential growth works, right?

So, yeah, practice. And practice A LOT.

How do you get to Carnegie Hall? Practice, Practice, Practice!

But practice mindfully because... "Practice only makes habit; only perfect practice makes perfect."—Every music teacher, ever.

So,

Junilu Lacar wrote:Practice doing the right things and doing things right.




I agree with everything you said, and I'll check out the web series.

To finish off my question, supposed I have a method that generates an attendance list for a class, regardless of domestic or international?

Assume we receive a list of newly registered students that's taking a beginner level Java course. Now, let's assume that each class holds 20 students, meaning our method would take the list, generate the attendance list of 20 students and write that new attendance list to the database(I'll keep it simple, for the purpose of my question, we're talking about the Student interface and attendance).  Regardless of Student type, you at least need first and last name.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One thing I've learned through experience and experimentation is to not go hog-wild about using interfaces. Everything in moderation. Having a Student type defined as an interface might be a bit much.  Right now, my heuristic is to use interfaces at system/layer/architectural boundaries.  This helps me keep layers relatively decoupled. Within a layer, there's not much need to use interfaces to put a level of indirection and decoupling between classes. If classes are all in the same layer, let them "know" about each other on a more intimate level. Interfaces put a lot of "distance" between types by hiding as much implementation details as possible. When this kind of abstraction is justified, it's a good thing. When it gets too much, it adds unnecessary complexity, which should be avoided.

So, should Student be an interface if you're just trying to do the things you described? I would lean towards, "probably not."
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:... meaning our method would take the list, generate the attendance list of 20 students and write that new attendance list to the database


And no, your method shouldn't do all those things. You should separate those concerns and delegate them to different methods that each do their own little job. Those methods will probably be in different classes, too, since a class that generates a report is probably going to be in a different layer from a class that saves a list of objects to the database. Functional Decomposition and Separation of Concerns is what you want to keep in mind.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:How did you come to learn all of this? Years of experience, or school? I "learned" Java in school but never came across what you just demonstrated.


I've actually been writing about this for my own purposes. I learned Java partly on my own and mostly from the many people here at the Ranch. Many of the "deeper" insights also came from discussions here but also from real-world experience, many bad (few things can beat learning in the school of hard knocks) many of them good as well. It's important to have that balance of seeing how messed up things can get and actually living out the flipside to the bad situations.

This is why I'm a vocal proponent for Test-Driven Development and Agile software development practices. I've seen what can be accomplished when you use these techniques correctly. I've also seen the messed up situations that you can find yourself in if you don't use them or don't use them effectively/correctly.

But I think I lucked out with my university professors. They were mostly industry professionals and had backgrounds as licensed engineers (Electronics and Communications Engineers mostly), had work experience in the industry on top of being educators, and they were businessmen (a group of them owned the first computer training and software development center in our city, in Mindanao, Southern Philippines). So, even though the prevailing programming paradigm back then was still structure/procedural programming and I learned how to program using Pascal and BASIC, the concepts that I was taught early in school included functional decomposition, modularization, organization, and abstraction. These are principles that seem to be applicable to any kind of problem solving endeavor and at its core, programming is just a fancy way to solve problems using a mathematically based language and a bunch of electronic circuitry. The technology may change, the language may be different, but the principles pretty much stay the same.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:One thing I've learned through experience and experimentation is to not go hog-wild about using interfaces. Everything in moderation. Having a Student type defined as an interface might be a bit much.  Right now, my heuristic is to use interfaces at system/layer/architectural boundaries.  This helps me keep layers relatively decoupled. Within a layer, there's not much need to use interfaces to put a level of indirection and decoupling between classes. If classes are all in the same layer, let them "know" about each other on a more intimate level. Interfaces put a lot of "distance" between types by hiding as much implementation details as possible. When this kind of abstraction is justified, it's a good thing. When it gets too much, it adds unnecessary complexity, which should be avoided.

So, should Student be an interface if you're just trying to do the things you described? I would lean towards, "probably not."



Small question, let's assume our game is really simple, if we add the methods increacehealth/decreasehealth to our character interface, and had a Weapon interface, now a weapon would obviously cause damage to our character. How would you create a weapon interface(cause our game can have more than one weapon that share the same attributes), and get the damage that weapon causes to deplete our character health? As you said getters/setter are code smell, so a getter like getWeaponDamage(); isn't considered proper practice. What would you do in this case?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Hank Emery wrote:Small question, let's assume our game is really simple, if we add the methods increacehealth/decreasehealth to our character interface, and had a Weapon interface, now a weapon would obviously cause damage to our character. How would you create a weapon interface(cause our game can have more than one weapon that share the same attributes), and get the damage that weapon causes to deplete our character health? As you said getters/setter are code smell, so a getter like getWeaponDamage(); isn't considered proper practice. What would you do in this case?


Method names like increaseHealth() and decreaseHealth() are smelly because they have a data focus. Increasing or decreasing the health of a Character happens as a consequence of some event or action that involved the Character. So I would look to that event or action and try to see what can be done inside the methods that handle the event or action to automatically increase or decrease health, without any external entity saying "Increase your health, Character, by this much!" or "Decrease your health, Character, by this much!"

I would probably think, when does my Character's health increase? When does it decrease? If a Character's health increases when you call its rest() or recover() method or it somehow gains health by killing its opponent as a result of you calling strike(Character other), then this is something that I might try:

You can probably guess in which methods each Character object's health is actually increased and decreased, right? Nobody external to the Character object had to manipulate its health levels. The Character object does that as a result of finishing off its opponent. The opponent, on the other hand, gives out the information about how much health it had left after setting its own health to zero when its finishOff() method gets called.

Do you see how this kind of code tells a story? It's not some "godlike" programmer inserting his thoughts into the commands and manipulating object properties through program commands. It's just objects encapsulating logic that makes them behave like their own animate and sentient things. That's the magic that happens when you write programs like this. Your thoughts come alive in the program even as they leave your head and get encoded in 1s and 0s in the computer.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That code was just a sample of what you might do a method like strike(Character opponent). You might want to code more logic in there, like if the opponent isn't killed by the strike, then you should use up some of the health based on the power that was used to strike the opponent. Maybe you'd have some logic to make the opponent do a counterstrike if it can fully defend against any given strike.

There are lots of rules that you can implement in these kinds of methods that give your objects a life and intelligence of their own. This is what object-orientation is about and that's why I often say that object-orientation is about behaviors and capabilities. Data and attributes are only the things that help support objects being able to exhibit their behaviors or capabilities. That's why you don't want to focus your design around methods names like getWhatever() and setWhatever() or increaseSomeAttribute() or decreaseSomeAttribute(). Those kinds of methods should be secondary in a design.

Methods like strike(Character opponent) and defendAgainst(Weapon, Power) are more interesting object behavior and these are what you should focus your design thinking on.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Hank Emery wrote:Small question, let's assume our game is really simple, if we add the methods increacehealth/decreasehealth to our character interface, and had a Weapon interface, now a weapon would obviously cause damage to our character. How would you create a weapon interface(cause our game can have more than one weapon that share the same attributes), and get the damage that weapon causes to deplete our character health? As you said getters/setter are code smell, so a getter like getWeaponDamage(); isn't considered proper practice. What would you do in this case?


Method names like increaseHealth() and decreaseHealth() are smelly because they have a data focus. Increasing or decreasing the health of a Character happens as a consequence of some event or action that involved the Character. So I would look to that event or action and try to see what can be done inside the methods that handle the event or action to automatically increase or decrease health, without any external entity saying "Increase your health, Character, by this much!" or "Decrease your health, Character, by this much!"

I would probably think, when does my Character's health increase? When does it decrease? If a Character's health increases when you call its rest() or recover() method or it somehow gains health by killing its opponent as a result of you calling strike(Character other), then this is something that I might try:

You can probably guess in which methods each Character object's health is actually increased and decreased, right? Nobody external to the Character object had to manipulate its health levels. The Character object does that as a result of finishing off its opponent. The opponent, on the other hand, gives out the information about how much health it had left after setting its own health to zero when its finishOff() method gets called.

Do you see how this kind of code tells a story? It's not some "godlike" programmer inserting his thoughts into the commands and manipulating object properties through program commands. It's just objects encapsulating logic that makes them behave like their own animate and sentient things. That's the magic that happens when you write programs like this. Your thoughts come alive in the program even as they leave your head and get encoded in 1s and 0s in the computer.



I'm starting to get into what you're saying

Now a little more complexity, don't worry no need for code just an explanation. Lets say that we have a health bar on screen, opponent.defendAgainstStrike() will probably call a few private helper methods to determine if the strike was successful or not, if not, it would take the damage the weapon caused and decrease the health, and then render the health bar(calling a separate method) to display, correct?

Let's say the Weapon was a ChargeGun(a futuristic pulse gun), so the strike method becomes shoot, the logic is almost the same, but instead of power() being passed when defendAgainstStrike(this.weaponInHand, power()) , could I pass this.damage() (assuming when I created my ChargeGun instance I passed the damage as a parameter in the constructor.  Like this:

Within the ChargeGun class:

 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And don't forget what I said before: Ideas that float around in your head seem better than they actually are than when you actually see them "on paper", i.e., in actual code.

Take what I just suggested:

That might not be quite right either. Why am I passing the absorbHealth() method the result of calling opponent.finishOff()? Would it be more clear and abstract if I wrote this instead?

Do you see what I changed? That means I eliminate the absorbHealth() method and have this instead:

I still have a pretty good story going on here, right? I would read that as "When I finish off this other Character, I make it relinquish all its remaining health and I absorb that health into myself"
Those two methods are simply:

Still a pretty good story in this code, right?
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:And don't forget what I said before: Ideas that float around in your head seem better than they actually are than when you actually see them "on paper", i.e., in actual code.

Take what I just suggested:

That might not be quite right either. Why am I passing the absorbHealth() method the result of calling opponent.finishOff()? Would it be more clear and abstract if I wrote this instead?

Do you see what I changed? That means I eliminate the absorbHealth() method and have this instead:

I still have a pretty good story going on here, right? I would read that as "When I finish off this other Character, I make it relinquish all its remaining health and I absorb that health into myself"
Those two methods are simply:

Still a pretty good story in this code, right?



Indeed, it is a good story, if you could take a look at the code I just posted, right before you posted yours, I changed strike to Shoot and a small alteration, I wanted to know if it's okay?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
With your ChargeGun example, I'm not so sure I'd do it that way. The semantics of that stuff happening in the ChargeGun class doesn't seem as natural as they would in a Character.  I might try to see what the commonalities are between different weapons and try to find an abstraction to represent their usage. I probably wouldn't care too much about the semantics of methods names strike() versus shoot() versus stab() or slice().  I tend to use those names only to find what the abstraction is that I'm really looking for. For example, given all those different ways of using a Weapon, I might end up refactoring the method to this instead:

Or something like that. Make sure to read your code over and over, forgetting everything you were thinking about before and come at the code as though you were someone else seeing it for the first time. Does it make sense? Is the story coherent? Do the object actions make sense? Do the method names reveal the intent? The variable names, do they reveal their intent? Do they add richness to the story you're trying to tell with this code?

That's basically my thought process when I try to critique my code.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:With your ChargeGun example, I'm not so sure I'd do it that way. The semantics of that stuff happening in the ChargeGun class doesn't seem as natural as they would in a Character.  I might try to see what the commonalities are between different weapons and try to find an abstraction to represent their usage. I probably wouldn't care too much about the semantics of methods names strike() versus shoot() versus stab() or slice().  I tend to use those names only to find what the abstraction is that I'm really looking for. For example, given all those different ways of using a Weapon, I might end up refactoring the method to this instead:

Or something like that. Make sure to read your code over and over, forgetting everything you were thinking about before and come at the code as though you were someone else seeing it for the first time. Does it make sense? Is the story coherent? Do the object actions make sense? Do the method names reveal the intent? The variable names, do they reveal their intent? Do they add richness to the story you're trying to tell with this code?

That's basically my thought process when I try to critique my code.



A little more clearer, thanks.

Let me just understand the logic a little here, Weapon would have a method called power that returns the power it can cause and you pass that to the opponent



to determine if said weapon did cause damage. If so, the Character class has other methods to reduce the health, and render the heath bar.

Is the attackWeapon.power(); simply a method that was overridden from an interface, and simply returns an int?

Like this:


 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's another reason I'd resist putting that logic in a class like ChargeGun. What do you do in other Weapon classes? What you'll probably end up seeing is a lot of duplicated logic. Another principle of good software is DRY, or Don't Repeat Yourself.  DRY is about duplicated ideas/knowledge/behavior, not duplicated characters/letters, as most people might think.  If each Weapon's "attack"-type method, slice, shoot, stab, poke, whatever, had to the same kind of logic that said:

then this would be a violation of DRY. You'd want to have that logic in one place only so that if you have to change it, it would only have to be changed in that one place. Duplicated knowledge/ideas/behavior makes you do more maintenance work than you should have to and it's a source of bugs that make your program's behavior inconsistent or just plain wrong in some parts while it's correct in others (indicating that you forgot to update one or more duplicated parts).
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Here's another reason I'd resist putting that logic in a class like ChargeGun. What do you do in other Weapon classes? What you'll probably end up seeing is a lot of duplicated logic. Another principle of good software is DRY, or Don't Repeat Yourself.  DRY is about duplicated ideas/knowledge/behavior, not duplicated characters/letters, as most people might think.  If each Weapon's "attack"-type method, slice, shoot, stab, poke, whatever, had to the same kind of logic that said:

then this would be a violation of DRY. You'd want to have that logic in one place only so that if you have to change it, it would only have to be changed in that one place. Duplicated knowledge/ideas/behavior makes you do more maintenance work than you should have to and it's a source of bugs that make your program's behavior inconsistent or just plain wrong in some parts while it's correct in others (indicating that you forgot to update one or more duplicated parts).



I'm very aware of DRY

If you could verify my post before the one you just posted, I'll drop this topic . It got off topic a while ago, and probably deserves it's own thread.
 
Hank Emery
Ranch Hand
Posts: 47
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Here's another reason I'd resist putting that logic in a class like ChargeGun. What do you do in other Weapon classes? What you'll probably end up seeing is a lot of duplicated logic. Another principle of good software is DRY, or Don't Repeat Yourself.  DRY is about duplicated ideas/knowledge/behavior, not duplicated characters/letters, as most people might think.  If each Weapon's "attack"-type method, slice, shoot, stab, poke, whatever, had to the same kind of logic that said:

then this would be a violation of DRY. You'd want to have that logic in one place only so that if you have to change it, it would only have to be changed in that one place. Duplicated knowledge/ideas/behavior makes you do more maintenance work than you should have to and it's a source of bugs that make your program's behavior inconsistent or just plain wrong in some parts while it's correct in others (indicating that you forgot to update one or more duplicated parts).



Ideally where would you place this type of logic so that we don't violate DRY?
reply
    Bookmark Topic Watch Topic
  • New Topic