2

We're working on a bugtracking system.

Our design has a BugReport class that represents the filing of a bug of some Project in the system. BugReports have tags, representing the state/progress of the BugReport. Possible tags are e.g. New, Closed, Duplicate, Under Review, ...

Tags have no responsibility other than representing the progress of the BugReport. Except for one special type of tag, Duplicate. Duplicate means that the BugReport is actually a duplicate of another BugReport in the system. When a user tags a BugReport as Duplicate, he should indicate of which BugReport the BugReport is a Duplicate of.

I'm having trouble to design this part. As said before, most tags only have the functionality of representing the progress of the BugReport. Except for one (maybe more in the future) which also has the functionality to point to another BugReport.

A simple enum would've sufficed if not for the Duplicate part, but I have no idea how to provide the extra functionality of Duplicate?

  • 3
    Represent "Duplicate" separately from other tags. Its nature is entirely different. The actual tag that goes with is "Closed". Separately from tracking the progress, you want something to track why a ticket was closed: fixed, not a bug, could not duplicate, duplicate, new feature, will not fix, etc. – Jerry Coffin Mar 17 '16 at 22:19
  • @JerryCoffin That shifts the problem from the status to the disposition field, but I don't see how it solves the underlying problem. – Sebastian Redl Mar 17 '16 at 22:22
  • @SebastianRedl: A fair number of "closed" reasons are going to have references to "other stuff"--another ticket in the case of a duplicate, a hash in the case of fixed, a design document in the case of not a bug, etc. So basically, for any disposition you have a Boolean to say whether a reference is needed, and possibly some way of specifying the type of the reference (but possibly not--you might just use a URI for all of them). Bottom line: you're going to have to solve the general problem for disposition anyway. – Jerry Coffin Mar 17 '16 at 22:26
  • 1
    That still leaves you with a design that breaks when the users decide they want "under review" to reference a reviewer. – Sebastian Redl Mar 17 '16 at 22:29
  • 1
    This question has a follow up question here: programmers.stackexchange.com/questions/313301/… – candied_orange Mar 20 '16 at 18:08
2

The information New, Closed, Duplicate, Under Review, and similar correspond to states of a BugReport.

Simple states are usually represented with an indicator or an enum. If you have only one exception, you could just use an optional association to another BugReport, with the remark that it shall be used only in the case of duplicates.

However another cleaner alternative would be to use the State design pattern. This is very powerful: the states are modeled as class, each state inheriting from a basic state, and encapsulating if necessary state-dependent data and behaviors. It is very powerful and maintenable.

enter image description here

  • Your first suggestion was our first implementation but we're reviewing that to protect the design from future extensions. The State pattern is something we've considered. You claim State is "encapsulating (...) state-dependent data and behaviours". While I agree with the behaviour part, I'm not so sure for the data part. How would Duplicate State keep a reference to another BugReport while the others do not keep any reference and still be accessible from the State interface? – Auberon Mar 17 '16 at 23:17
  • I've considered Decorator as well. Since Duplicate adds extra functionality to a Tag. As far as I know, it isn't possible to extend Tag's functionality (which is an extra reference) using the pattern. Even if we could, how would one access the reference from the interface? – Auberon Mar 17 '16 at 23:20
  • I've updated with a quick picture of a possible model, showing how state could take care of state specific data. Note also that it would be very easy to keep an history of the sates (either with active state + container of past states, or a stack of states, the top being the active one) – Christophe Mar 17 '16 at 23:28
  • 3
    @Auberon In answer to your question. Stop asking "how do I access state?", the general rule is that you don't access state. The state is encapsulated. A BugReport would know how to display itself (possibly through another Strategy object) in a particular medium. Part of its displaying itself would be to pass the medium to the BugState object so it can display itself (hence the showState() method in the interface. In short, whatever code thinks it needs the duplicate should be passed to the BugState to use. – Daniel T. Mar 17 '16 at 23:42
  • 1
    With "taking care of themselves", I mean calling general state methods (that could be called from the BugReport) with a unique signature/interface, and let each state contribute with its specifics. You should however avoid giving states responsibilities that it doesn't have (separation of concerns). For instance, if your BugRepport is a business logic object, it should remain independent of the GUI, so that you can use it in Windows, Gnome, OS/X or console applications. Therefore it may be safer to foresee a string conversion, and leave the printing for the UI subsystem. – Christophe Mar 18 '16 at 17:54

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.