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.

D3e3f4ac37c02289f5dfed115949fc88?s=128

John Kary

April 02, 2014
Tweet

Transcript

  1. 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. 3.

    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. 4.
  4. 5.
  5. 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');
 
 $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
  6. 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');
 
 $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
  7. 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->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. 11.

    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
  9. 12.

    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
  10. 13.

    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
  11. 14.

    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
  12. 15.

    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
  13. 16.

    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. 17.

    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
  15. 18.

    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
  16. 19.

    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
  17. 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->setMinBallsPerBucket(0);
 $this->dist->setMinBucketsPerBall(0); ! $this->dist->run();
 
 $results = $this->dist->getResults();
 $expected = array(
 'a' => array('200'),
 );
 
 $this->assertEquals($expected, $results);
 }
 } TEST
  18. 21.

    class BucketBallDistribution
 {
 private $bucketIds = array();
 private $ballIds =

    array();
 
 private $minBallsPerBucket = 0;
 private $minBucketsPerBall = 0; ! // ... } CLASS
  19. 22.

    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
  20. 23.

    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. 24.

    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
  22. 25.

    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
  23. 26.

    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
  24. 27.
  25. 31.
  26. 32.

    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
  27. 33.
  28. 35.

    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
  29. 36.

    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
  30. 37.

    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
  31. 39.

    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
  32. 40.

    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
  33. 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()
 
 // 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
  34. 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
  35. 43.

    Smell! ! When an object's public methods must be invoked


    in a specific order to properly use it
  36. 45.

    An object should be ! ready to use and impossible

    to misuse! ! after it has been instantiated Object Instantiation Rules
  37. 46.

    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
  38. 47.

    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
  39. 48.

    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
  40. 49.

    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
  41. 50.

    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);
 }
 }
  42. 51.

    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);
 }

  43. 52.

    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);
 }

  44. 53.

    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);
 }

  45. 54.

    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);
 }
 }
  46. 55.

    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
  47. 56.

    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
  48. 57.

    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
  49. 58.

    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
  50. 59.

    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
  51. 60.

    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
  52. 61.

    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
  53. 63.

    An object’s configuration should not change after instantiation If you

    need a different configuration create another instance API Design Principles
  54. 64.

    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
  55. 65.

    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
  56. 66.
  57. 67.

    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
  58. 68.

    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
  59. 69.

    Do not expose getters for values you don’t use yset

    Do not expose getters for configuration API Design Principles
  60. 70.

    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
  61. 71.

    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
  62. 72.

    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
  63. 73.
  64. 74.

    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. 75.

    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. 76.

    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
  67. 77.

    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
  68. 78.

    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. 81.

    Class and Methods Principles STATELESS Do not store data during

    execution DETERMINISTIC Given the same input, the return value is identical
  70. 82.

    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
  71. 83.

    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);
 }
 }
  72. 84.

    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);
 }
 }
  73. 85.

    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);
 } }
  74. 86.

    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);
 } }
  75. 87.

    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
  76. 88.

    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
  77. 89.

    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
  78. 90.

    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
  79. 91.

    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
  80. 92.

    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
  81. 93.

    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
  82. 94.

    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
  83. 95.

    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
  84. 96.

    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
  85. 97.

    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
  86. 98.
  87. 99.

    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
  88. 100.

    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
  89. 101.

    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
  90. 102.

    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
  91. 103.
  92. 104.

    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 

  93. 105.

    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