Inner vs. Outer Join

Here is a really good visual explanation of different types of SQL joins. I was recently asked what the difference was, and while I knew the answer, I fumbled to articulate it. I should have simply said “An inner joint results in a subset or overlap of results and an outer join results in a union of results from two or more tables.” (i.e., outer joins return records for the left side even if nothing exists for the right side.)

[Coding Horror: A Visual Explanation of SQL Joins]

10 programming languages that could shake up IT – JavaWorld

10 programming languages that could shake up IT – JavaWorld.

Apache Commons Configuration with JBoss 5

Here’s a problem that frustrated me for a bit: When using Apache Commons Configuration under JBoss 5, I kept running into the following error when attempting to save to my configuration file (which was a resource under the deployed /classes path):

ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/xxxx].[xxxx]] (http-0.0.0.0-8080-1) Servlet.service() for servlet flint threw exception
java.net.UnknownServiceException: protocol doesn't support output
at java.net.URLConnection.getOutputStream(URLConnection.java:792)
at org.apache.commons.configuration.AbstractFileConfiguration.save
(AbstractFileConfiguration.java:449)

What the heck? This error happened every time I attempted to save to my configuration file. It worked fine in Tomcat 6.x, but any time I tested on JBoss, while I could read from the configuration file, the above error was thrown every time I attempted to write to it.

JBoss 5.x VFS (virtual file abstraction) for the files that it deploys, and this causes problems with Commons Config’s default FileChangedReloadingStrategy. So the fix is to do something like this instead:

VFSFileChangedReloadingStrategy f = VFSFileChangedReloadingStrategy();
((FileConfiguration) config).setReloadingStrategy(f);

It turns out that we really want to use VFSFileChangedReloadingStrategy (which means using Apache Commons Config 1.7) . This also requires that the Apache Commons VFS API be on your classpath. The good news is that VFSFileChangedReloadingStrategy works well even with non-VFS deployments (i.e. plain old Tomcat and Jetty). Problem solved!

Scala in 2012

JavaWorld.com: Scala for 2012? Deciding Whether to Invest In a Programming Language

Programming Trends to Watch

This was an interesting article:

[JavaWorld: 11 Programming Trends to Watch]

Appropriate Checkin Comments

I read this post today with a list of funny checkin comments today. Some of them are funny simply because of the lacking description. Here are some comments I’ve seen in my personal experience:

  • many small changes
  • Microsoft IE sucks!
  • cleanup
  • oops
  • fix the bug

Worse, I’ve seen entirely empty changeset comments.

The above lists, along with those found on the funny checkin comments page provide some examples of inappropriate commit comments. Why? They are unprofessional and lacking in detail and meaning. Some projects are audited and reviewed by external third parties. As a project manager or architect, would you be embarrassed for  an auditor to see the comment “fix sucky code?” I would. Even worse than being embarrassed, there is a productivity problem that can arise from poor checkin comments.

What is an appropriate comment? An appropriate comment must (minimally) have a few things:

1. Appropriate level of detail about the change, including why the change was made, what impact there may be, etc.
2. Appropriate to the changeset. Along with this, a single changeset should, as much as possible, reflect a single ticket or change. Many lazy developers check in a large set of code with a number of intertwined changes that are unrelated. When it comes time to revert a particular change or track a defect this creates problems, and ultimately it defeats one major purpose of version control.
3. Details about the completeness of the change. Generally a changeset should complete a ticket or work item, but this is not always the case. If there is remaining work to be done, “TODO” items or further functional requirements that impact the changeset, this should be noted.
4. Finally, perhaps the most important part, the checkin comment should refer to a ticket. Not all changesets have tickets written, sure, but in general, if the ticket is a defect, enhancement or requirement implementation, there should be one or more tickets that are related. Any modern version control and ticket system will be able to tie these together.

One developer writes:

Many developers are sloppy about commenting their changes, and some may feel that commit messages are not needed. Either they consider the changes trivial, or they argue that you can just inspect the revision history to see what was changed. However, the revision history only shows what was actually changed, not what the programmer intended to do, or why the change was made. This can be even more problematic when people don’t do fine-grained commits, but rather submit a week’s worth of changes to multiple modules in one large pile. With a fine-grained revision history, comments can be useful to distinguish trivial from non-trivial changes in the repository. In my opinion, if the changes you made are not important enough to comment on, they probably are not worth committing either.

Getting developers to write good checkin comments seems to be an ongoing battle. In the business of writing software, its easy to convince oneself that checkin comments are a waste of time. The real waste of time is later, when trying to track the introduction of a defect or trace requirement implementation to code. There is simply no good excuse for lacking checkin comments.

Is the checkin comment “cleanup” appropriate? Yes, in some cases, as long as its true. If I am cleaning up formatting of code, including things like indents and spacing and correcting whitespace, then yes, “cleanup” is an appropriate changeset comment. Generally, however, real comments are required.

[Vistamix: The Humor of Code Checkin Comments]
[Loop Label: Best Practices for Version Control]

What Every *GOOD* Developer Should Know: Quality Assurance

I’m currently reading “The Clean Coder,” and Robert Martin puts emphasis on the importance of software engineers incorporating QA practices into their regular work much better than I can. Here are a few quotes of his on the subject:

“Software is too complex to create without bugs. Unfortunately that doesn’t let you off the hook. The human body is too complex to understand in its entirety, but doctors still take an oath to do no harm. If they don’t take themselves off a hook like that, how can we?”

“Some folks use QA as the bug catchers. They send them code that they haven’t thoroughly checked. They depend on QA to find the bugs and report them back to the developers.  Indeed, some companies reward QA based on the number of bugs they find. The more bugs, the greater the reward.”

“…So automate your tests. Write unit tests that you can execute on a moment’s notice, and run those tests as often as you can.”

I am really enjoying this book. Its a fun and easy ready.

[Amazon: The Clean Coder]

What Every *Good* Developer Should Know

I came across this guy’s blog post titled “10 Things Every Good Web Developer Should Know.” The post is geared toward web developers, but it did get me thinking a bit about the more general questions. I’ve noticed shortcomings among developers (myself included) for a many years. What are some of the things that all GOOD developers SHOULD be expected to know? This list is hardly comprehensive, but I can think of a few things right away:

1. Linux/Unix

If you can’t do basic editing in vi you may find yourself in for a world of hurt at some point. I’ve known many programmers who attempt to write software in the safety of their IDE running on Windows only to find severe problems when it comes time to deploy on the server (and the server is typically some flavor of Linux). I recall a fellow software engineering student in my college days saying of his code, “It all works, it just won’t compile!” It sounds silly, right? Assuming software that is written, build and deployed in Windows will built and deploy just fine in another OS is equally as silly (yes, this goes for Java as well).

2. How to debug

Duh, right? Not so. I have helped many, many engineers with basic debugging. I don’t know if it is that I am particularly good at debugging (I’d like to think so), or that (some) others are particularly poor at it, but for most of my career I’ve heard, “Matt, this isn’t working, can you help?”

Generally this question is asked by an engineer who has spend a fair amount of time staring at the screen hoping to gain some diving inspiration and fix a bug. It never works this way. You have to be willing to dig into the code and actually find where the error is. Look through that stack trace! Run the debugger! When all else fails, start sticking print lines all over your code! Staring at the screen will rarely reveal a complex bug. A compile error, sure, but a bug, no.

3. Basic knowledge of C/C++ and or Assembly

In the day of virtual machines, powerful IDEs, scripted languages, OOAD and encapsulation on top of encapsulation on top of encapsulation, it can be too easy to write code and never understand exactly how much stuff has to happen for that code to work its magic. I have not written anything in assembly since college, and I have not written C code for 10 years, but I rely on my knowledge of the low-level “stuff” every time I write code. It helps to understand fundamentals of computer science, optimization, memory handling and what exactly makes all the magic of a 4GL come together. Many people get by without knowledge of assembly language, sure, but these people will not be “superstar” engineers… They’ll be programmers.

4. Version Control

There’s no excuse for not using version control. I would say it borders on negligent not to.

5. HTML, CSS, Javascript
This one may seem like another no-brainer, but I have run into many developers over the course of my career who simply do not have anything more than the most basic understanding of HTML.

6. System Administration

Just the other day sendmail quit working for me. I use sendmail to alert the team about project activity in Redmine, Subversion and Jenkins CI. I run project management software that is served using Ruby and Rails, Apache and Tomcat. I have written perl scripts for handling batch jobs and specialized email alerts. I have written bash scripts that tie in to various subversion triggers. I have installed Ant, Maven, Git, Subversion, Tomcat, Apache, GTK, GCC… You name it… All with NO help from a Linux administrator. Like it or not, these activities become the responsibility of the lead software engineer. If you embrace it and enjoy it, life will be easy. If you are lost, and waiting for the help of a system administrator, you may be in for a very long wait!

7. Database Design

EVERY good programmer MUST understand things likes normalization, joins, foreign keys, natural keys, sequences, race conditions, locking, and on and on. We cannot rely on a database designer. Even the largest companies I have worked for have, the ones with database administrators, have little if anything to say about database design. Database design is the responsibility of the software engineer. A poor design can cripple what may otherwise be good software.

8. Quality Assurance

Our goal as engineers it to deliver a high quality product with no defects. We all know that there will be defects, but this fact does not change the goal.

9. Communication, Documentation, Technical Writing

Even if your company does have the means to hire a dedicated technical writer, that employee will have no idea what your code is doing. Strong documentation is on the engineer (us). I never had to take a technical writing class in college. Fortunately, writing is something I enjoy. For the engineer who hopes to never have to write a document, he or she is likely to be very annoyed in this career.

The Clean Coder

The Clean Coder

http://www.amazon.com/Clean-Coder-Conduct-Professional-Programmers/dp/0137081073/ref=sr_1_1?ie=UTF8&qid=1320525011&sr=8-1

I’m reading a book right now titled The Clean Coder. Here’s a quote from chapter 1:

Your career is your responsibility. It is not your employer’s responsibility to make sure you are marketable. It is not your employer’s responsibility to train you, or to send you to conferences, or to buy you books. These things are your responsibility. Woe to the software engineer who entrusts his career to his employer.
-Robert C. Martin, The Clean Coder

[Amazon: The Clean Coder]

Initializing Persisted Collections (JPA/Hibernate)

Here’s a good question/answer that I came across today over at Stackoverflow. The answer is that it NOT a good idea to set a collection inside of a getter or setter method because:

I would strongly discourage lazy initialization for properties in an ORM entity.

We had a serious issue when doing lazy initialization of an entity property using Hibernate, so I would strongly discourage it. The problem we saw was manifest by a save taking place when we were issuing a search request. This is because when the object was loaded the property was null, but when the getter was called it would return the lazy initialized object so hibernate (rightly) considered the object dirty and would save it before issuing the search.

I’ve been burned by this as well.

[Stackoverflow: Is it good practice to initialize fields inside a JPA entity getter?]

Best Software Developers

From Kawseq Consulting:

An average developer can produce software 10 times as fast as the worst developers. The best software developers can produce software 10 times as fast as average developers. That means the best software developers can produce software as much as 100 times as fast as the worst developers.

1. Hiring cheaper developers actually costs much more up front than hiring the best developers, because you have to hire many more of the cheaper developers to get the same job done.

2. Hiring cheaper developers actually costs more later because you have to spend a lot more developer time fixing the higher number of bugs they put in.

3. Hiring cheaper developers means waiting longer to get working software because of the additional build-test-fix cycles to fix the larger number of bugs.

No matter how much time you give them or how many you throw at a project, cheaper sotware developers cannot produce code of the same quality as high quality software developers. You cannot expect a large number of cheaper software developers to produce a high quality result, just as you would not expect to hire 10 house painters and get them to produce the Mona Lisa. The lower quality produced by large teams of average or poor software developers inevitably leads to software that is more expensive to maintain and develop down the track.

That last bit hits the nail on the head!

Also, cheaper developers do not necessarily supplement more experienced and qualified developers. It just means that the better software developer has to rewrite the mistakes made by the less skilled team members.

Kawseq Consulting: Why Quality is More Important Than Price

JBoss Deployment Gotchas

The other day I was attempting to deploy a web app in JBoss (5.1) that had deployed just fine in Tomcat. In JBoss I kept seeing the following error:

java.lang.ClassCastException: org.hibernate.ejb.HibernatePersistence cannot be cast to javax.persistence.spi.PersistenceProvider

It turns out that the problem was because JBoss was first loading its own Hibernate classes. When my application started to deploy there was a Hibernate jar conflict (my Hibernate version was newer than that which JBoss shipped with).

To solve this problem is is necessary to direct JBoss to load class files for the application first. To achieve this, create the following jboss-classloading.xml file in WEB-INF:

<classloading xmlns="urn:jboss:classloading:1.0"
              domain="YourAppNameDomain"
              export-all="NON_EMPTY"
              import-all="true">
</classloading>

I had been testing my application using Tomcat 6.x, and, knowing that JBoss uses Tomcat as its web container, I assumed there would be no problems when deploying to JBoss. I never saw this issue in Tomcat because it does not package its own Hibernate jars.

With that issue resolved, I was still perplexed as to why my application would not launch. In my JBoss server log files I continued to get errors the the deployment of my application would not complete. This is hardly a new issue to those with JBoss experience (I found this post from 2003) The problem, it turns out, was that my application included a newer version of xalan.jar than that which JBoss ships with. This problem is similar to the Hibernate issue above, however, it cannot be resolved in the same way, since the xalan classes are used during JBoss’s initial deployment of the web application (i.e., it relies on the xalan jar file prior to reading jboss-classloading.xml).

To resolve this issue I decided that it would be easiest to simply making a separate distribution for my JBoss deployment. I would like to be able to deploy on Glassfish, Jetty, Tomcat and JBoss, but since JBoss has this conflict, one solution is to make a build target similar to this (I am using ant):

<target name="jboss-dist" depends="compile">
 <war destfile="jboss-dist/MyProject.war">
   <fileset dir="WebContent">
     <exclude name="**/xalan*"/>
   </fileset>
   <classes dir="build/classes"/>
 </war>
</target>

Now I have a JBoss deployment which does not include xalan–and it deploys without error!

Trello

A friend was showing me Trello. Looks really cool.

Test-Parallel Development

Here’s a post (albeit dated) where a developer lists a few problems with test driven development. There are plenty more where that came from. What I’ve found works better is a hybrid approach, where we write tests at the same time as code (or just after). The idea behind pure TDD is one of those that sounds good on paper but is difficult to implement practically. Developing to the test means that we abandon some of the best parts of Agile by again tying our hands to strict requirements (this time the requirements are automated tests that don’t work until the code required is implemented). While I am a big supporter of functional automated tests and their inclusion in CI, I don’t think pure TDD is practical. A much better approach is to write functional code and tests together.

The biggest problem I have with TDD is included on the Wikipedia entry on the subject:

Test-driven development is difficult to use in situations where full functional tests are required to determine success or failure. Examples of these are user interfaces, programs that work with databases, and some that depend on specific network configurations. TDD encourages developers to put the minimum amount of code into such modules and to maximize the logic that is in testable library code, using fakes and mocks to represent the outside world.

Fakes and mocks are fine, but I prefer to spend more time implementing tests that run against real world conditions. Also, most all applications that I work on include a UI and/or database. Often, database and UI design occurs alongside all other development.

Taking HTMLUnit as an example, how often do we know what form and input names will appear on a page before we implement it? The same is generally true of database design. In an ideal world, pure TDD would be a great approach. In the real world, where I work, I need more flexibility. This being said, I think most software teams aren’t anywhere near this being a problem. Most have yet to spend appropriate time on automated tests.

Ticket System as a Trigger for Peer Reviews

Somewhat recently I was thinking about what ticket status might be appropriate when using issue tracking for all tasks from functional requirements to documentation to defect tracking. It got me thinking about the need for peer reviews of code and how tedious these reviews can be. It turns out there is at least one plugin for Trac that includes hooks for annotation of code for the sake of peer review. It does not, however, appear to include any kind of formal sign-off capability.

I started thinking that it would be nice to have a plugin for peer reviews (for Trac or Redmine or whatever). Used wisely, however, defining our workflow in a manner that makes the peer review process an integral part of it, we can probably simplify things. Do we really need a plugin, or can we simply use a “In Review” status to achieve the same thing? I suppose the answer to this depends on how strict you want to be.

Here’s what I’m thinking with regard to the history of a ticket (or issue or task or work item or whatever we choose to call it):

 

  • New
  • In-Progress
  • Resolved (or, if we determine that a ticket should not be completed, we have alternatives, such as deferred, rejected, duplicate, etc.)
  • In-Review
  • Closed

 

With a setup such as this, we can use the Resolved status as an indicator that an Issue has been completed, but it is not yet ready to be closed. Tickets are only closed when appropriate peer review actions have been taken. Who determines what these actions are? That is up to the project manager (or the team lead), and it is enforced by proper routing of the ticket. Easy individual responsible for peer review is assigned the ticket. Seeing the “In-Review” status, this colleague reviews the code changes (observing the changset that is attached to the ticket) and makes comments (in the ticket notes).

I know this sounds like a bit of legwork, but I see a few major benefits of an approach like this:

  • Tracing – We now have an audit log of all peer review comments. Using our ticket system with configuration management integration, tickets, changesets and review comments are linked together and not lost in some email thread or document somewhere.
    Time Savings – Anyone who has ever sat through a peer review (and I’m guessing most project managers and developers have) knows how insanely time consuming they can be. Because nobody ever seems to have time, we attempt to save time by doing a large review of code; We wait for a long time, and then we are faced with a peer review involving an overwhelming amount of code. This leads to the next benefit…
  • Better Focus of Reviews – I don’t know about you, but I find that I am much better at reviewing a smaller amount of code or a single functional area than attempting to review thousands of lines of code all at once. We’re all busy, and this isn’t going to change. What happens when you find out that you have a peer review at the end of the week and you have to read through and mark up 5 class files? Do you set aside everything you are working on and do it? You try, but time is short, and so you hurry.
  • Communication – When I take the time to review a changeset, it benefits both team and the individual performing the review. Now I am better informed about what others are working on, where it is implemented, how it is implemented, etc. I don’t have to go bug Joe the Developer to ask him if he finished such-and-such. I already know that he did because I reviewed his code.

This all assumes that our team follows good project management when it comes to the handling of issue tracking and version control. It means that we have to have well organized tickets and we have to commit changesets in some meaningful fashion. This should be a no-brainer.

Is the Software Medical Device World Ready for Agile?

To begin with, I don’t see any real reason why software medical device manufacturers should fear Agile. I do, however, see some stipulations that need to be made. Here is a rather dated article on the subject (from 2007) : Agile Development in an FDA Regulated Setting.

The author of the blog post concludes:

It seems to me that Agile methodologies have a long way to go before we see them commonly used in medical device software development. I’ve searched around and have found nothing to make me think that there is even a trend in this direction. Maybe it’s that Agile processes are just too new. They seem popular as a presentation topic (I’ve been to several), but I wonder how prevalent Agile is even in mainstream software development?

Since the article was written (4 years ago), Agile has clearly gained a solid foothold in mainstream software development. With companies bound by medical device FDA guidelines, however (or even IEEE, ISO 9001, ISO 13484), there may be some understandable fear on new approaches. What seems to happen is that the known process becomes the only trusted process, and adoption of anything knew leads to so many questions that it is simply pushed aside (regardless of the potential benefit to the company).

The “twelve principles” of the Agile Manifesto include:

  • Customer satisfaction by rapid delivery of useful software
  • Welcome changing requirements, even late in development
  • Working software is delivered frequently (weeks rather than months)
  • Working software is the principal measure of progress
  • Sustainable development, able to maintain a constant pace
  • Close, daily co-operation between business people and developers
  • Face-to-face conversation is the best form of communication (co-location)
  • Projects are built around motivated individuals, who should be trusted
  • Continuous attention to technical excellence and good design
  • Simplicity
  • Self-organizing teams
  • Regular adaptation to changing circumstances

Uh oh. A few of these principles are very likely to send upper management, at least those that are used to their traditional waterfall SOPs, running for the door. But who says we can’t make modifications where we need to?

I suspect that much of the resistance to Agile methodologies is closely tied to a fear of change. Upper management trusts that which they know, despite some of the obvious shortfalls.

Wikibook: CI for Software Medical Devices

I’ve started a Wikibook, and I welcome any contributors: CI for Software Medical Devices.

[Wikibooks]

Why I Dislike the @author Annotation

Here’s why I LOVE the @author annotation (in Javadoc comments): It makes me look really good having my name on tons of code. It shows that I am a high-output engineer.

Here’s why I HATE the @author annotation: It implies some sort of ownership of a method, class or package to the rest of the team.

When it comes to writing software, my experience has always been that smaller teams with good developers can get significantly more done than large teams with mediocre developers. (On this note, it may be a good idea to hire a single great developer at $150k rather than 3 junior programmers at $60k, but that’s a separate post).

The @author annotation can be very good to place in your javadoc comments so that others know who to turn to for questions about the code that was written. I’m not opposed to its use (in fact, I use it all the time). Its use, however, should not imply that others on the team are prohibited from modifying the code written by another programmer. On the contrary: Code is the responsibility of the entire team. All code!

There have been many occasions throughout my career wherein another developer said to me, “Hey Matt, can you write such-and-such a method so that I can get such-and-such?” An obvious example is in DAO classes. Another developer may be writing some controller code that requires some DAO method downstream. That developer should not find it necessary to ask the guy or gal who wrote the DAO class to implement a method. Write it yourself! Okay, there are certainly times when it may be appropriate to do so, but the main point is that we should make it clear that all code is the responsibility of everyone on the team.

Another example is when a defect is found. We’ve all made them… Writing code, to some extent, means writing defects. When a defect is found it is never appropriate to allow the rest of the team to be hung up because of it. The person discovering the defect, whether he or she wrote the defect or not, is free to correct it.

I’ll use myself as an example. One time I wrote a POJO class with a method like this:

getSTatus()

Oops! This is a pretty straightforward problem: That T should be lowercase. Because this was code that I checked in and my name appear as the @author, another team member pointed the typo out to me and asked me to correct the problem. This is certainly fair to do, but in the amount of time it took to call me over, show me the typo and send me to fix it, the other team member could have simply checked in a fix. That @author tag does not indicate that the @author is the only one allowed to modify any code.

Tabs vs. Spaces

[Coding Horror: Death to the Space Infidels]
[Joel on Software Forum: Tabs or Spaces?]
[Why I Love Tabs]
[Why I Prefer NO Tabs]
[The Tabs vs. Spaces Holy War]
[Revisiting Tabs and Spaces]
[Rizzoweb: Tabs vs. Spaces]
[Tabs vs. Spaces: The End of the Debate!]

The list goes on and on…

A Bidirectional Add-To-List Mistake

Here’s a somewhat real-world example of a bad coding practice. When setting up bidirectional relationships, its important to remember that the add methods for adding to a list that results in a one-to-many and many-to-one relationship set the parent/child relationship in both directions. To make life simple, I like to provide a couple of different ways of adding to a one-to-many list. For example, say a database contains a “PEOPLE” table made of of Person objects, and each person has many Phones:

@Entity
public class Person {
    @Id
    @GeneratedValue
    private int id;

    private String name;
    private int age;

    @OneToMany(mappedBy = "person")
    @JoinColumn(name = "PERSON_ID")
    private List phones;
    ...
}
@Entity
public class Phone {
    @Id
    @GeneratedValue
    private int id;

    private String number;
    private String type;
    private boolean preferred;

    @ManyToOne(mappedBy = "person")
    @JoinColumn(name="PERSON_ID", nullable=false)
    private Person person;
    ...

    public Person getPerson() {
        return person;
    }
}

Naturally, we need to enforce the bidirectional relation ship like so that adding a phone requires us to add a person (the PERSON_ID foreign key cannot be null!) and adding a phone via a person (person.addPhone(…)) requires that the a phone is added to the phones property and the phone object added to that list is assigned a parent person.

So in our Person class we need a method like this:

addPhone(Phone phone) {
    if (!phones.contains(phone) {
        phones.add(phone);
        phone.setPerson(this);
    }
}

And in the Phone class we need:

setPerson(Person person) {
    if (this.person != person)
        this.person = person;
}

This is all fine and nice, but sometimes it is much easier to have a method that allows us to set all the child relationships at once. I like to offer both methods (i.e., my Person class would have both an addPhone and addPhoneList method). This isn’t at all uncommon. The problem is that where the phone owner is set may be confusing. Is it inside or outside the POJO?

It is tempting to leave the calling logic to do the work. For example:

List phones = new Phones();
for (some loop) {
    Phone = new phone;
    phones.add(phone);
    phone.setOwner(person);
}

person.addPhoneList(phones);

In our Person class we would then need a method like this:

addPhoneList(List phones) {
    this.phones = phones;
}

This assumes that whoever is writing the calling code understands the need to set the phone owner prior to persisting the person object. It also goes against our previous logic for adding a single phone to the list of phones for a person object. (I realize that I am ignoring the fact that my example method may leave some existing phone numbers orphaned or uni-directional, a separate issue).

A better approach to the addPhoneList method is this:

addPhoneList(List phones) {
    for (Phone phone : phones {
        phone.setPerson(this);
    }
}

By doing things this way we keep the work properly encapsulated to the Person class, and we don’t have to assume that the calling logic (and whoever writes it) set the owner for each phone in the list. Its just cleaner… As with nearly everything, there is a tradeoff between efficiency and bulletproof code. We are forced to loop through the list of phones twice in this scenario: Once when the phones are created and again when inserting a phone list to a Assuming we don’t have a massive list and are not making this call with extreme frequency, the overheard is really negligible.

This seems like a basic problem with an obvious solution, but I have seen code this written this say a number of times (where the add single phone method covers the bidirectional relationship but the add multiple method does not). Hibernate/JPA cannot magically figure out the parent/child relationship, so it is very important to enforce it and properly encapsulate responsibility within the persisted POJOs.

[Level Up: One-To-Many Associations]
[Level Up: Many-To-One Associations]

Follow

Get every new post delivered to your Inbox.

Join 67 other followers