Thursday, April 24, 2014

Feedback: Giving, Seeking, and Receiving

Giving feedback is difficult. Receiving feedback can be tough at times (especially when it's negative feedback).

In my world, feedback is very useful critical. After years of practice, I still feel that I'm not good at giving feedback. So, I'm writing down some notes that I found helpful in giving (seeking and receiving) feedback.

Note #1: Give Feedback As Soon As Possible

Don’t store it up. Give feedback as soon as possible (within hours, or days, of a specific event or instance if you can).

Note #2: Choose An Appropriate Time And Place

Allow enough time so that you are not rushed. Never give "negative" feedback in public.

I also time-box the session to not exceed 60 minutes. I find that about 30 minutes is good enough. If the conversation begins to drag, get emotional or you/they need time to "digest" what is being said, take time out—arrange a break and reschedule the meeting for a later time.

Note #3: Be Specific

There's nothing more frustrating than feedback that is not specific. How would you react to the following?

  • You're doing ok, I’m happy.
  • You need to do/manage this better.
  • I'm disappointed with you.
  • Your code was terrible.

Seriously! How would you react to the above?

So, how can I be more specific? Here, I found that using the STAR and SBI models help me think about ways I can be more specific.

Here's an example, and further breakdown (in table form).

I felt you really supported me when the team missed some stories in the recently concluded sprint. I had expected you to be frustrated by that because we had committed to it, but you understood and told the team that it wasn't my fault. So I’d like to say thanks, I feel much better about things.
Situation I felt you really supported me when the team missed some stories in the recently concluded sprint. I had expected you to be frustrated by that because we had committed to it…
Behavior …but you understood and told the team that it wasn't my fault.
Impact So I’d like to say thanks, I feel much better about things.

Here's another example, and further breakdown (in table form).

I've noticed that you have been coming to work at 10:30am this past week. The team's daily stand-up was agreed to be at 10am. It's in our team policy that we are all on time in the morning. Because you came into work after the stand-up, the team didn't hear about your status updates and blockers. Being 'one person down' put a lot of pressure on the rest of the team. The others in the team even took tasks that you've probably started.
Situation I've noticed that you have been coming to work at 10:30am this past week.
Task The team's daily stand-up was agreed to be at 10am. It's in our team policy that we are all on time in the morning.
Action Because you came into work after the stand-up, the team didn't hear about your status updates and blockers.
Result
(or impact)
Being 'one person down' put a lot of pressure on the rest of the team. The others in the team even took tasks that you've probably started.

At this point (after providing the facts/specifics, and sometimes the impact), I would usually pause, and ask for the person's feelings. Like, what happened?, what do you think happened here?, how do you feel about that?, and listen. Yep, pause and listen. Sometimes, pausing is enough. The person I'm giving feedback to, would explain his/her side. So, I pause and just listen.

Note #4: End with an Agreement

End the feedback session with an agreement. This is important. So, don't forget about ending with an agreement.

Usually, when giving negative feedback, an agreement should be reached. This agreement involves preventing the undesired behavior from occurring again, and providing consequences if it does occur again. Decide together what action(s) you both will take after the meeting.

A Suggested Sequence

While researching further on giving/getting feedback, I chanced upon a PDF from ACTPS Performance Framework. It suggests the following sequence:

  1. When you… (situation and behavior)
  2. I am concerned because… (impact)
  3. Pause for discussion.
  4. I would like…
    Because…
  5. What do you think?
When you… A statement that describes the behaviour without judgment, exaggeration, labelling or motives. Just state the facts as specifically as possible (You could use the STAR model outlined above).
I am concerned because… Say who or what it impacts and what the impact is.
Pause for discussion. Let the other person respond.
I would like…
Because…
Describe the change to the other person to consider and why you think the change will address the issue/concern.
What do you think? Listen to the other person's responses. Be prepared to discuss options.

And, don't forget to end with an agreement.

Good News For Those Who Seek Feedback

A research paper, "Tell Me What I did Wrong: Experts Seek and Respond to Negative Feedback," in The Journal of Consumer Research, says that when people are experts on a subject, or consider themselves experts, they’re more eager to hear negative feedback, while those novices are more likely to seek positive responses.

So... if you're eager to hear negative feedback, congratulations! You're on your way to becoming experts.

Further Reading

Just a few days ago, I saw this book by Douglas Stone and Sheila Heen at Fully Booked (across DLSU Taft).

Thanks for the Feedback: The Science and Art of Receiving Feedback Well
I don't have a copy. But I watched some talks (on YouTube) given by the book's authors. So far, it's good to know that receiving feedback is a skill that can be learned.

Sunday, April 13, 2014

Mapping a Map in JPA

It's common to see a java.util.List being used for a to-many mapping (with ORM). And it's also common to need to get an element in that list using some key. So, I thought, why not use a java.util.Map instead (and still maintain the to-many mapping)?

As I found out, it's not often used, but quite easy to do. So, I'm sharing what we learned here (applying it to a fictitious case of a library app).

Mapping a Map in JPA

In our library app, we have books and copies of them. One book can have one or more copies. The resulting tables should look something like this.

Book
ID (auto-generated primary key)
TITLE
Other columns like author, publisher, etc.
Copy
ID (auto-generated primary key)
BOOK_ID (foreign key to Book table)
COPY_REF_ID
STATUS

In UML, it would look something like this. Book with many copies (UML class diagram)

And the JPA code would look something like this.

@Entity
public class Book {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  @Column(name="ID")
  private Long id;

  private String title;

  @OneToMany(orphanRemoval=true)
  @MapKey(name="referenceId")
  @JoinColumn(name="BOOK_ID", referencedColumnName="ID")
  private Map<String, Copy> copies;

  ...

  public void borrowCopy(String referenceId) {
    Copy copy = this.copies.get(referenceId);
    if (copy != null) {
      copy.borrowCopy();
    }
  }
  ...
}
@Entity
@Table(uniqueConstraints=@UniqueConstraint(
        columnNames = {"BOOK_ID", "COPY_REF_ID"}))
public class Copy {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  @Column(name="ID")
  private Long id;

  @Column(name="COPY_REF_ID")
  private String referenceId;
  ...

  public void borrowCopy() {...}
  public void returnCopy() {...}
}

The other important bit to make the one-to-many Map work is the @MapKey annotation. This tells the ORM to use that field (of Copy) as the key to the Map. To ensure that the referenceId will be unique for copies of a particular book, we've added a unique constraint on the Copy entity.

Unidirectional One-to-Many

Notice that I'm using a unidirectional one-to-many mapping. Although this is not necessary when mapping a map, this unidirectional one-to-many mapping can make things simpler, since the Copy object does not need to have a reference to the Book object. This is achieved by removing the @ManyToOne annotation on the Copy object, and adding a @JoinColumn to the @OneToMany annotation in the Book object. This tells the ORM the column name to use on the many-side of the relationship. In the example above, I've instructed the ORM to use a column named BOOK_ID on the Copy table (the many-side of the relationship, since one book can have many copies).

Lazy Collections

My colleague (Juno Aliento) pointed this out to me (@LazyCollection(LazyCollectionOption.EXTRA)). This is useful when you don't want the entire collection (or map, as in this case) to be loaded because you're doing a size().

Note that this is Hibernate-specific, and may not be available in other JPA providers.

As of release 3.2, Hibernate can perform per-item lazy initialization of collections. The reference documentation mentions it here. When the association mapping (OneToMany or ManyToMany) is set to lazy="extra", the collection implementation for the mapping takes on "smart" collection behavior, i.e. some collection operations such as size(), contains(), get(), etc. do not trigger collection initialization. This is only sensible for very large collections, but it's quite handy nonetheless.