• 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
  • Liutauras Vilda
  • Junilu Lacar
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Knute Snortum
  • Devaka Cooray
  • Tim Cooke
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Ron McLeod
  • Carey Brown
Bartenders:
  • Paweł Baczyński
  • Piet Souris
  • Vijitha Kumara

Distributed Reservation Management System (DRMS) using Java RMI

 
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tushar Goel wrote:

Why is the method (line 18) called registerMyself?


I was thinking that library itself not registered any student. In real time Student request librarian or whatever admin is that s/he wanted to open an account.
On receiving such request account is opened. So yes library.registerMyself() is wrong, i suppose it should be student.registerMyselfToLibrary() but
whatever you are saying is also looking correct as library is only one who will create an account. I am confused here. Please guide.


Anthropomorphism (giving human characteristics to non-human things) is a useful device when doing Object-Oriented Programming but you have to be careful to do it from the proper perspective. Another way to look at it is as abstractions. OOP is really about assigning behaviors and responsibilities to the appropriate abstraction.

Right now, the idea is to have a "Library" abstraction. Its responsibility is to register Students so that they can use other services of the Library. So it makes sense to me to "say" to a Library, "Hey, Library, please register this Student (tushar) so that he can start availing himself of your services."

Translating that to code, you have a Library.register(Student) method. See how that works? Library is the "thing" you're talking to, and "register" is the command that it responds to. "This Student, tushar" is the parameter that you give to the Library so it can carry out the register command. If some other Student comes along who needs to register, you again "talk" to the Library and tell him, "Hey, Library, register this Student, Bob, so he can start borrowing books from you." As code, that would be

See how we extended the "conversation" with Library? We gave Library a responsibility/behavior of responding to the question, "Is this student registered with you?" via the boolean method Library.isRegistered(Student).

You have to pretend that you're talking to these things and telling them to do things. That's why method calls are also referred to in some older literature as "messages". Calling a method of an object is also referred to as "sending the object a message." The parameters passed in to a method is the information related to that specific request for the object to do something. The problem with student.registerMyselfToLibrary() is that it doesn't translate to a conversation like the above.

In the case of student.registerMyselfToLibrary(), it's as if I were talking to a Student, the object that we're sending a message to, and saying "Hey, Student, register myself to Library." If this were an actual sentient thing we were talking to, I can only imagine the kind of confusion it would be experiencing when you say something like that to it. First of all, the "Student" would say "huh, who is this 'myself' thing?" And then it might say, "Uhmm, and what do you mean by 'toLibrary'? What is this 'Library' of which you speak?" That's because you never gave it anything to work with: there are no parameters sent along with that message. All the information needed ("myself" and "Library") was conveyed in the message name itself. But that doesn't work as code. You have the wrong perspective.

That's why I said that your story doesn't make a lot of sense.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tushar Goel wrote:

Let the code guide you into what you should do next.


I suppose it required lot of practise and patience. Thanks again.


Yes, a lot of practice and perseverance. I read a lot of other people's code, too, and that helped me a lot. Reading both experienced and inexperienced people's code helps you see contrasts in how things are and can be done. I also compared my code with other people's code and started getting a feel for what worked better. There's a mindset that you need to adopt, a certain mode of thinking that helps. I think it can be taught but only with lots of examples and you have to get people to actually do it.

I practice martial arts and I think this is very much like learning a technique in martial arts. I can show people where a pressure point is and how to apply a technique to hit that specific pressure point but every person has to actually practice the technique and get many repetitions before they can make use of that knowledge. Most of all, they have to feel the technique being applied to them. They need to experience what it's like to be on the receiving end of the technique before they can effectively apply it on others.

Luckily, I practice Aikido and while the techniques we practice can be extremely painful for the one receiving it (some people need a LOT of convincing ) but only to the point where conflict can be controlled and settled. In Aikido, the aim is to resolve conflict without causing permanent harm to anyone, even the "bad" guy.
 
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Junilu for excellent explanation. I got it now, problem was with the conversation. You gave very good example related to the message flow.

I have corrected the package name and Test method now. Also please suggest if my test method names are ok?






User story: Student registration

To do list now:

1) test to register a Student
2) test to check a student is registered without registering a student
3) test null value in isRgisteredMethod
4) test null value in register method
5) test null value in student information
6) test zero size in student information
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Now working on todo list point: test to check a student is registered without registering a student




The test fails as isRegistered() is always returning true. So it gives me thought to add student in some collection and check if the user is not registered or not
from that collection. By doing this my 2nd Test passed but first test failed. So i need to add collection.add() into that to make a test pass. So finally it comes:


 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Do you think that

IsRegistered_CheckStudentRegistration_ReturnFalseIfStudentIsNotRegistered

is a better name than something like

isRegistered_should_be_true_after_successful_registration

?

Which one conveys a more coherent thought? Which one is more conversational? I try to come up with test names that read like a summary of a behavior I want to describe. I want to convey the intent. Your test name, to me, looks like a shorthand describing what's happening in the the test but it doesn't reveal the intent of the test very clearly. Of course I may just be biased but I have done a lot of code reviews and I know that I can always accept names given by other people when they make sense to me. Yours is one of those names where I would have to ask "What is the intent of this test? Can we find a name that more clearly summarizes that intent rather than try to explain what it's doing and how it's doing it?"

Note the way I choose when to capitalize words in my test names. If I refer to an actual method, I will use the same capitalization for that method name as in the production code. Otherwise, I use all lowercase and underscores. I find this more readable. It's a style that I adapted from author, speaker, and Thoughtworker, Neal Ford.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think the key to writing more readable programs is choosing good names and using those names along with the constructs available in the programming language in a way that makes the code more conversational rather than this terse, cold, mechanical style that I often see in other developer's code. My biggest peeve are abbreviations and dropping all vowels in words. There is no call for that in languages like Java. Of the two snippets below, which one is more readable:

See how the variable name searching flows with the while statement to make for a very conversational style? The first snippet is something that I see way too often though and it drives me nuts!
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Junilu, i have updated my test cases with the suggested name. Actually i took this name pratice from one of the video i was watching.

 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You are right.. Second one is more readable. By giving the proper name we could make our life during development or maintenance lot more easier.

I can understand the pain. I am facing the same challenge in the project i am working on in my office. The code is written some 10 years back in Java 1.4 and by some
C guys. Each method is like 2000 to 3000 lines or more. They have used name like you used in scenario 1st and no comments at all. I spent most of the time to
understand them and when i understand it and thought it should work this way but surprisingly the result always different.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Can i move ahead to next item in todo list if above 2 test cases is correct?

Current Todo list items


1) test to register a Student
2) test to check a student is registered without registering a student
3) test null value in isRgisteredMethod
4) test null value in register method

I have removed null and zero length check items because i thought that's Student class responsibility.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Where is your production code?

Edit: OK I see it. You misspelled "registeredStudents"
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Oops sorry. So other things are ok? Should i moved to next item?
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sure, move on whenever you're ready. Try to keep your goals high-level though. Yes, you'll have low-level things in your todo list like checks for null and such but also have things like:

1. Should be able to see how many students are registered
2. Should be able to check if a book is available
3. Should be able to reserve a book if it's not available
4. Should be able to see how many people have a book reserved ahead of me

These say nothing about implementation details like which class or what method or null or zero -- which are all implementation level details. These are the high-level descriptions of what you can do with the system. These are what guide you in making overall design decisions.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Junilu, I am super excited for moving ahead but i control my feelings to avoid any mistakes and waiting for getting a go ahead with my partner(You).

For the high level things, i thought i need to maintain ToDo list for each story point not an overall list. That's why i removed some of the earlier points
discussed from the current ToDo list. Thanks for the correction.

I will code some of the points and paste it. Also could you please tell me if we follow TDD then how we implement design patterns? Is it required?
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My approach to patterns is this:

Familiarize yourself with patterns, the motivations to use them, and the contexts in which they are properly applied. This is what is most important about patterns.

Start learning how to recognize the PROBLEMs to which patterns are best applied. If you are familiar with the general context in which a pattern is applied, there are many different kinds of problems that they can be applied to. Different problems may have similar contexts but specifics of their solutions will vary, sometimes the specifics can vary greatly.

Learn how to refactor. Again, this requires you to learn how to detect problems in the code and in the design.

When you have this broad-based "sensitivity" then you can effectively apply patterns. A pattern is not one specific solution. A pattern is a general "template" for a class of solutions to a class of problems. That's why it's called a PATTERN and not simply a SOLUTION.

Bottom line is, I don't go around with a pattern in mind and look for a problem to apply it to. I keep my eye out for problems, learn to recognize them, and then dig around in my brain to see if there's a known pattern that can help me figure out a solution to the problem.

When you're doing TDD, you are always looking for problems because refactoring and design thinking are intrinsic to the technique and you are doing it all the time. So, the likelihood of you being able to apply one pattern or another is very high, as long as you have that broad-based knowledge and familiarity of patterns.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Let me give another analogy, based on architecture, from which the idea of design patterns came (See Christopher Alexander and Patterns).

There's an area in Miami called the Art Deco District. It is named after the style of buildings in that area. Each building is unique in its own way and no two building are exactly alike but they are all built in the same style: Art Deco. The "pattern" name is Art Deco. You might hear of people refer to their houses as "Colonial Style" or "Victorian Style" or whatever. The "style" is the pattern name. When someone says to you, "The building was built in the Art Deco style," you can immediately get a general idea of what it will look like even though you've never seen it. This is another thing that patterns give you: a way to communicate an idea about general characteristics of something without having to see the specifics. In patterns parlance, it's called a "Pattern Language".

So that's why I say that it's the generalities about a pattern that you need to be familiar with and not so much the specifics.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So that means we need to have a knowledge of the most of the patterns available if not all before applying them. Because then only we can figured it out
which will be best to apply in a particular problem.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't know all the patterns. I know the ones I've used before. It doesn't take much to familiarize yourself with them -- even if you don't have intimate knowledge of them as long as you understand what they are generally about you should be fine. That's why collaborative work is more effective than solo work. If you don't know a pattern but you're working with someone who has a different background, then they may know other patterns that they can relate to a problem. I have been encouraging mob programming on my teams more and more just because the diversity of experience gives us a deeper and richer well from which to draw out possible solutions.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You can start from a very high level: the categories of patterns. These include (but probably not limited to): Behavioral, Creational, Structural.

I tend to focus on Behavioral patterns because, as I said before, OO is about behaviors and responsibilities. Command, Chain of Responsibility, Strategy, Template, Visitor, Observer, Null Object, etc.

But I use the Creational ones too: Factory, Factory Method, Builder, Prototype, etc.

And of course the Structural patterns that I use the most: Facade, Adapter, Bridge, Composite, Decorator

I always have to look around for specific solution examples but when I see bad code, I always seem to be able to recognize an appropriate pattern just from my knowledge of the contexts, motivations, and kinds of problems that are related to the patterns that I know. In other words, I know the principles for applying them even though I won't have a specific solution right off the top of my head. That's what makes it fun because then you use your creativity to figure out the specific solution based on the pattern.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Agree we need to the know problem context then we have to figured it out which patterns is more connected to this context and used then. I am reading
Head First Design pattern book as well to get familiarity. Thanks sir..

Meantime i have added some of the test cases as well. During these tests i thought i have to instantiate library again and again and also needs to
type register method several times so i did little bit re-factoring too.



Production code:
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's cool. I might try to find a more concise name for totalNumberOfRegisteredUsers(); that's a bit of a mouthful. How about userCount() maybe? Do we really need to qualify users as "registered"? As opposed to what, "unregistered"? Do we really consider anyone who isn't registered as a User?
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Oh yeah.. Users in a library are always registered.. No un-registered user is allowed. So it doesn't make any sense to mention that. Will correct it and move to next item.


 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Good afternoon. I worked on next items "Should be able to add book" and "Should be able to return book count"








 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You should rename the test isBookAvailable_should_able_to_add_book - what that says does not make sense and it's not reflective of what the test actually does.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You are right. I was confused when i added that. I suppose i should remove this test as i already have another test with same functionality,
"isBookAvailable_should_return_true_when_book_available()". Also is it ok to use such names "booksCount_should_return_3_when_3_books_added()"?
I was thinking isn't i am telling about the implementation details?
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Those kinds of tests are fine. That particular one is redundant with the return_2_when_2 test though. You only need one of these two tests. The one with 0 books is good; that's a corner case. Try to think of more corner cases.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Junilu, i am struck in one of the case "Should return the students details which have not returned book after x days overdue". This work should be
done by the Administrator.

So the test case is like:



then assert the count with the number of defaulters. Is it correct?
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Actually, you are going too deeply into implementation details there. You have to keep pulling yourself up from those depths of thinking when you're designing and try to keep to a high-level view. This takes a lot of effort and discipline to learn so don't get discouraged. Just remember that when you find yourself stuck and ask yourself the question, "Is there a higher level view that I can take instead? Can I back off further and deal with simpler abstractions?" Only go back down to implementation detail level when you have a clear idea of what the high-level story is.

With the story, I would state it as "As a librarian, I want to see which students have overdue books so I can start contacting them to ask them to return the books."

Then, I would say "Ok, let's set up one student who has borrowed one book that is overdue by 1 day" This would lead me to put on my TODO list:

* corner case: book is going to be overdue tomorrow
* corner case: book is going to be overdue for 1 year tomorrow.

I'll leave it to you to understand why I think that second corner case is significant. It has to do with possible implementations of due date calculations.

Going back to the main scenario, here's how I would expect the test to be structured:
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
With that high-level scenario, I can then start exploring implementation-related test cases:
* Try when book is borrowed close to the end of the month and becomes overdue close to the beginning of the month
* Try when book is due on Feb 29 (is this an actual corner case?)
* Try when book is due on the 1st of the month
* Try when book is due at the end of the month
* Try when book was borrowed last year
* Try when ... whatever else interesting case you can think of

This is when you can benefit from another person's perspective. On my team, we develop code like this as a group or as pairs. That way, different people can suggest other scenarios that you might miss. Ideally, at certain points throughout you'd also collaborate with someone who hasn't been involved with the implementation and can see things from a "disinterested third party" point of view.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Then you might realize that these tests are NOT really about the Delinquent Students list but rather about the Overdue Books calculations. So you might decide to move these to a test class of their own.

It's all about clarifying the intent of the tests and production code and organizing ideas into related groups of things.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Junilu. It is excellent idea.

corner case: book is going to be overdue for 1 year tomorrow.


I got it. Say if i reserved a book which having a due date on 31st December and if we don't return it then in next day is 1 Jan which make a a year's difference but
practically difference is only for 1 day. So we need to take care of this as well so that user should charged for 1 day only not a year.

On my team, we develop code like this as a group or as pairs.


I am missing this things. That's why in 2-3 months down the line i am planning to change it.

So you might decide to move these to a test class of their own.


So should we consider to make a separate production code class as well in such cases. I know i am thinking about implementation detail which may be wrong.


I will figured it out more. Its dinner time now.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tushar Goel wrote:

So you might decide to move these to a test class of their own.


So should we consider to make a separate production code class as well in such cases. I know i am thinking about implementation detail which may be wrong.


Not necessarily. There's no "rule" that says there needs to be a one-to-one relationship between test classes and production classes. Like I said, it's about organizing ideas and grouping related things together. A set of tests are focused on some aspect, say overdue calculation, so they can be separated out into one unit. Another set of tests are focused on registration, so they have their own unit. Both sets of tests can still be using the Library. So you'd have LibraryRegistrationTest and LibraryOverdueCalculationTest. Then again, if some of those test names don't make sense, then you have to consider maybe separating the functionality out to a different class.

You just have to be sensitive to "smells" and let the code guide you to the right thing to do. If you can't detect a problem, then you'll just merrily go along, oblivious to dangers until you really start getting stuck. The downside to that is that you need to get stuck a few times before you start developing that sensitivity. It's all part of the learning process. In sports, that's what they call "reps" (repetitions).

There's a quote that goes: "Experience is what allows you to recognize mistakes when you make them again."
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tushar Goel wrote:

corner case: book is going to be overdue for 1 year tomorrow.


I got it. Say if i reserved a book which having a due date on 31st December and if we don't return it then in next day is 1 Jan which make a a year's difference but
practically difference is only for 1 day. So we need to take care of this as well so that user should charged for 1 day only not a year.


Not quite what I had in mind but that's another possible corner case to consider. All these are just guarding against naive implementations of the calculation. Say I did a naive calculation based only the month and day. So a book was due to be returned on March 30, 2014 but today is March 29, 2015. A naive calculation might see that today, March 29, is before March 30 and will incorrectly see the book as only being due tomorrow when in fact, it has already been overdue for a year.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Good evening Junilu. I have added some cases for story points "To check the number of copies reserved by others ahead me" and "Number of copies available now"






I am working on the Test case to list overdue students.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For calculating the period, how about converting a date into long. Date having getTime() which returns millisec from 1970. So if we say
issuedTime in milli-sec since 1970 + milli sec in book refund duration (days * hours * minutes * seconds * milli-sec) < currentTime in milli-sec since 1970

Then we say the book is overdue and difference between them tells the overdue duration. It will include all scenarios. Isn't?

Something like this:




Production code:


 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tushar,

I think you have the general idea by now. There is probably always going to be something in your code that I can nitpick on, some maybe more significant than others. I would advise you to read up on the books that I recommend in this thread: https://coderanch.com/t/647934/patterns/Learning-OO-Patterns-UML to expand your horizons about design.

The only thing that remains is to Practice, Practice, Practice.

Good luck.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, a few last tips before I let you go off on your own

At some point, you should smell that the Library class is getting very big and has way too many responsibilities. You will probably want to divide it up into different sections or modules, like Registration, Circulation, Reservations, Acquisition, etc. Try to use the language of the domain. Notice that those names I just gave are the names of different sections/departments at most libraries.

Don't preempt the refactoring into these modules though. Try to see if you can keep going until you feel the kind of pain involved with having a Library class that has too many responsibilities. This is the best way to sensitize yourself to that design smell. Then try to refactor it.

Always keep an eye out for poorly chosen names. In your overdueStudents() method, the variable on line 32 is overdueStudent but its type is a list. A list is a collection of things so the variable name should be plural, not singular. This may seem like a little thing but it can make a big difference to the reader, even if he unconsciously makes the necessary translation in his head. Keep the code grammatically correct and conversational; this makes it more readable. Avoid abbreviations and shortcuts as much as possible.

Try to keep your methods to 10 lines of code or fewer. I find that I'm getting closer to averaging between 5 and 10 lines of code in my methods now. I've been doing TDD for quite a while now though and getting to this point has taken me a few years. Most of Kent Beck's code is supposedly made up of methods with 5 lines of code or less. I've heard it said that Beck writes a lot of one-liner methods just so he can hide some kind of detailed calculation behind an expressive name. That's the kind of expressiveness I aspire to have in my code.

Also, start getting offended by code that looks like lines 36 to line 42. That code is messy - it hides its intent.

Java 8 can make this very expressive:

Remember: it's mostly about properly assigning responsibilities and behaviors. The other important aspect to good design is keeping dependencies loose and to a minimum and hiding as much implementation detail as possible. Oh, and read up about leaky abstractions, you want to avoid those if you can.

Good luck.

 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This shows just how obsessive I have become about semantics.


This will return a list that possibly has duplicates because a Student can have multiple overdue books. Next refactoring would be to return a Set instead:

Eventually you'll want to think about optimizing the search. Is it right to filter all books? Is there a better starting point?

It's all good -- the endless possibilities is what makes it challenging and fun.
 
Junilu Lacar
Marshal
Posts: 14351
238
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Arrrgh! Do you smell that design flaw? Why would a Book be responsible for knowing if it was overdue or not?

Seems like there needs to be a Checkout(Book, Student) object. This would be your starting point. For all checkouts, see which ones are past the allowed checkout period, then collect all the students into a set. Or you could stick with a List and group the results by Checkout::getStudent and print out a list of students with the books each of them has overdue.

So many possibilities.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I suppose "Thanks" is very small word to express the all the help and knowledge you have shared with me. Please accept my sincere thanks as a token of respect for
all your help and guidance. If possible i would love to buy a beer for you if we met any-time.

I will definitely follow all your advice and implement them in my day to day activity to improve myself.
 
Tushar Goel
Ranch Hand
Posts: 952
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Whatever knowledge (small though) i have today is result of support of Yours, Campbell, Winston, Tim and other Java ranchers. Thanks all of you again.
 
I like tacos! And this tiny ad:
Java file APIs (DOC, XLS, PDF, and many more)
https://products.aspose.com/total/java
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!