views:

122

answers:

2

You're writing an application that manages online courses. A course is completed in many different ways. A user must do one or more of the follow to complete the course:

  • spend x amount of hours in the course
  • take a test, and pass the test (a passing score could be different for every course)
  • take all the lessons in a course
  • some other requirements you don't know about yet

When a course is completed, some event needs to happen. The event depends on the course. One or more of the following may need to happen:

  • A custom certificate is created for the user
  • An organization is alerted via email, HTTP callback, or something else
  • some other requirements you don't know about yet

Many of the courses are almost identical with respect to their requirements, but some are completely unique. There are a lot of courses, upwards of 50, and more are always being added.

How would you design an application like this? Is there a design pattern you can use to eliminate redundant code, and make it easy to add/edit courses?

+1  A: 

A message bus for handling the final phase and a state machine to determine when they have passed. Actually all of this could be done with a message bus. A good book to read on it is Enterprise Integration Patterns which goes over situations like these. The tricky part is making sure that faults the software don't cause students to lose getting credit.

Maybe I just have jms/esb fever.

fuzzy-waffle
+1  A: 

Here how I would start sketching it out...

You have a Course object which accepts a Requirements object and a OnCompleteActions object in its constructor... granted I would make the constructor internal and Create a CourseBuilder that will know how to build all of the different courses but...

When ever the Course is updated it checks if the Requirements are met by passing itself to the Requirements object. If it meets the requirements it then passes itself to the OnCompleteActions.

private void OnCourseUpdate()
{
        if (this._Requirements.AreMetBy(this))
        {
            this._OnCompleteActions.Execute(this);
        }
}

Requiremetns object is nothing but an aggregate list of IRequirement which you could fine tune based on the Course that you create... the AreMetBy method simple enumerates all of your IRequirements in the list and checks to see if your course satisfies them all...

interface IRequirement 
{
    public bool IsMetBy(Course course);
}

Then you could have all sorts of different Requirements that implement IRequirement...

class CourseHoursRequirement : IRequirement
{
    public CourseHoursRequirement(int minimumHours)
    {...}

    public bool IsMetBy(Course course)
    {
        return course.NumberHours >= this._MInimumHours 
    }
}

Same idea for the OnCompleteActions would have a list of one or More IOnCompleteAction that would execute each one. ex. CreateCertificateOnCompleteAction, SendEmailOnCompleteAction, etc.

By encapsulating each possible Requirement in its own class you can then Build a course that would have a MinimumHourRequirement, a PassedAllTestRequirement, etc. You could easily add new requirements as you go because they are all implementing the same interface. You probably have to add some limit properties as you go (like minimumHours) but the real work is done inside of the IsMetBy() method...

Good luck!

J.13.L
That helps a lot. Thank you.
Let me know if there is anything else I can help you with...
J.13.L