Skip to main content

Programming Foundations - Lotto Session #1


This tutorial covers key concepts to assist with learning programming best practices and foundations. Examples demonstrate the construction of foundation classes using a lottery pick scenario.  Software best practices include: separation of concerns, abstraction, validations, and testing. If these aren't familiar at all, great, this session will get you started on your way to understanding.  I hope you enjoy learning through this session and upcoming sessions that will build upon one another. Let's get started!

This material covers beginning concepts while touching on some intermediate API-level topics.  The following will be included in this session:
  1. Create an abstract model to represent a post-transformed lotto drawing.
  2. Create a specific subclass that extends the abstract model.
  3. Address initialization of state and validations.
  4. Construct test coverage to verify the implemented model.

Creating a Model

A typical lottery drawing includes a set of core picks and a special single pick that usually resides in a different range of values than the core picks.  In our example, we will use the following rules:

  • Core picks will be 5 numbers in the range 1-65, with no duplicates allowed.
  • Special pick (e.g. power pick) will be a single number in the range 1-36.
  • A drawing will be for a specific date and there will only be one drawing per day.

To model this, let's start with some code.  Let's design our application to accommodate some future lottery models, so as we find more styles of lotteries, we can plug those into our application!  One way to approach this is to create an abstraction for what we call a drawing.



This is an example of object-oriented inheritance in Java.  If you aren't familiar with inheritance, no worries, it will be explained as we work through our application.

public abstract class Drawing { }

Let's start with our state that we foresee needing for our drawing.  Since we are creating an abstraction at this point, we are going to be generic.  We know we need a single date so we will use LocalDate from Java 8's java.time package.  And for a set of picks, this can be represented by a set of integers.  

protected LocalDate date;
protected Set<Integer> corePicks;

Since we know that validation will be necessary for each type of drawing, we can include this as an abstract method that must be implemented by subclasses.  An exception class is identified as well to allow proper feedback to the caller.

abstract void validate() throws ValidationException;

When a class is used as an object in Java, it must be constructed, so our abstraction can identify a generic constructor to ensure the core picks for a specific date are properly handled.

public Drawing(LocalDate date, Set<Integer> corePicks) { }

At this point, we have a basic abstraction of a Drawing to build upon.  To make this abstraction useful, we will create a subclass that extends Drawing.  This will include power pick state and some constants to identify boundaries for number of core picks, maximum core pick, and maximum power pick.

The constructor is implemented to illustrate how the state of a PowerDrawing will be initialized.  It is important to check for required information, these checks have been added to the abstract Drawing class as well as the PowerDrawing class' constructor to ensure proper initialization.

Checks are added to our Drawing constructor to ensure no missing picks or date. Note: this is one power of inheritance, we don't have to do this for every new class as we expand the lotto drawing models we expand in the future.

Since we are utilizing the base class at this point, let's add the required validate() implementation.  In this case, validate() was declared as an abstract method in the Drawing base class and is required to be implemented in our PowerDrawing class. Otherwise, a compile time issue will occur.

Here's the first iteration of a validate() operation.
The validate solution utilizes the stream library introduced in Java 8.  In this case, it allows us to easily detect a core pick that is out of range based on on our range defined with an IntRange.  A filter checks for ANY core pick that is NOT in the accepted core pick range.  The power pick validation is easier as we just check to see if it's not in the accepted power picks range.

While constructing tests to cover this functionality, I determined there was a Java 8 class IntStream that would alleviate the need for the Apache IntRange usage.  As a result, the final solution includes the following approach.

Note: There are many ways to solve this problem, but I found the second version to reduce some lines of code as well as reduce a dependency for functionality that is available in Java 8.



When implementing the validate() method, it may be noticed that the validation component could be generic and implemented in the base class Drawing.  As such, we can create a validateCorePicksSize(...) method to reference from our subclass validate() method.


Why do this?  The advantage of the base class is that common Drawing operations can be implemented in that class as opposed to each subclass having its own implementation.  The trick when using inheritance is that the operation does need to be generic and never specific to a subclass. If there is something so specific to the subclass core pick size validation, that can self-contained in the subclass.

For the test-driven development fans, we've gone way too far without some testing, let's address that now to see how this model can be used.

I chose to use Spock for test coverage, which is a testing and specification framework that supports Java & Groovy application testing.  The tests are written in the Groovy language, which is handy for testing and scripting solutions due to its dynamic and concise nature.

The test cases can easily be re-implemented in JUnit or other testing frameworks, so no worries if you do not want to use Spock.

Note: I've found the Spock framework to be extremely powerful and has many capabilities that can make your tests extremely concise and easy to comprehend. I've used this framework to test highly complex enterprise solutions and it has amazed me with what it can provide. Don't be fooled by Spock's low version number!

Unit Testing

The Drawing and PowerDrawing classes have some validations to target with tests.  To start, import the Spock Specification class and extend it with our customized test.   

import spock.lang.Specification;
class PowerDrawingTest extends Specification {
}
Now a test operation is added.  A nice thing about Spock is we can name the test operation to be explanatory, so when the test is executed it will include the description with the result of the test.

def "power drawing - construct and validation success"() {
}

The implementation of our test will follow a test pattern used within Spock to assist with comprehending what is being tested.  That is, we use Spock's given, when, and then separation of duties within a test operation.  Notice how each section can have its own description to allow for easier comprehension of what is being given, tested, and expected result(s).



This is a start for our overall test coverage, in the next session we will expand on this coverage by adding some additional test operations using Spock.

Summary

In this session, we touched on modeling lotto drawing information using Java.   Topics such as custom validation, inheritance, and object state initialization were covered. A brief introduction to streams with alternatives for dealing with range checks were included.  The session was finalized with test coverage using the Spock framework.

Check out the complete source code using the link below and feel free to contact me for future session content!  Until next time ...

Source - Lotto Session #1

References

Java 8 - General

https://docs.oracle.com/javase/8/docs/api/

Java 8 - Streams

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

Spock - Specification

http://spockframework.org/

  

Comments