Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Refactoring: Less Code, Less Problems (Part 1)

Refactoring: Less Code, Less Problems (Part 1)

Video of this talk: https://www.youtube.com/watch?v=PjHZFTbg6gg

John talks about guidelines and code smells for improving object API design. He takes an existing class and demonstrates refactoring it to a leaner more focused version of its previous self. Most importantly, what questions to ask yourself as you're writing new classes.

Pass 1 (and a future Part 2) will approach refactoring a class from the outside as opposed to the inside. We discuss topics like breaking apart bigger classes to make smaller classes that do one thing, programming without getters and setters, consistent entry/return points, and guidelines for object instantiation. This talk focuses less on in-function refactoring and more on API-level refactoring.

John Kary

April 02, 2014
Tweet

More Decks by John Kary

Other Decks in Technology

Transcript

  1. Less Code, Less Problems Pass 1(of 2) April 2, 2014


    Kansas City PHP User Group Slides: http://johnkary.net/talks John Kary Code Slinger, Build Breaker @johnkary
  2. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function setBucketIds($bucketIds){...}
 
 public function setBallIds($ballIds){...}
 
 public function setMinBallsPerBucket($count){...}
 
 public function setMinBucketsPerBall($count){...}
 
 public function run(){...}
 
 public function getResults(){...}
 
 public function getResultsByBall(){...}
 
 public function getMinBucketsPerBall(){...}
 
 public function getMinBallsPerBucket(){...}
 
 public function getBallPoolSize(){...}
 
 public function getStatusMessage(){...}
 
 public function createBallIdPool(){...}
 
 public function checkBallIdForBucketId($ballId, $bucketId){...}
 } CLASS
  3. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->bucketIds = array('a');
 $this->ballIds = array('200');
 
 $results = $this->runDistribution();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 
 // ...
 
 private function runDistribution() {
 $this->dist->setBucketIds($this->bucketIds);
 $this->dist->setBallIds($this->ballIds);
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall);
 
 $this->dist->run();
 
 return $this->dist->getResults();
 }
 } TEST
  4. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->bucketIds = array('a');
 $this->ballIds = array('200');
 
 $results = $this->runDistribution();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 
 // ...
 
 private function runDistribution() {
 $this->dist->setBucketIds($this->bucketIds);
 $this->dist->setBallIds($this->ballIds);
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall);
 
 $this->dist->run();
 
 return $this->dist->getResults();
 }
 } TEST
  5. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->bucketIds = array('a');
 $this->ballIds = array('200');
 
 $this->dist->setBucketIds($this->bucketIds);
 $this->dist->setBallIds($this->ballIds);
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  6. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->bucketIds = array('a');
 $this->ballIds = array('200');
 
 $this->dist->setBucketIds($this->bucketIds);
 $this->dist->setBallIds($this->ballIds);
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  7. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->bucketIds = array('a');
 $this->ballIds = array('200');
 
 $this->dist->setBucketIds($this->bucketIds);
 $this->dist->setBallIds($this->ballIds);
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  8. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->bucketIds = array('a');
 $this->ballIds = array('200');
 
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  9. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->bucketIds = array('a');
 $this->ballIds = array('200');
 
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  10. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $bucketIds;
 private $ballIds;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  11. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  12. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  13. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket($this->minBallsPerBucket);
 $this->dist->setMinBucketsPerBall($this->minBucketsPerBall); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  14. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket(0);
 $this->dist->setMinBucketsPerBall(0); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  15. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket(0);
 $this->dist->setMinBucketsPerBall(0); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  16. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0; ! // ... } CLASS
  17. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->setMinBallsPerBucket(0);
 $this->dist->setMinBucketsPerBall(0); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  18. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  19. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  20. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  21. use KCPHPUG\BucketBallDistribution;
 
 class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /** @var

    BucketBallDistribution */
 private $dist;
 
 protected function setUp() {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeOneBucketToOneApp() {
 $this->dist->setBucketIds(array('a'));
 $this->dist->setBallIds(array('200'));
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  22. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function setBucketIds($bucketIds){...}
 
 public function setBallIds($ballIds){...}
 
 public function setMinBallsPerBucket($count){...}
 
 public function setMinBucketsPerBall($count){...}
 
 public function run(){...}
 
 public function getResults(){...}
 
 public function getResultsByBall(){...}
 
 public function getMinBucketsPerBall(){...}
 
 public function getMinBallsPerBucket(){...}
 
 public function getBallPoolSize(){...}
 
 public function getStatusMessage(){...}
 
 public function createBallIdPool(){...}
 
 public function checkBallIdForBucketId($ballId, $bucketId){...}
 } CLASS
  23. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function setBucketIds($bucketIds){...}
 
 public function setBallIds($ballIds){...}
 
 public function setMinBallsPerBucket($count){...}
 
 public function setMinBucketsPerBall($count){...}
 
 public function run(){...}
 
 public function getResults(){...}
 
 public function getResultsByBall(){...}
 
 public function getMinBucketsPerBall(){...}
 
 public function getMinBallsPerBucket(){...}
 
 public function getBallPoolSize(){...}
 
 public function getStatusMessage(){...}
 
 public function createBallIdPool(){...}
 
 public function checkBallIdForBucketId($ballId, $bucketId){...}
 } CLASS
  24. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Inform runtime about various state
 public function createBallIdPool()
 public function getBallPoolSize()
 public function checkBallIdForBucketId($ballId, $bucketId)
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  25. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Inform runtime about various state
 public function createBallIdPool()
 public function getBallPoolSize()
 public function checkBallIdForBucketId($ballId, $bucketId)
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  26. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Inform runtime about various state
 public function createBallIdPool()
 public function getBallPoolSize()
 public function checkBallIdForBucketId($ballId, $bucketId)
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  27. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Inform runtime about various state
 public function createBallIdPool()
 public function getBallPoolSize()
 public function checkBallIdForBucketId($ballId, $bucketId)
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  28. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Inform runtime about various state
 private function createBallIdPool()
 private function getBallPoolSize()
 private function checkBallIdForBucketId($ballId, $bucketId)
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  29. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  30. Smell! ! When an object's public methods must be invoked


    in a specific order to properly use it
  31. An object should be ! ready to use and impossible

    to misuse! ! after it has been instantiated Object Instantiation Rules
  32. An object should be ! ready to use and impossible

    to misuse! ! after it has been instantiated Object Instantiation Rules Enforce required values in the constructor
  33. class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution
 */


    private $dist;
 
 protected function setUp()
 {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array('201','202','203','204','205','206','207','208' $this->dist->setMinBallsPerBucket(1);
 $this->dist->setMinBucketsPerBall(3);
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  34. class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution
 */


    private $dist;
 
 protected function setUp()
 {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array('201','202','203','204','205','206','207','208' $this->dist->setMinBallsPerBucket(1);
 $this->dist->setMinBucketsPerBall(3);
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  35. class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution
 */


    private $dist;
 
 protected function setUp()
 {
 $this->dist = new BucketBallDistribution();
 }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array('201','202','203','204','205','206','207','208' $this->dist->setMinBallsPerBucket(1);
 $this->dist->setMinBucketsPerBall(3);
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  36. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' $this->dist->setMinBallsPerBucket(1);
 $this->dist->setMinBucketsPerBall(3);
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 }
  37. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' $this->dist->setMinBallsPerBucket(1);
 $this->dist->setMinBucketsPerBall(3);
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }

  38. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' $this->dist->setMinBallsPerBucket(1);
 $this->dist->setMinBucketsPerBall(3);
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }

  39. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' $this->dist->setMinBallsPerBucket(1);
 $this->dist->setMinBucketsPerBall(3);
 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }

  40. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 }
  41. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  42. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  43. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 CLASS
  44. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 CLASS
  45. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 CLASS
  46. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 CLASS
  47. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 CLASS
  48. An object’s configuration should not change after instantiation If you

    need a different configuration create another instance API Design Principles
  49. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Set Configuration
 public function setMinBucketsPerBall($count)
 public function setMinBallsPerBucket($count)
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 CLASS
  50. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall() ! // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  51. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  52. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 } ! // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  53. Do not expose getters for values you don’t use yset

    Do not expose getters for configuration API Design Principles
  54. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 }
 
 // Get Configuration (but based on runtime data?)
 public function getMinBallsPerBucket()
 public function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  55. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 }
 
 // Get Configuration (but based on runtime data?)
 private function getMinBallsPerBucket()
 private function getMinBucketsPerBall()
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  56. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 // Set Configuration
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0) $this->minBucketsPerBall = $minBucketsPerBall; $this->minBallsPerBucket = $minBallsPerBucket;
 }
 
 // Set runtime data
 public function setBucketIds($bucketIds)
 public function setBallIds($ballIds)
 
 // Main runtime algorithm
 public function run()
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage()
 }
 CLASS
  57. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 }
  58. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 }
  59. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run() {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  60. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run() {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  61. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run() {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  62. Class and Methods Principles STATELESS Do not store data during

    execution DETERMINISTIC Given the same input, the return value is identical
  63. Class and Methods Principles STATELESS Do not store data during

    execution IDEMPOTENT Given the same input, the state of the system is identical when the method completes DETERMINISTIC Given the same input, the return value is identical
  64. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 }
  65. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3()
 {
 $this->build(3, 1);
 
 $this->dist->setBucketIds(array('a','b','c','d'));
 $this->dist->setBallIds(array(‘201','202','203','204','205','206','207','208' 
 $results = $this->dist->run();
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 }
 }
  66. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3() {
 $this->build(3, 1);
 
 $bucketIds = array('a', 'b', 'c', 'd');
 $ballIds = array('201', '202', '203', '204', '205', '206', '207', '208', '209 
 $results = $this->dist->run($bucketIds, $ballIds);
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 } }
  67. TEST class BucketBallDistributionTest extends \PHPUnit_Framework_TestCase
 {
 /**
 * @var BucketBallDistribution


    */
 private $dist;
 
 protected function build($minBucketsPerBall = 0, $minBallsPerBucket = 0)
 {
 $this->dist = new BucketBallDistribution($minBucketsPerBall, $minBallsPerBuck }
 
 public function testDistributeManyBucketToManyAppsLimit3() {
 $this->build(3, 1);
 
 $bucketIds = array('a', 'b', 'c', 'd');
 $ballIds = array('201', '202', '203', '204', '205', '206', '207', '208', '209 
 $results = $this->dist->run($bucketIds, $ballIds);
 $expected = array(
 'a' => array('201','205','209','203','207','204','208'),
 'b' => array('202','206','210','204','208','201','205','209'),
 'c' => array('203','207','201','205','209','202','206','210'),
 'd' => array('204','208','202','206','210','203','207'),
 );
 
 $this->assertEquals($expected, $results);
 } }
  68. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run() {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  69. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run() {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  70. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  71. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  72. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($bucketIds, $ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  73. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! public function setBucketIds(array $bucketIds) {
 $this->bucketIds = $bucketIds;
 } ! public function setBallIds(array $ballIds) {
 $this->ballIds = $ballIds;
 }
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($bucketIds, $ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  74. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall; private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! ! ! ! ! ! ! 
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($bucketIds, $ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  75. class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall; private $ballPool =

    array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! ! ! ! ! ! ! 
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($bucketIds, $ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  76. class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall; private $ballPool =

    array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! ! ! ! ! ! ! 
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($bucketIds, $ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  77. class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall; private $ballPool =

    array();
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! ! ! ! ! ! ! 
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($bucketIds, $ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  78. class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $results =

    array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){} ! ! ! ! ! ! ! 
 
 public function run(array $bucketIds, array $ballIds) {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($bucketIds, $ballIds); while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  79. class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $results =

    array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){ 
 // Main runtime algorithm
 public function run(array $bucketIds, array $ballIds)
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage(array $bucketIds, array $ballIds)
 }
 CLASS
  80. class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $results =

    array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){ 
 // Main runtime algorithm
 public function run(array $bucketIds, array $ballIds)
 
 // Get results after runtime
 public function getResults()
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage(array $bucketIds, array $ballIds)
 }
 CLASS
  81. class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 
 public function getResults() {
 return $this->results;
 } ! public function run() {
 $this->results = array();
 $this->resultsByBall = array();
 
 $ballPool = $this->createBallIdPool($this->bucketIds, $this->ballI while ($ballPool ...) {
 // ...
 $this->results[$bucketId][] = $ballId;
 // ...
 }
 
 return $this->results;
 } } CLASS
  82. class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $results =

    array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall = 0, $minBallsPerBucket = 0){ 
 // Main runtime algorithm
 public function run(array $bucketIds, array $ballIds)
 
 // Get results after runtime
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage(array $bucketIds, array $ballIds)
 }
 CLASS
  83. ass BucketBallDistribution
 private $bucketIds = array();
 private $ballIds = array();


    private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0;
 private $ballPool = array();
 private $results = array();
 private $resultsByBall = array();
 public function setBucketIds($bucketIds){...}
 public function setBallIds($ballIds){...}
 public function setMinBallsPerBucket($count){...}
 public function setMinBucketsPerBall($count){...}
 public function run(){...}
 public function getResults(){...}
 public function getResultsByBall(){...}
 public function getMinBucketsPerBall(){...}
 public function getMinBallsPerBucket(){...}
 public function getBallPoolSize(){...}
 public function getStatusMessage(){...}
 public function createBallIdPool(){...}
 public function checkBallIdForBucketId($ballId, $bucketId){...}
 class BucketBallDistribution
 {
 private $minBallsPerBucket;
 private $minBucketsPerBall;
 private $results = array();
 private $resultsByBall = array();
 
 public function __construct($minBucketsPerBall 
 // Main runtime algorithm
 public function run(array $bucketIds, array $ba 
 // Get results after runtime
 public function getResultsByBall()
 
 // Text describing results
 public function getStatusMessage(array $bucketI 

  84. Further Learning Refactoring: Improving the Design of Existing Code
 Martin

    Fowler, 2000 http://refactoring.com Less: The Path to Better Design
 Sandi Metz (GoRuCo 2011) http://vimeo.com/26330100 Therapeutic Refactoring
 Katrina Owen (2012) http://www.youtube.com/watch?v=J4dlF0kcThQ