• Post Reply Bookmark Topic Watch Topic
  • New Topic

Non-static Private variables vs Local variables  RSS feed

 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Let's say I have the following:


Now, I have many methods where I have declared local variables. When I call other methods within these method I have to pass in arguments to work with those local variables, obviously. The problem is that there are many things that I am checking in the methods and I am passing many arguments; sometimes 5 or 6 and I find that this adds more time when debugging and it's prone to errors. I could very well declare all of these variables as non-static and private like the other ones above so that I could just use them any where in the class. I have been told however that this is not good.
What is the convention? When is it good practice to declare them as such?

Should I only use local variables when I am only using them in that method and nowhere else? This has always been in my mind so I need some guidance please because as the projects I code get larger and larger this is starting to become an issue.
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16060
88
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Adding member variables to your class just because you need to pass variables from one method to the other inside the class is indeed not good practice.

If you find that you have to pass too many variables between methods, you have to re-think the design of your class and the methods. It's a sign that you are making your class and methods too complicated and that you should probably split it up into smaller, simpler classes or methods.

One of the object oriented programming design principles is the single responsibility principle: a class, or method, should do only one thing, and not multiple, unrelated things, because otherwise it will tend to become too complicated. What you experience might be a sign that your class and methods are violating this principle.

In general, the scope of variables should be as small as possible. This includes: use local variables instead of member variables when these variables are only needed inside one method.
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I feel like I did not explain it right. I posted a few threads with questions about this particular project. Our professor wants us to call methods from each subtract, add, multiplication etc method to check for signs, which one is bigger so that we can call the right method.
For instance, in the subtract method I have these local variables:



Should I have just declared them as private instance variables that way I do not have to pass them each time to the other methods? I hope this is clear
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jesper de Jong wrote:Adding member variables to your class just because you need to pass variables from one method to the other inside the class is indeed not good practice.

If you find that you have to pass too many variables between methods, you have to re-think the design of your class and the methods. It's a sign that you are making your class and methods too complicated and that you should probably split it up into smaller, simpler classes or methods.



I was thinking about that but I am not adding any more member variables. The variables that I am always passing from the subtract method to other methods to check whether that is the correct one to use are those same that I have posted. I just don't know if it would be a good idea to declare them as member variables or not. But I see from your advice that I do need to fix the design. Each method does one thing only but unfortunately we can only use one class and put all the methods here which I do not like.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In general, you want to keep the scope of your program entities as small as possible and limit access to them to only the things that need them. If a value is used only in a method, then why would you want to declare it in a wider scope?

People get themselves into big messes because they let little messes live on for a long time. You will never write correct code with one or two tries. There's always something that you should refactor, especially as your requirements and your solutions grow bigger and more complex. If you neglect to refactor your small mistakes as you make them, then they grow into bigger mistakes.  Small mistakes are easier to fix soon after you make them. The more time there is between when you make a poor decision and when you realize your mistake and factoring your code to fix it, the more difficult it is to actually fix.

For example, when you say that you're passing many arguments, that's an indication of a poor decision. You should limit the number of arguments to your methods to three or four. Any more than that, you should think about refactoring to reduce number of parameters.  If you fail to refactor right away and keep writing more code on top of that poor design, then the new code will also suffer from more poor decisions you'll be forced to make because of the original poor design. From there it's a vicious cycle.

So, my advice would be to learn how to recognize code smells like Long Parameter List. Know what the negative consequences are of those code smells. Learn how to recognize both the smells and the consequences. Sometimes, the best way to recognize that your design has a smell is when you experience the negative consequences.

As for your specific question, your example doesn't give enough context to make a definitive judgement. It's like asking, "If my friend X went out with my other friend Y, would it be a good thing if they did Z?" As with your example, that statement is simply too vague to say one way or the other.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Andres wrote:For instance, in the subtract method I have these local variables:
...
Should I have just declared them as private instance variables that way I do not have to pass them each time to the other methods? I hope this is clear

Again, you haven't given us enough context to make a proper judgement. Show us the code for that entire subtract() method, maybe we'll have a better idea of how you're using those variables.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
By the way, non-static variables are commonly referred to as instance variables.
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Daniel Andres wrote:For instance, in the subtract method I have these local variables:
...
Should I have just declared them as private instance variables that way I do not have to pass them each time to the other methods? I hope this is clear

Again, you haven't given us enough context to make a proper judgement. Show us the code for that entire subtract() method, maybe we'll have a better idea of how you're using those variables.









I may be missing a few curly braces but the program works just fine.
I hope my program is not poorly designed. But if it please advice me as to how to make it better. There is more code but I simplified it for the purposes of my question
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Andres wrote:I hope my program is not poorly designed.

Unfortunately, it is. I can't make heads or tails of what you're trying to do in that code.

When I see a method declared as

public BigInt subtract(BigInt otherValue)

the most reasonable usage of it would be something like this:

I would NEVER expect any of the underlying calculations for the above operations to involve as many other things and as many extra operations as what you have in that code so I can only wonder, "What in the h*ll is going on there?!!"
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
[/code]
I would NEVER expect any of the underlying calculations for the above operations to involve as many other things and as many extra operations as what you have in that code so I can only wonder, "What in the h*ll is going on there?!!"


It's more elaborate than that. The project calls for the numbers coming in to be stored in an ArrayList. Since some numbers may be + and others -, one array may be bigger than the other or both may be the same it is not that easy to subtract. We need to account for everything since they are in an ArrayList. This program is meant for us to practice. With this in mind, could you tell me why is it poorly designed? That was I can improve.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Andres wrote:With this in mind, could you tell me why is it poorly designed?

I thought I already gave you a pretty good reason: it's not intuitive at all.  How in the world does it make sense to have something named "BigInt", a name that implies a single value, and an action called "subtract" that appears to pertain to two BigInt objects suddenly rope in a bunch of arrays and do a bunch of elaborate calculations? How does this not scream "BAD DESIGN!" to you?

If I gave you a simple calculator and said, "Use this to see what the difference between 5 and 3 is..." and then you tried to use the calculator but found out it needed 5 gallons of gas, 17 batteries, 20 eggs, a loaf of bread, and you running 5 miles in less than 10 minutes before it would give you back the answer of 2, how does that make any sense? That's what your code looks like to me.
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Daniel Andres wrote:With this in mind, could you tell me why is it poorly designed?

I thought I already gave you a pretty good reason: it's not intuitive at all.  How in the world does it make sense to have something named "BigInt", a name that implies a single value, and an action called "subtract" that appears to pertain to two BigInt objects suddenly rope in a bunch of arrays and do a bunch of elaborate calculations? How does this not scream "BAD DESIGN!" to you?

If I gave you a simple calculator and said, "Use this to see what the difference between 5 and 3 is..." and then you tried to use the calculator but found out it needed 5 gallons of gas, 17 batteries, 20 eggs, a loaf of bread, and you running 5 miles in less than 10 minutes before it would give you back the answer of 2, how does that make any sense? That's what your code looks like to me.


Alright. Thanks for the advice
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What do any of those lists have to do with subtracting two integers anyway?
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here's another one: why would there be calls to print arrays in the subtract() method? That's about as surprising as having your printer print out something every time you flushed your toilet.  If I had a method called flushToilet(), it would be pretty surprising for it to make my printer do something as well, right? This is called the Principle of Least Astonishment or Least Surprise. A class and its methods should only do what one might reasonably expect them to do based on what the class and method names explicitly state or normally imply. 
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think you have two big problems you need to address first with this code:

1. Cognitive dissonance created by violating the Principle of Least Astonishment, already discussed

2. Improper assignment of object responsibility - lookup Single Responsibility Principle and GRASP - your BigInt class should only be concerned with operations related to the single integer value each BigInt instance represents. It shouldn't have to know about operations involving those lists of numbers that you're doing whatever else with.  If you had an operation that subtracted a BigInt value from each of the elements of a list and returned another list that held all the results, that's fine. However, if you defined a BigInt method that out of nowhere just reached outside of the current instance and started manipulating lists that had nothing to do with the current integer value, that would be inappropriate. That would be like you going over to your neighbor's house and rearranging the things in his garage without his knowledge or permission.  Also refer to the Law of Demeter to see the kind of things a class/method should be limited to "touching" or "knowing".
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:Here's another one: why would there be calls to print arrays in the subtract() method? 


This class is not finished. As we, the programmers who are not that experienced yet, write code I believe is a common practice to use system.out.println() to debug and make sure things are working out correctly as we work on a project. I print out both arrays because I want to make sure each index does what it's supposed to do as subtraction is happening with each iteration. And those printed arrays let me see which numbers I am working on at the moment. Once the program is complete then I polish it and get rid of all of those sysouts. I said "we" because I think I am not alone in this.

If you had an operation that subtracted a BigInt value from each of the elements of a list and returned another list that held all the results, that's fine.


Yes, this is what is happening in my program. I need to subtract each index from the corresponding index of the other array and then add the result in the variable I declared as sumOfBothArrays to then print out the results as a string. If my code does not express that in its entirety is because I am still learning. We all want to be exceptional programmers! That's why we post on here to get advice from more experience/experts like you and everyone else who helps out.
After all, if I didn't care about how my code looks I wouldn't have posted anything in the first place.

I would NEVER expect any of the underlying calculations for the above operations to involve as many other things and as many extra operations as what you have in that code so I can only wonder, "What in the h*ll is going on there?!!"


Next time I will clearly state what is happening to avoid confusion that way people can help me directly with my problem instead of them asking:  "What in the h*ll is going on there?!!
As always, your answers to many of my posts have been of great help and I always appreciate it. Even if sometimes you throw me a ton of bricks over the head first BTW, the article about code smells is great. Where do you pull out of all these principles from? Are they engraved in your head from decades of studying or do you have a website that have all of these essential techniques to keep in mind as we continue to learn?
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel, I appreciate your candor and patience. I'm not trying to be mean, that's just kind of the way I talk in real life. My wife often has to remind me that it doesn't come across well if people aren't used to the way I talk so I have to keep working on getting better. People I work with don't mind because they know it's not about them but about the code and its quality, plus we always talk about egoless programming; I guess I should have said that up front, too. You probably caught me in a bad mood, too, because I've been trying to get some folks from the academe to listen to some concerns about how students are being taught and I see some of the same issues in the problem you've been given and in your questions. Again, not your fault so sorry for letting those frustrations bleed into my responses to you.

Anyway, here's where you're on the right track: You're creating methods that encapsulate more complicated operations and giving those methods expressive names. You have the right idea when you give names like printValues and determineWhichArrayIsBigger -- these help you keep your code more   abstract and high-level where lots of details would only obscure the code and make your logic more difficult to follow. Keep doing that because that's a very good practice.

As far as debugging, here are a few things about that:

1. Make it clear in your code that statements are for debugging. Separate those lines from the rest of the code so it stands out.

2. Use more expressive names to make those debug statements stand out even more. If you anticipate on using that device for debugging often, create a separate utility class, like a Debug class with static methods so you can write something like this instead:


3. A more preferable method to the above is to use Java's logging system but that's more stuff you have to learn. The time you spend learning how to use logging is worth it though.

4. An even more preferable method is to use automated unit tests instead. This is the way I work. Read up on JUnit and how to use it. Then read up on Test-Driven Development. These are probably still way over your head at this point but keep this in mind. As you get more comfortable with the language, you'll want to start using more powerful tools. It's like moving up to using power tools in a carpentry class.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Andres wrote:I need to subtract each index from the corresponding index of the other array and then add the result in the variable I declared as sumOfBothArrays to then print out the results as a string.

This is why I had so many other questions about the code. Even with this, it's kind of hard to answer your original question about using local versus instance variables. To me, it's kind of like trying to answer a question like "Should I use a #8 or #10 extension wire to toast bread in my swimming pool?" The correct answer to that is always "Don't try to toast bread in your swimming pool."  It's hard for me to look past what's wrong in the rest of the things you're doing in that method so the question of using local variables versus instance variables doesn't even matter if you don't first address the bigger problems with the logic and coherence of the code in the subtract() method.

Where do you pull out of all these principles from? Are they engraved in your head from decades of studying or do you have a website that have all of these essential techniques to keep in mind as we continue to learn?

Yes, and there are many places you can find these techniques discussed and illustrated. But here's the thing: I was taught procedural programming. My first languages were Pascal and BASIC. Very early on, we were taught about functions and procedures so we learned valuable lessons in functional decomposition and program organization. Now, I'm not claiming to have written perfectly organized code right out of the gate but I don't recall ever writing functions that were more than 50 lines of code long.

I was also lucky to have an instructor who had industry experience and for whatever reason, for which I'll be forever grateful, he made us aware of the idea of "elegant code" vs. "kludgy code" very early on. That instructor—thank you, Mr. Herbolingo!—not only gave us a good foundation on which to build, he also made us aware that there is such a thing as "good" vs. "bad" code. So I guess from the start, I've always been looking for ways to write good code.

Here are a couple of principles I think a programmer at any level can start with:

1. Clarity/Expressiveness: Make your code clear and expressive. Express your intent, hide the details. Make your code say what it does and do what it says.

2. Simplicity: Make your code as simple as it can be. Another way to look at this is to think small: small classes and small methods.

Here's one of my favorite quotes about simplicity:
C.A.R. Hoare wrote:There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here's another problem solving technique to be aware of: Asking Five Whys

It might not be useful to apply the technique as it is normally prescribed to be applied but it's worth going back the principle behind it which is about digging deeper and looking for the real problem you want to address. Here, that principle leads to asking more questions beyond just "Should I use local variables vs. instance variables" to see whether that's really the issue you need to address. This is really what led me to ask about all that other stuff. 

Based on the information you've given so far, it seems to me that what you really want to do is much more than just what can be clearly and accurately expressed by a method like subtract().  I'd suggest that perhaps you should try something like subtractLists(List first, List second) as an initial expression of intent and see where that leads you instead.
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
At least now I know this is how you talk in real life. It'll be easier in future posts since I'll know your responses would be about the code and nothing personal.
plus we always talk about egoless programming; I guess I should have said that up front, too.


I actually saw this in another post. I think Campbell posted something about the 10 commandments of egoless programming. It's true! Number 1 rule should be that we need to never take it personal. If there is criticism then there is room for improvement. I have not read about JUnit and and Test-Driven Development but I'll definitely get there.
The professors I've had so far have been great but unfortunately they care more about whether it compiles and works rather than elegance. This is not to say they will ignore code that looks like gibberish but no professor has even said to me the importance of refactoring, code smells, or what it really means to be more expressive and intuitive. My current professor does heavily suggest that our variables and methods always have meaning and that they do what they say they do. I always try to emulate that.

2. Simplicity: Make your code as simple as it can be. Another way to look at this is to think small: small classes and small methods. 


I am currently revamping my entire BigInt class because of the long parameters, I am changing the names of my methods from thisArrayBiggerDifferentSigns to differenceOfBothArrays for example regardless of whether one is bigger than the other one. I've found a better way of dealing with that by using a temporary ArrayList in the same method that swaps the arrays in case the passing object is bigger than the this.object. I hope I'm explaining this correctly but now my code looks cleaner so far with significantly less lines of code. The only thing I'm struggling with is reducing the lines from the method I posted above called sameSizeArraysDifferentSigns (whose name I'm also changing) and a few similar ones that do different computations. Because there is a lot going on when adding or subtracting big numbers, including checking to see whether we need to add or subtract one from a previous digit, I think in this case is ok for a method to be this long. Is it not?

Based on the information you've given so far, it seems to me that what you really want to do is much more than just what can be clearly and accurately expressed by a method like subtract().  I'd suggest that perhaps you should try something like subtractLists(List first, List second) as an initial expression of intent and see where that leads you instead.


Our Professor wants us to call the class BigInt and the methods add and subtract, that's the problem.

So within my subtract method I can then name other methods appropriately such as subtractLists.
 
Daniel Andres
Ranch Hand
Posts: 94
3
AngularJS C++ Chrome Eclipse IDE Oracle Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Actually the swapping of arrays happen in a control statement before I call the method, that way the method only does the subtraction.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Andres wrote:At least now I know this is how you talk in real life. It'll be easier in future posts since I'll know your responses would be about the code and nothing personal.

I'm glad we got that smoothed over. Sorry again if it sounded like I was going off on you rather than at the code. It's natural for people to attach themselves to the code they write so any criticism of the code tends to get taken personally. Not the first time I've had to remind myself to ease up and chill out.

no professor has even said to me the importance of refactoring, code smells, or what it really means to be more expressive and intuitive.

Yeah, I wish there were more who would.

My current professor does heavily suggest that our variables and methods always have meaning and that they do what they say they do. I always try to emulate that.

That's good. Keep at it and make core to your practice.

I think in this case is ok for a method to be this long. Is it not?

It takes a while to get a hang of writing small methods. You need to recognize when certain ideas can be separated from each other and then know how to tease things apart. I used to think that a method with 20 lines of code was pretty small. In time, 15 lines of code in a method would bug me and I'd try to find ways to cut it down to less than 10 lines. Most of the methods I write nowadays have been refactored down to 1 to 8 lines of code. So it's a process and "long" is relative to what you can juggle in your head comfortably without having to scratch and look a little confused. I guess as I get older and gain more experience with refactoring, it takes a lot less to confuse me now than it did before, so the smaller I can make my methods, the better for my sanity.
 
Junilu Lacar
Sheriff
Posts: 11493
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One of my favorite examples of refactoring code to clarify its intent is the one for the Compose Method refactoring.

This article explains the details and motivations quite nicely: http://codebetter.com/jeremymiller/2006/12/03/composed-method-pattern/

There's no substitute for doing it yourself though. Start with the "before" code and walk yourself through the thought process and steps for slowly and systematically refactoring it into the "after" code.

Do the exercise multiple times to really drill the principles behind making the changes into your head. Don't just do it mechanically but also practice talking yourself through the process; I think you'll find it more beneficial.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!