I have a set of annotations which are used for tracking failures/success of a function.

Now, there is a class A which has a function f(). This function needs to be invoked for different business use-cases.

What is the right way to track failures/success per business use-case basis? One of the possible approach can be creating separate classes (per use-case) extending class A. These classes will override the f() and call the implementation of super. Now, the required annotations can be putted in these implementation.

However, taking this approach will cause creation of unnecessary classes/object just for tracking purposes.

What is the right way to solve this?

  • 2
    What is a use-case? If they are large you might be better off implementing classes for each test, this will allow you to expand in the future? – Asking Questions Dec 27 '17 at 17:02
  • 1
    There are many ways to wrap functionality: inheritance, interfaces, Proxy Pattern. Or you can just build the tracking into the existing class. But we don't know enough about your situation to offer help. fwiw, classes are, for the most part, free. objects are typically inexpensive, and if their overhead is too high (by observation/measurement), you might share, reuse, or recycle them via a factory or other to reduce overhead. – Erik Eidt Dec 27 '17 at 21:16
  • @AskingQuestions The use-case is basically the source of information through which the input of function f() is being created. – Anshul Jain Dec 28 '17 at 19:07
  • e.g. There are 2 service (B & C) and both are calling service A. Thus the use-cases are B and C. – Anshul Jain Dec 28 '17 at 19:20

There is no "right way" there are several highly annoying ways and a few merely irritating ways.

Inheriting from A and having SubA.f() call super.f() can be highly annoying. Especially if there end up being multiple levels that call up and down. So much so that it has a name: The Yo Yo Problem.

Now just because something has a name doesn't mean it's good or bad. It means it's easy to research. Do that and learn what others say the issues are and decide if, in your situation, you care.

One solution is to just use exceptions. That gives the calling code (your use-case code) control of how it is handled. No need for inheritance.

Another is to pass objects into A.f() that have the success & failure behavior you want called in those events for this particular use-case.

This last one will even work with your annotations. Just annotate the success and failure methods. Still no need for inheritance.

|improve this answer|||||
  • Hi @CandiedOrange, Thanks for the answer and pointing me towards the YoYo problem. However, situation I am trying to describe is a bit different in following ways: – Anshul Jain Dec 28 '17 at 19:39
  • - It will resemble the YoYo pattern but I think it becomes a problem when the inheritance chain is long. In my case, the inheritance tree would be level based because the use-cases I am mentioning are essentially the clients of our service. Thus there would be only one level of inheritance representing all the clients. – Anshul Jain Dec 28 '17 at 19:40
  • - The annotations (e.g. @Latency, @Count(trackingKey="ClientAFailure",trackOn=TrakOn.FAILURE), @Count(trackingKey="ClientASuccess",trackOn=TrakOn.SUCCESS), @Time etc.) we are using is being provided by an external dependency. Thus, controlling these from calling class will require re-implementation of the logic of capturing of these tracking. – Anshul Jain Dec 28 '17 at 19:41
  • Also, I couldn't fully understand your suggestion regarding passing an object with success/failure methods. Kindly provide some examples. – Anshul Jain Dec 28 '17 at 19:41
  • The passing idea is about sending the usecase behavior details into A.f() so you don't have to go back to the calling code. – candied_orange Dec 28 '17 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.