Thursday, May 15, 2014

Service-Orientation, Object-Orientation, SOA, and DDD

With some recent discussions on SOA, ESB, and managing its complexity, I thought I'd write about some relevant points (at least, the ones I find quite relevant) and some questions.

Web Services and SOA

How do you know you're doing SOA? The common answer is, when you're using web services. Unfortunately, web services have nothing to do with SOA.

WTF?!? SOA != Web services

Web services were not created because of SOA! Yup, that's right. It was not created because of SOA.

SOA was first coined by Gartner back in 1996 (see note), long before any web services technology were even developed.

Web services were created to get heterogeneous enterprise packages and systems (mostly from big vendors like Oracle, IBM, Microsoft) to talk to each other in an interoperable way. The W3C started the web services group sometime in 2002 to do just that, and they came up with the web services standards that we know today (e.g. SOAP, WSDL).

W3C was not thinking of SOA when the web services group was developing standards. Unfortunately, the industry mistakenly thought that web services are for service-oriented architecture (SOA). Simply because of the word "service"—web services, service-oriented architecture. Duh?

Tenets of Service Orientation

Like object-orientation, the industry gave service-orientation a spin and (by doing) learned some lessons. In doing OO, we've come to understand that it's not just about inheritance. We've come to favor composition over inheritance, and we program to an interface, not to an implementation. In doing service-orientation, we've come to apply some design guidelines. One of them is Don Box's Four Tenets of Service Orientation. It originally appeared back in 2004 when Don Box published an article on MSDN called "A Guide to developing and Running Connected Systems with Indigo" (Indigo is what's known today as Windows Communication Foundation or WCF for short).

Don defined the following four (4) tenets:

  • Boundaries are explicit
  • Services are autonomous
  • Services share schema and contract, not class
  • Service compatibility is determined based on policy

Although it is showing its age, I still find it quite relevant. I think most people make the mistake of focusing on the technology of SOA, and forgetting about the underlying design principles of service-orientation. It seems that most are making the mistake of using some kind of ESB (or some other SOA-based tool) as a reason an excuse to implement SOA correctly.

One of the tenets indicate that (service) boundaries are explicit. So, how do we mark the boundaries of a service? What's a service in the first place?

The word 'boundary' (in boundaries are explicit) reminded me of a website (Should I Use SOA?) that Edge showed me a while back. It will ask you if you're Amazon. If you answered 'No', it shows a page that says you should not be using SOA, as it is too early. It goes on to explain something about separating services, getting the proper breakdown, and aligning team boundaries with service boundaries.

In service-orientation, I like Udi Dahan's definition of a service in service-orientation.

A service is the technical authority for a specific business capability.

Any piece of data or rule must be owned by only one service.

- The Known Unknowns of SOA - from Udi Dahan's Blog

It's really about business capability. And there is a strong emphasis on encapsulation such that any piece of data or rule must be owned by only one service.

So, if in my organization, we have the business capability of showing a catalog of products, and that is separate from pricing, does this mean we have to mark the boundaries along those lines of separation?

Or say, if in an organization, the HR owns the employee and employment data, and another group owns the customer data, does this mean that we have a service for HR to own all employee/employment data and rules, while another service owns all the customer data? What if a former employee becomes a customer, or vice-versa?

Here's another thought. Since services in service-orientation are built around a specific business capability, I remember reading an interview with Werner Vogels, Chief Technology Officer at Amazon where he mentions that Amazon applies the motto You build it, you run it. Here, the team that develops the product (is this a service? a business capability?) is responsible for maintaining it in production for its entire life-cycle. All products are services managed by the teams that built them. The team is dedicated to each product throughout its life-cycle and the organization is built around product management instead of project management.

There is another lesson here: Giving developers operational responsibilities has greatly enhanced the quality of the services, both from a customer and a technology point of view. The traditional model is that you take your software to the wall that separates development and operations, and throw it over and then forget about it. Not at Amazon. You build it, you run it. This brings developers into contact with the day-to-day operation of their software. It also brings them into day-to-day contact with the customer. This customer feedback loop is essential for improving the quality of the service.

- an interview with Werner Vogels, Chief Technology Officer at Amazon

If service-orientation is about business capability, wouldn't DDD (as it emphasizes business-domain) be appropriate to determine the 'boundaries' and the separation?

If services are autonomous, does it mean it shouldn't be relying on other services to function properly?

When I read services share schema and contract, not class, I ask myself, isn't this programming to an interface, not to an implementation?

Are your (SOA) services following (or breaking) any of the four (4) tenets?

There's so much more to service-orientation than I could write in this post. I hope to write more in the coming months.

Service-Orientation vs. Object-Orientation

Don Box explains:

Service-orientation is an important complement to object-orientation that applies the lessons learned from component software, message-oriented middleware and distributed object computing. Service-orientation differs from object-orientation primarily in how it defines the term "application." Object-oriented development focuses on applications that are built from interdependent class libraries. Service-oriented development focuses on systems that are built from a set of autonomous services.

- A Guide to Developing and Running Connected Systems with Indigo
(Indigo is what's known today as Windows Communication Foundation or WCF for short)

Another point of difference is with how messages are communicated. In service-orientation, services send and receive data (no attached behavior). In OO, objects can send messages that contain data and behavior. In service-orientation, since services can be implemented using different platforms, it can only safely send/receive data (without behavior).

In Closing

I still have a lot to learn in service-orientation and in SOA. Writing this post has helped me clear things up. I think it's good to see that the industry is building on good things that worked (like service-orientation emphasizing on boundaries and autonomy, which I think was building on top of OO's encapsulation). I hope to write more about this as I do more SOA.

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.