Feed on
Posts
Comments

The Problem to Solve

Many web applications collect financial information to submit as leads for loans, credit card applications, bank information or other purposes. To ensure that the submitted SSN is valid, a validation algorithm must be implemented against the submitted value. Many websites in their infancy check only for length and null, but there is actually a formula that is published by the government to further qualify the SSN in the form field. By validating this SSN further, the quality of the generated lead is increased, which will have direct impact on the value of the data.

The algorithm we’ll construct is based on the following formulaic instruction:

“A valid SSN is determined by the following rules according to the website http://www.ssa.gov/employer/ssnweb.htm

Area-Group-Serial (AAA-GG-SSSS) The Social Security number consists of nine (9) digits. The first three (3) digits denote the area (or State) where the application for an original Social Security number was filed.

Within each area, the group number (middle two (2) digits) range from 01 to 99 but are not assigned in consecutive order. For administrative reasons, group numbers issued first consist of the ODD numbers from 01 through 09 and then EVEN numbers from 10 through 98, within each area number allocated to a State. After all numbers in group 98 of a particular area have been issued, the EVEN Groups 02 through 08 are used, followed by ODD Groups 11 through 99.

Within each group, the serial numbers (last four (4) digits) run consecutively from 0001 through 9999.”

So, for reference, just in case: The first three digits are the “Area” reference. The second two digits are the “Group” reference, and the final four digits are the “Serial Number” value.

We’ll create a validator that checks to ensure that the social security number is the right length (stripped of dashes and white spaces), is all numbers, and finally implements the Social Security Administration’s formula for the Area/Group validation and their list of invalid SSNs.

What is needed

The data for Area/Group validation and invalid SSN’s is quite static. ?For performance reasons, it is not necessary or reasonable to create a database to manage this data when a simple list can be used. ?In this particular implementation, we’ll hard code these values into a dictionary constant and create a frozenset to make the lookup and validation of the SSN Area even faster. The list of invalid SSNs will also be a frozenset.

Why frozenset

I use a Python set because I’m just testing “membership” in the group. This gives me optimization. Further I decided to use frozenset because it’s API is limited further, not allowing updates, ordering or indexing. I want to use these values as a constant that is loaded into the VM at run-time and does not depend on any database lookup for performance reasons.

Project Structure

The file structure is a typical Django Project with an “application” subdirectory. The application subdirectory is called finvs, short for “financial validators”. By using the manage.py startapp finvs, you’ll get the basic structure of the finvs automatically, and then you can add the utils subdirectory to abstract your algorithms and validation objects away from the actual application.

Note that a tests.py file has been created automatically. When running manage.py test {app} the tests that are located in the tests.py of each {app} directory — in this case finvs, will be run. Once everything is set up, we will explain how to use the tests to develop the actual implementation used in the validation_formulas.py file without ever having to start the Django server. This means that you won’t have to develop a lot of front end code or do anything that you don’t need to do. You can develop in an independent manner and work on the code that is a priority.

project_root
        |-finvs
                |-utils
                        |-__init__.py
                        |-ssn_constants.py
                        |-validation_formulas.py
                |-__init__.py
                |-models.py
                |-tests.py
                |-views.py
        |-__init__.py
        |-manage.py
        |-settings.py
        |-urls.py

For the purposes of this demonstration, the only files we’ll be using in this structure are finvs/utils/ssn_constants.py to hold the data in a “persistence layer”, finvs/utils/validation_formulas.py to contain the actual implementation method(s) of the validation, and finvs/tests.py to test and develop the code before I actually implement it.

The “Persistence Layer”

As described above, having all the information in a database requires too much overhead and is a drag on performance of the validation. Having to suffer through a lookup to a database and the maintenance of this data involves more work and runtime cost than is necessary for what is very static data that rarely changes.

Since there are only a few hundred records to deal with, there is very little memory overhead taken up holding these values as static members. I therefore created a file in the utils directory that contains the data I will use to validate SSNs against (ssn_constants.py). The code I inserted is enumerated in its entirety below:

finvs/utils/ssn_constants.py
# a dictionary of area/group field values.
#The values represent the "high value" to be
# used with the SSN validation algorithm.
SSN_HIGH_VALUES ={
"001":"04","002":"02","001":"04","002":"02","003":"02","004":"06","005":"06","006":"06",
"007":"06","008":"90","009":"88","010":"90","011":"88","012":"88","013":"88","014":"88",
"015":"88","016":"88","017":"88","018":"88","019":"88","020":"88","021":"88","022":"88",
"023":"88","024":"88","025":"88","026":"88","001":"04","002":"02","003":"02","004":"06",
"005":"06","006":"06","007":"06","008":"90","009":"88","010":"90","011":"88","012":"88",
"013":"88","014":"88","015":"88","016":"88","017":"88","018":"88","019":"88","020":"88",
"021":"88","022":"88","023":"88","024":"88","025":"88","026":"88","027":"88","028":"88",
"029":"88","030":"88","031":"88","032":"88","033":"88","034":"88","035":"72","036":"70",
"037":"70","038":"70","039":"70","040":"08","041":"08","042":"08","043":"08","044":"08",
"045":"08","046":"08","047":"08","048":"08","049":"08","050":"96","051":"96","052":"96",
"053":"96","054":"96","055":"94","056":"94","057":"94","058":"94","059":"94","060":"94",
"061":"94","062":"94","063":"94","064":"94","065":"94","066":"94","067":"94","068":"94",
"069":"94","070":"94","071":"94","072":"94","073":"94","074":"94","075":"94","076":"94",
"077":"94","078":"94","079":"94","080":"94","081":"94","082":"94","083":"94","084":"94",
"085":"94","086":"94","087":"94","088":"94","089":"94","090":"94","091":"94","092":"94",
"093":"94","094":"94","095":"94","096":"94","097":"94","098":"94","099":"94","100":"94",
"101":"94","102":"94","103":"94","104":"94","105":"94","106":"94","107":"94","108":"94",
"109":"94","110":"94","111":"94","112":"94","113":"94","114":"94","115":"94","116":"94",
"117":"94","118":"94","119":"94","120":"94","121":"94","122":"94","123":"94","124":"94",
"125":"94","126":"94","127":"94","128":"94","129":"94","130":"94","131":"94","132":"94",
"133":"94","134":"94","135":"17","136":"17","137":"17","138":"17","139":"17","140":"17",
"141":"15","142":"15","143":"15","144":"15","145":"15","146":"15","147":"15","148":"15",
"149":"15","150":"15","151":"15","152":"15","153":"15","154":"15","155":"15","156":"15",
"157":"15","158":"15","159":"82","160":"82","161":"82","162":"82","163":"82","164":"82",
"165":"82","166":"82","167":"82","168":"82","169":"82","170":"82","171":"82","172":"82",
"173":"82","174":"82","175":"82","176":"82","177":"82","178":"82","179":"82","180":"82",
"181":"82","182":"82","183":"82","184":"82","185":"82","186":"82","187":"82","188":"82",
"189":"82","190":"82","191":"82","192":"82","193":"82","194":"82","195":"82","196":"82",
"197":"82","198":"82","199":"82","200":"82","201":"82","202":"82","203":"82","204":"82",
"205":"82","206":"82","207":"80","208":"80","209":"80","210":"80","211":"80","212":"75",
"213":"75","214":"75","215":"75","216":"73","217":"73","218":"73","219":"73","220":"73",
"221":"04","222":"02","223":"99","224":"99","225":"99","226":"99","227":"99","228":"99",
"229":"99","230":"99","231":"99","232":"53","233":"51","234":"51","235":"51","236":"51",
"237":"99","238":"99","239":"99","240":"99","241":"99","242":"99","243":"99","244":"99",
"245":"99","246":"99","247":"99","248":"99","249":"99","250":"99","251":"99","252":"99",
"253":"99","254":"99","255":"99","256":"99","257":"99","258":"99","259":"99","260":"99",
"261":"99","262":"99","263":"99","264":"99","265":"99","266":"99","267":"99","268":"11",
"269":"11","270":"11","271":"11","272":"11","273":"11","274":"11","275":"11","276":"11",
"277":"11","278":"11","279":"11","280":"11","281":"11","282":"11","283":"11","284":"11",
"285":"11","286":"11","287":"11","288":"11","289":"11","290":"11","291":"11","292":"11",
"293":"11","294":"11","295":"11","296":"08","297":"08","298":"08","299":"08","300":"08",
"301":"08","302":"08","303":"31","304":"29","305":"29","306":"29","307":"29","308":"29",
"309":"29","310":"29","311":"29","312":"29","313":"29","314":"29","315":"29","316":"29",
"317":"29","318":"04","319":"04","320":"04","321":"04","322":"04","323":"04","324":"04",
"325":"04","326":"04","327":"04","328":"04","329":"04","330":"04","331":"04","332":"04",
"333":"04","334":"04","335":"04","336":"04","337":"04","338":"04","339":"04","340":"04",
"341":"04","342":"04","343":"04","344":"04","345":"04","346":"04","347":"04","348":"04",
"349":"04","350":"04","351":"04","352":"04","353":"04","354":"04","355":"04","356":"04",
"357":"04","358":"04","359":"04","360":"04","361":"04","362":"33","363":"33","364":"33",
"365":"33","366":"33","367":"33","368":"31","369":"31","370":"31","371":"31","372":"31",
"373":"31","374":"31","375":"31","376":"31","377":"31","378":"31","379":"31","380":"31",
"381":"31","382":"31","383":"31","384":"31","385":"31","386":"31","387":"27","388":"27",
"389":"27","390":"27","391":"27","392":"27","393":"27","394":"27","395":"25","396":"25",
"397":"25","398":"25","399":"25","400":"65","401":"65","402":"65","403":"65","404":"65",
"405":"63","406":"63","407":"63","408":"99","409":"99","410":"99","411":"99","412":"99",
"413":"99","414":"99","415":"99","416":"59","417":"59","418":"59","419":"59","420":"59",
"421":"59","422":"59","423":"59","424":"57","425":"99","426":"99","427":"97","428":"97",
"429":"99","430":"99","431":"99","432":"99","433":"99","434":"99","435":"99","436":"99",
"437":"99","438":"99","439":"99","440":"21","441":"21","442":"21","443":"21","444":"21",
"445":"21","446":"21","447":"19","448":"19","449":"99","450":"99","451":"99","452":"99",
"453":"99","454":"99","455":"99","456":"99","457":"99","458":"99","459":"99","460":"99",
"461":"99","462":"99","463":"99","464":"99","465":"99","466":"99","467":"99","468":"47",
"469":"47","470":"47","471":"47","472":"47","473":"47","474":"47","475":"47","476":"47",
"477":"45","478":"37","479":"35","480":"35","481":"35","482":"35","483":"35","484":"35",
"485":"35","486":"23","487":"23","488":"23","489":"23","490":"23","491":"23","492":"23",
"493":"23","494":"23","495":"23","496":"23","497":"23","498":"21","499":"21","500":"21",
"501":"31","502":"31","503":"39","504":"37","505":"51","506":"49","507":"49","508":"49",
"509":"25","510":"25","511":"25","512":"25","513":"25","514":"25","515":"25","516":"43",
"517":"41","518":"73","519":"73","520":"51","521":"99","522":"99","523":"99","524":"99",
"525":"99","526":"99","527":"99","528":"99","529":"99","530":"99","531":"59","532":"59",
"533":"57","534":"57","535":"57","536":"57","537":"57","538":"57","539":"57","540":"71",
"541":"71","542":"69","543":"69","544":"69","545":"99","546":"99","547":"99","548":"99",
"549":"99","550":"99","551":"99","552":"99","553":"99","554":"99","555":"99","556":"99",
"557":"99","558":"99","559":"99","560":"99","561":"99","562":"99","563":"99","564":"99",
"565":"99","566":"99","567":"99","568":"99","569":"99","570":"99","571":"99","572":"99",
"573":"99","574":"45","575":"99","576":"99","577":"41","578":"41","579":"41","580":"37",
"581":"99","582":"99","583":"99","584":"99","585":"99","586":"57","587":"97","589":"99",
"590":"99","591":"99","592":"99","593":"99","594":"99","595":"99","596":"80","597":"80",
"598":"80","599":"80","600":"99","601":"99","602":"57","603":"57","604":"55","605":"55",
"606":"55","607":"55","608":"55","609":"55","610":"55","611":"55","612":"55","613":"55",
"614":"55","615":"55","616":"55","617":"55","618":"55","619":"55","620":"55","621":"55",
"622":"55","623":"55","624":"55","625":"55","626":"55","627":"02","628":"02","629":"02",
"630":"02","631":"02","632":"02","633":"02","634":"02","635":"02","636":"02","637":"02",
"638":"02","639":"02","640":"02","641":"02","642":"98","643":"98","644":"98","645":"98",
"646":"86","647":"86","648":"40","649":"38","650":"40","651":"38","652":"38","653":"38",
"654":"22","655":"22","656":"22","657":"22","658":"20","659":"12","660":"12","661":"12",
"662":"12","663":"10","664":"10","665":"10","667":"30","668":"28","669":"28","670":"28",
"671":"28","672":"28","673":"28","674":"28","675":"28","676":"10","677":"10","678":"10",
"679":"09","680":"76","681":"10","682":"09","683":"09","684":"09","685":"09","686":"09",
"687":"09","688":"09","689":"09","690":"09","691":"03","692":"03","693":"03","694":"03",
"695":"03","696":"03","697":"03","698":"03","699":"01","700":"18","701":"18","702":"18",
"703":"18","704":"18","705":"18","706":"18","707":"18","708":"18","709":"18","710":"18",
"711":"18","712":"18","713":"18","714":"18","715":"18","716":"18","717":"18","718":"18",
"719":"18","720":"18","721":"18","722":"18","723":"18","724":"28","725":"18","726":"18",
"727":"10","728":"14","729":"07","730":"05","731":"05","732":"05","733":"05","750":"05",
"751":"03","756":"01","757":"01","758":"01","759":"01","760":"01","761":"01","762":"01",
"764":"62","765":"62","766":"48","767":"48","768":"48","769":"48","770":"48","771":"46",
"772":"46"
}

# frozenset makes for quick access to the key fields of the SSN high values
# the key fields are the 'areas'
VALID_SSN_AREAS = frozenset(SSN_HIGH_VALUES.keys())

# a frozenset of invalid ssn numbers
INVALID_SSN_NUMBERS = frozenset([
"002281852","042103580","062360749","078051120",
"095073645","128036045","135016629","141186941",
"165167999","165187999","165207999","165227999",
"165247999","189092294","212097694","212099999",
"306302348","308125070","468288779","549241889",
"987654320","987654321","987654322","987654323",
"987654324","987654325","987654326","987654327",
"987654328","987654329"])

The Test Harness

Description of the Test

There are a few parts to the test. I built it in a few steps. first, the setUp method creates a “Good” SSN, “Good” Group and “Good” High Group values. The “High Group” is that value that is highest allowed for the particular “Area” value. The first method, testSSNValidation(self) is a test of the implementation with a known good serial number. This is the first method that I wrote, because this is where I “worked out” the algorithm that I wanted to use in the implementation.

Once I got the “right answer”, I could create another test method to throw a whole bunch of numbers at it to ensure that it is working right under all circumstances and border conditions. Note the extensive documentation — you may be passing this code off to another team in the future, and it’s important to leave a good trail. Validation this complicated is not self documenting. Walking through the method, I first created the return value that I wanted to use and made it False so that if any validation failed it would fall through and just return. Once the default was set, I stripped out any hyphens and whitespace, I checked the value for length, then check to ensure that the Area (first three digits) is valid. If the number passes all these tests, we can then go into the private method that I created to implement the “high values” formula __isGroupValid(self,group,groupHighestValue):

Note: this is a pretty complex formula so I’m not going to get into the gritty details — see the SSA site for more info…

finvs/tests.py
"""
This file tests the finvs application
"""
import unittest
from django.test import TestCase
from finvs.utils.validation_formulas import ValidationFormulas
from finvs.utils.ssn_constants import SSN_HIGH_VALUES
from finvs.utils.ssn_constants import INVALID_SSN_NUMBERS
from finvs.utils.ssn_constants import VALID_SSN_AREAS

class ValidatorsTestCase(unittest.TestCase):

    GOOD_SSN = ' '
    GOOD_GRP = 0
    GOOD_HIGH_GRP_VAL = 0

    def setUp(self):
        self.GOOD_SSN = '526-33-4563'
        self.GOOD_GRP = 33
        self.GOOD_HIGH_GRP_VAL = 99

   def testSSNValidation(self):
        """Tests the algorithm in the validator against
            known high values for the first three digits

           Validate a Social Security Number (SSN). A valid SSN
            is determined by the following rules according to the
            website http://www.ssa.gov/employer/ssnweb.htm

           Area-Group-Serial (AAA-GG-SSSS) The Social Security
            number consists of nine (9) digits. The first three
            (3) digits denote the area (or State) where the application
            for an original Social Security number was filed.

           Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.

           Within each group, the serial numbers (last four (4) digits)
            run consecutively from 0001 through 9999.
           """
    def testSSNAlgorithm(self):
        bool=False
        ssn_v=self.GOOD_SSN.translate(None,'-')
        ssn_v=ssn_v.strip()
        #print("SSN: %s" % (ssn_v))
        if (len(ssn_v)==9 and ssn_v.isdigit()):
            #print("SSN passed for length and digits: %s" % (ssn_v))
            key_v = ssn_v[3:5]
            if ssn_v[0:3] in VALID_SSN_AREAS:
                hg_v = SSN_HIGH_VALUES[ssn_v[0:3]]
                #check for valid group for Area ID in private method
                bool = self.__isGroupValid(int(key_v), int(hg_v))
            #print("VALID_GROUP: %s" % (bool))
        self.assertTrue(bool)

    def testIsValidSSN(self):
        validator = ValidationFormulas()
        self.assertTrue(validator.isValidSSN(self.GOOD_SSN))
        long_ssn = "   %s   " % (self.GOOD_SSN)
        self.assertTrue(validator.isValidSSN(long_ssn))
        stripped_ssn = self.GOOD_SSN.translate(None,'-')
        self.assertTrue(validator.isValidSSN(stripped_ssn))
        for bad_ssn in INVALID_SSN_NUMBERS:
            self.assertFalse(validator.isValidSSN(bad_ssn))
        bad_ssn = "742-51-1234"
        self.assertFalse(validator.isValidSSN(bad_ssn))

    def testGroupValidAlgorithm(self):
        self.assertTrue(self.__isGroupValid(self.GOOD_GRP,self.GOOD_HIGH_GRP_VAL))

    def testShowSSNAreas(self):
        self.assertEqual(len(SSN_HIGH_VALUES.keys()), len(VALID_SSN_AREAS))

    #-----------------Private Functions-------------------------------------------

def __isSSNGroupValid(self,group,groupHighestValue):

        """Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.
            """
        validGroup = False
        moduloGroupNumber = group % 2
        moduloGroupHighest = groupHighestValue % 2

        if ((moduloGroupHighest == 1) & (groupHighestValue >= 1) & (groupHighestValue <= 9)):
            if ((moduloGroupNumber == 1) & (group >= 1) & (group <= groupHighestValue)):
                validGroup = True

        elif ((moduloGroupHighest == 0) & (groupHighestValue >= 10) & (groupHighestValue <= 98)):
            if (((moduloGroupNumber == 1) & (group >= 1) & (group <= 9))
            | ((moduloGroupNumber == 0) & (group >= 10) & (group <= groupHighestValue))):
                validGroup = True

        elif ((moduloGroupHighest == 0) & (groupHighestValue >= 2) & (groupHighestValue <= 8)):
            if (((moduloGroupNumber == 1) & (group >= 1) & (group <= 9))
            | ((moduloGroupNumber == 0) & (group >= 10)
            & (group <= 98))
            | ((moduloGroupNumber == 0) & (group >= 2)
            & (group <= groupHighestValue))):
                validGroup = True

        elif ((moduloGroupHighest == 1) & (groupHighestValue >= 11) & (groupHighestValue <= 99)):
            if (((moduloGroupNumber == 1) & (group >= 1) & (group <= 9))
            | ((moduloGroupNumber == 0) & (group >= 10)
            & (group <= 98))
            | ((moduloGroupNumber == 0) & (group >= 2)
            & (group <= 8))
            | ((moduloGroupNumber == 1) & (group >= 11)
            & (group <= groupHighestValue))):
                validGroup = True

        return validGroup

The next methods test and retest the algorithms, ensuring that bad numbers, numbers with white space and invalid numbers also return False for their tests. More comprehensive tests can and should be written before this code goes into production, but there is now the basis for an implementation and transfer of our "test" code to validation_formulas.py

The Implementation

The implementation is almost "cut and paste" from the test at this point. The private method is a complete clone, and the public validation method just changes a few things around to get the right information. This particular implementation is somewhat basic, since it only returns True or False with the number submitted -- it doesn't tell the requestor exactly what happened, just that the number submitted is good or bad. More sophistication can be added by returning pointers towards messages, then assigning a pointer for each test that fails. A test with no failure could return a "zero", and after that messages could pile up.

This is a good strategy for any sophisticated validation system, since there are few hard-core validations that need to have a binary response -- it is more important to have some "why" answers with a failed validation, and in some cases, validations may not "fail" in a particular manner. One example of a "gray area" in validation would be in profanity filters. Some lexicon may be quite profane to a particular user, where another may not. In these particular cases, a "score" might be returned for verification instead of a binary. Another case would be in Address fields -- ones that don't have a number followed by string of letters may not be a real address, but there are outliers that need to be covered...

validation_formulas.py
#!/usr/bin/env python
# encoding: utf-8
"""
validation_formulas.py
Created by Danilo Gurovich on 2010-03-19.
"""
from finvs.utils.ssn_constants import *

class ValidationFormulas:

    #Validates Social Security Number
    def isValidSSN(self,ssn_str):
        """Validate a Social Security Number (SSN). A valid SSN
            is determined by the following rules according to the
            website http://www.ssa.gov/employer/ssnweb.htm

           Area-Group-Serial (AAA-GG-SSSS) The Social Security
            number consists of nine (9) digits. The first three
            (3) digits denote the area (or State) where the application
            for an original Social Security number was filed.

           Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.

           Within each group, the serial numbers (last four (4) digits)
            run consecutively from 0001 through 9999.
           """
        isValid=False
        #strip all the dashes and whitespace
        ssn_v=ssn_str.translate(None,'-')
        ssn_v=ssn_v.strip()
        #Check length and ensure that it's a digit
        if (len(ssn_v)==9 and ssn_v.isdigit()):
            #print("SSN passed for length and digits: %s" % (ssn_v))
            #Check to ensure that it's not an invalid number
            if(ssn_v not in INVALID_SSN_NUMBERS):
                key_v = ssn_v[3:5]
                if ssn_v[0:3] in VALID_SSN_AREAS:
                    hg_v = SSN_HIGH_VALUES[ssn_v[0:3]]
                    #check for valid group for Area ID in private method
                    isValid = self.__isSSNGroupValid(int(key_v), int(hg_v))

        return isValid

    #---------- Private Functions -------------------------------------------------------

def __isSSNGroupValid(self,group,groupHighestValue):

        """Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.
            """
        validGroup = False
        moduloGroupNumber = group % 2
        moduloGroupHighest = groupHighestValue % 2

        if ((moduloGroupHighest == 1) & (groupHighestValue >= 1) & (groupHighestValue <= 9)):
            if ((moduloGroupNumber == 1) & (group >= 1) & (group <= groupHighestValue)):
                validGroup = True

        elif ((moduloGroupHighest == 0) & (groupHighestValue >= 10) & (groupHighestValue <= 98)):
            if (((moduloGroupNumber == 1) & (group >= 1) & (group <= 9))
            | ((moduloGroupNumber == 0) & (group >= 10) & (group <= groupHighestValue))):
                validGroup = True

        elif ((moduloGroupHighest == 0) & (groupHighestValue >= 2) & (groupHighestValue <= 8)):
            if (((moduloGroupNumber == 1) & (group >= 1) & (group <= 9))
            | ((moduloGroupNumber == 0) & (group >= 10)
            & (group <= 98))
            | ((moduloGroupNumber == 0) & (group >= 2)
            & (group <= groupHighestValue))):
                validGroup = True

        elif ((moduloGroupHighest == 1) & (groupHighestValue >= 11) & (groupHighestValue <= 99)):
            if (((moduloGroupNumber == 1) & (group >= 1) & (group <= 9))
            | ((moduloGroupNumber == 0) & (group >= 10)
            & (group <= 98))
            | ((moduloGroupNumber == 0) & (group >= 2)
            & (group <= 8))
            | ((moduloGroupNumber == 1) & (group >= 11)
            & (group <= groupHighestValue))):
                validGroup = True

        return validGroup

Why is this Cool?

This whole way of developing code is cool because I don't need to fire up the server and drill through a bunch of pages to find out if I had "done it right". In fact, I haven't even wrote the service that I want to connect to, and I haven't even filled out the model in the application that I'm working in. I'm just doing one piece at a time, then building the model and service once I have everything ironed out. I'll have super-duper test coverage without writing my code twice, and really have confidence in the entire back-end as I build the view and controller modules out, buying plenty of time to optimize, refactor and work everything into some nice design patterns (Strategy, anyone?)

Free PDF    Send article as PDF   

Leave a Reply

Bad Behavior has blocked 217 access attempts in the last 7 days.