Top Banner
MIN-MAXING Software Costs Konstantin K. @everzet
96

Min-Maxing Software Costs

Apr 16, 2017

Download

Technology

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Min-Maxing Software Costs

MIN-MAXINGSoftware Costs

Konstantin K.@everzet

Page 2: Min-Maxing Software Costs

TECHNICALDEBT

Page 3: Min-Maxing Software Costs

Without frameworks

Simple frameworks

Enterprise frameworks

Page 4: Min-Maxing Software Costs

IS MESSPART OF

A COURSE?

Page 5: Min-Maxing Software Costs

MIN-MAXING SOFTWARE COSTS

Page 6: Min-Maxing Software Costs

SOFTWARE FORCES

• Creation - Introduction of a brand new feature

• Change - Business-driven modification of existing feature

• Ownership - Physical capability to change a feature

• Control - Capability to sustainably change a feature

Page 7: Min-Maxing Software Costs

SOFTWARE COSTS

1. Cost of Creation

2. Cost of Change

3. Cost of Control

Page 8: Min-Maxing Software Costs

COST OF CREATION

Page 9: Min-Maxing Software Costs

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation

Page 10: Min-Maxing Software Costs

CONVENTIONS OPTIMISE

FOR CREATION

Page 11: Min-Maxing Software Costs

$ bin/rails generate controller welcome index

Page 12: Min-Maxing Software Costs

from django.contrib import admin

from . import models

admin.site.register(models.Article)

Page 13: Min-Maxing Software Costs

package hello;

import java.util.concurrent.atomic.AtomicLong; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;

@RestController public class GreetingController { ... }

Page 14: Min-Maxing Software Costs

CREATIONIS LIMITED BYTHE LIFE SPAN

Page 15: Min-Maxing Software Costs

Creation→ Change

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation

Page 16: Min-Maxing Software Costs

Creation→ Change

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation

Pure observation &personal experience

Page 17: Min-Maxing Software Costs

Creation→ Change

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation

Conventional Project

Page 18: Min-Maxing Software Costs

Creation→ Change

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation

Conventional Project

Conventional Project

Page 19: Min-Maxing Software Costs

Convention-based projects either die a hero or live long enough to see themselves become the villain.

Page 20: Min-Maxing Software Costs

COST OF CHANGE

Page 21: Min-Maxing Software Costs

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change

Page 22: Min-Maxing Software Costs

THE SEARCHFUNCTION

Page 23: Min-Maxing Software Costs

public function searchAction(Request $req) { $form = $this->createForm(new SearchQueryType, new SearchQuery); $normalizedOrderBys = $this->getNormalizedOrderBys($filteredOrderBys); $this->computeSearchQuery($req, $filteredOrderBys); if ($req->query->has('search_query')) { /** @var $solarium \Solarium_Client */ $solarium = $this->get('solarium.client'); $select = $solarium->createSelect(); // configure dismax $dismax = $select->getDisMax(); $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2')); if ($req->query->has('search_query')) { $form->bind($req); if ($form->isValid()) { $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery()); $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery); $escapedQuery = preg_replace('/(^| )\\\\\+(\S)/', '$1+$2', $escapedQuery); if ((substr_count($escapedQuery, '"') % 2) == 0) { $escapedQuery = str_replace('\\"', '"', $escapedQuery); } $select->setQuery($escapedQuery); } } } elseif ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'error' => 'Missing search query, example: ?q=example' ), 400)->setCallback($req->query->get('callback')); } return $this->render('SomeAppWebBundle:Web:search.html.twig'); }

Page 24: Min-Maxing Software Costs

public function searchAction(Request $req) { $form = $this->createForm(new SearchQueryType, new SearchQuery); $normalizedOrderBys = $this->getNormalizedOrderBys($filteredOrderBys); $this->computeSearchQuery($req, $filteredOrderBys); if ($req->query->has('search_query')) { /** @var $solarium \Solarium_Client */ $solarium = $this->get('solarium.client'); $select = $solarium->createSelect(); // configure dismax $dismax = $select->getDisMax(); $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2')); if ($req->query->has('search_query')) { $form->bind($req); if ($form->isValid()) { $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery()); $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery); $escapedQuery = preg_replace('/(^| )\\\\\+(\S)/', '$1+$2', $escapedQuery); if ((substr_count($escapedQuery, '"') % 2) == 0) { $escapedQuery = str_replace('\\"', '"', $escapedQuery); } $select->setQuery($escapedQuery); } } } elseif ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'error' => 'Missing search query, example: ?q=example' ), 400)->setCallback($req->query->get('callback')); } return $this->render('SomeAppWebBundle:Web:search.html.twig'); }

Page 25: Min-Maxing Software Costs

HOW LONG WOULDIT TAKE TO ADD TAGS

SUPPORT?

Page 26: Min-Maxing Software Costs

public function searchAction(Request $req) { $form = $this->createForm(new SearchQueryType, new SearchQuery); $normalizedOrderBys = $this->getNormalizedOrderBys($filteredOrderBys); $this->computeSearchQuery($req, $filteredOrderBys); if ($req->query->has('search_query')) { /** @var $solarium \Solarium_Client */ $solarium = $this->get('solarium.client'); $select = $solarium->createSelect(); // configure dismax $dismax = $select->getDisMax(); $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2')); if ($req->query->has('search_query')) { $form->bind($req); if ($form->isValid()) { $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery()); $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery); $escapedQuery = preg_replace('/(^| )\\\\\+(\S)/', '$1+$2', $escapedQuery); if ((substr_count($escapedQuery, '"') % 2) == 0) { $escapedQuery = str_replace('\\"', '"', $escapedQuery); } $select->setQuery($escapedQuery); } } } elseif ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'error' => 'Missing search query, example: ?q=example' ), 400)->setCallback($req->query->get('callback')); } return $this->render('SomeAppWebBundle:Web:search.html.twig'); }

Page 27: Min-Maxing Software Costs

public function searchAction(Request $req) { $form = $this->createForm(new SearchQueryType, new SearchQuery); $this->computeSearchQuery($req, $filteredOrderBys); $typeFilter = $req->query->get('type'); if ($req->query->has('search_query') || $typeFilter) { /** @var $solarium \Solarium_Client */ $solarium = $this->get('solarium.client'); $select = $solarium->createSelect(); // configure dismax $dismax = $select->getDisMax(); $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2')); $dismax->setPhraseFields(array('description')); $dismax->setBoostFunctions(array('log(trendiness)^10')); $dismax->setMinimumMatch(1); $dismax->setQueryParser('edismax'); // filter by type if ($typeFilter) { $filterQueryTerm = sprintf('type:"%s"', $select->getHelper()->escapeTerm($typeFilter)); $filterQuery = $select->createFilterQuery('type')->setQuery($filterQueryTerm); $select->addFilterQuery($filterQuery); } if ($req->query->has('search_query')) { $form->bind($req); if ($form->isValid()) { $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery()); $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery); $escapedQuery = preg_replace('/(^| )\\\\\+(\S)/', '$1+$2', $escapedQuery); if ((substr_count($escapedQuery, '"') % 2) == 0) { $escapedQuery = str_replace('\\"', '"', $escapedQuery); } $select->setQuery($escapedQuery); } } $paginator = new Pagerfanta(new SolariumAdapter($solarium, $select)); $perPage = $req->query->getInt('per_page', 15); if ($perPage <= 0 || $perPage > 100) { if ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'status' => 'error', 'message' => 'The optional packages per_page parameter must be an integer between 1 and 100 (default: 15)', ), 400)->setCallback($req->query->get('callback')); } $perPage = max(0, min(100, $perPage)); } } elseif ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'error' => 'Missing search query, example: ?q=example' ), 400)->setCallback($req->query->get('callback')); } return $this->render('SomeAppWebBundle:Web:search.html.twig'); }

Page 28: Min-Maxing Software Costs

{ $form = $this->createForm(new SearchQueryType, new SearchQuery); $filteredOrderBys = $this->getFilteredOrderedBys($req); $normalizedOrderBys = $this->getNormalizedOrderBys($filteredOrderBys); $this->computeSearchQuery($req, $filteredOrderBys); $typeFilter = $req->query->get('type'); $tagsFilter = $req->query->get('tags'); if ($req->query->has('search_query') || $typeFilter || $tagsFilter) { /** @var $solarium \Solarium_Client */ $solarium = $this->get('solarium.client'); $select = $solarium->createSelect(); // configure dismax $dismax = $select->getDisMax(); $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2')); $dismax->setPhraseFields(array('description')); $dismax->setBoostFunctions(array('log(trendiness)^10')); $dismax->setMinimumMatch(1); $dismax->setQueryParser('edismax'); // filter by type if ($typeFilter) { $filterQueryTerm = sprintf('type:"%s"', $select->getHelper()->escapeTerm($typeFilter)); $filterQuery = $select->createFilterQuery('type')->setQuery($filterQueryTerm); $select->addFilterQuery($filterQuery); } // filter by tags if ($tagsFilter) { $tags = array(); foreach ((array) $tagsFilter as $tag) { $tags[] = $select->getHelper()->escapeTerm($tag); } $filterQueryTerm = sprintf('tags:("%s")', implode('" AND "', $tags)); $filterQuery = $select->createFilterQuery('tags')->setQuery($filterQueryTerm); $select->addFilterQuery($filterQuery); } if (!empty($filteredOrderBys)) { $select->addSorts($normalizedOrderBys); } if ($req->query->has('search_query')) { $form->bind($req); if ($form->isValid()) { $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery()); $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery); $escapedQuery = preg_replace('/(^| )\\\\\+(\S)/', '$1+$2', $escapedQuery); if ((substr_count($escapedQuery, '"') % 2) == 0) { $escapedQuery = str_replace('\\"', '"', $escapedQuery); } $select->setQuery($escapedQuery); } } $paginator = new Pagerfanta(new SolariumAdapter($solarium, $select)); $perPage = $req->query->getInt('per_page', 15); if ($perPage <= 0 || $perPage > 100) { if ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'status' => 'error', 'message' => 'The optional packages per_page parameter must be an integer between 1 and 100 (default: 15)', ), 400)->setCallback($req->query->get('callback')); } $perPage = max(0, min(100, $perPage)); } $paginator->setMaxPerPage($perPage); $paginator->setCurrentPage($req->query->get('page', 1), false, true); $metadata = array(); foreach ($paginator as $package) { if (is_numeric($package->id)) { $metadata['downloads'][$package->id] = $package->downloads; $metadata['favers'][$package->id] = $package->favers; } } if ($req->getRequestFormat() === 'json') { try { $result = array( 'results' => array(), 'total' => $paginator->getNbResults(), ); } catch (\Solarium_Client_HttpException $e) { return JsonResponse::create(array( 'status' => 'error', 'message' => 'Could not connect to the search server', ), 500)->setCallback($req->query->get('callback')); } return JsonResponse::create($result)->setCallback($req->query->get('callback')); } if ($req->isXmlHttpRequest()) { try { return $this->render('PackagistWebBundle:Web:search.html.twig', array( 'packages' => $paginator, 'meta' => $metadata, 'noLayout' => true, )); } catch (\Twig_Error_Runtime $e) { if (!$e->getPrevious() instanceof \Solarium_Client_HttpException) { throw $e; } return JsonResponse::create(array( 'status' => 'error', 'message' => 'Could not connect to the search server', ), 500)->setCallback($req->query->get('callback')); } } return $this->render('PackagistWebBundle:Web:search.html.twig', array( 'packages' => $paginator, 'meta' => $metadata, )); } elseif ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'error' => 'Missing search query, example: ?q=example' ), 400)->setCallback($req->query->get('callback')); } return $this->render('PackagistWebBundle:Web:search.html.twig'); }

Page 29: Min-Maxing Software Costs

{ $form = $this->createForm(new SearchQueryType, new SearchQuery); $filteredOrderBys = $this->getFilteredOrderedBys($req); $normalizedOrderBys = $this->getNormalizedOrderBys($filteredOrderBys); $this->computeSearchQuery($req, $filteredOrderBys); $typeFilter = $req->query->get('type'); $tagsFilter = $req->query->get('tags'); if ($req->query->has('search_query') || $typeFilter || $tagsFilter) { /** @var $solarium \Solarium_Client */ $solarium = $this->get('solarium.client'); $select = $solarium->createSelect(); // configure dismax $dismax = $select->getDisMax(); $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2')); $dismax->setPhraseFields(array('description')); $dismax->setBoostFunctions(array('log(trendiness)^10')); $dismax->setMinimumMatch(1); $dismax->setQueryParser('edismax'); // filter by type if ($typeFilter) { $filterQueryTerm = sprintf('type:"%s"', $select->getHelper()->escapeTerm($typeFilter)); $filterQuery = $select->createFilterQuery('type')->setQuery($filterQueryTerm); $select->addFilterQuery($filterQuery); } // filter by tags if ($tagsFilter) { $tags = array(); foreach ((array) $tagsFilter as $tag) { $tags[] = $select->getHelper()->escapeTerm($tag); } $filterQueryTerm = sprintf('tags:("%s")', implode('" AND "', $tags)); $filterQuery = $select->createFilterQuery('tags')->setQuery($filterQueryTerm); $select->addFilterQuery($filterQuery); } if (!empty($filteredOrderBys)) { $select->addSorts($normalizedOrderBys); } if ($req->query->has('search_query')) { $form->bind($req); if ($form->isValid()) { $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery()); $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery); $escapedQuery = preg_replace('/(^| )\\\\\+(\S)/', '$1+$2', $escapedQuery); if ((substr_count($escapedQuery, '"') % 2) == 0) { $escapedQuery = str_replace('\\"', '"', $escapedQuery); } $select->setQuery($escapedQuery); } } $paginator = new Pagerfanta(new SolariumAdapter($solarium, $select)); $perPage = $req->query->getInt('per_page', 15); if ($perPage <= 0 || $perPage > 100) { if ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'status' => 'error', 'message' => 'The optional packages per_page parameter must be an integer between 1 and 100 (default: 15)', ), 400)->setCallback($req->query->get('callback')); } $perPage = max(0, min(100, $perPage)); } $paginator->setMaxPerPage($perPage); $paginator->setCurrentPage($req->query->get('page', 1), false, true); $metadata = array(); foreach ($paginator as $package) { if (is_numeric($package->id)) { $metadata['downloads'][$package->id] = $package->downloads; $metadata['favers'][$package->id] = $package->favers; } } if ($req->getRequestFormat() === 'json') { try { $result = array( 'results' => array(), 'total' => $paginator->getNbResults(), ); } catch (\Solarium_Client_HttpException $e) { return JsonResponse::create(array( 'status' => 'error', 'message' => 'Could not connect to the search server', ), 500)->setCallback($req->query->get('callback')); } return JsonResponse::create($result)->setCallback($req->query->get('callback')); } if ($req->isXmlHttpRequest()) { try { return $this->render('PackagistWebBundle:Web:search.html.twig', array( 'packages' => $paginator, 'meta' => $metadata, 'noLayout' => true, )); } catch (\Twig_Error_Runtime $e) { if (!$e->getPrevious() instanceof \Solarium_Client_HttpException) { throw $e; } return JsonResponse::create(array( 'status' => 'error', 'message' => 'Could not connect to the search server', ), 500)->setCallback($req->query->get('callback')); } } return $this->render('PackagistWebBundle:Web:search.html.twig', array( 'packages' => $paginator, 'meta' => $metadata, )); } elseif ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'error' => 'Missing search query, example: ?q=example' ), 400)->setCallback($req->query->get('callback')); } return $this->render('PackagistWebBundle:Web:search.html.twig'); }

{ $form = $this->createForm(new SearchQueryType, new SearchQuery); $filteredOrderBys = $this->getFilteredOrderedBys($req); $normalizedOrderBys = $this->getNormalizedOrderBys($filteredOrderBys); $this->computeSearchQuery($req, $filteredOrderBys); $typeFilter = $req->query->get('type'); $tagsFilter = $req->query->get('tags'); if ($req->query->has('search_query') || $typeFilter || $tagsFilter) { /** @var $solarium \Solarium_Client */ $solarium = $this->get('solarium.client'); $select = $solarium->createSelect(); // configure dismax $dismax = $select->getDisMax(); $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2')); $dismax->setPhraseFields(array('description')); $dismax->setBoostFunctions(array('log(trendiness)^10')); $dismax->setMinimumMatch(1); $dismax->setQueryParser('edismax'); // filter by type if ($typeFilter) { $filterQueryTerm = sprintf('type:"%s"', $select->getHelper()->escapeTerm($typeFilter)); $filterQuery = $select->createFilterQuery('type')->setQuery($filterQueryTerm); $select->addFilterQuery($filterQuery); } // filter by tags if ($tagsFilter) { $tags = array(); foreach ((array) $tagsFilter as $tag) { $tags[] = $select->getHelper()->escapeTerm($tag); } $filterQueryTerm = sprintf('tags:("%s")', implode('" AND "', $tags)); $filterQuery = $select->createFilterQuery('tags')->setQuery($filterQueryTerm); $select->addFilterQuery($filterQuery); } if (!empty($filteredOrderBys)) { $select->addSorts($normalizedOrderBys); } if ($req->query->has('search_query')) { $form->bind($req); if ($form->isValid()) { $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery()); $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery); $escapedQuery = preg_replace('/(^| )\\\\\+(\S)/', '$1+$2', $escapedQuery); if ((substr_count($escapedQuery, '"') % 2) == 0) { $escapedQuery = str_replace('\\"', '"', $escapedQuery); } $select->setQuery($escapedQuery); } } $paginator = new Pagerfanta(new SolariumAdapter($solarium, $select)); $perPage = $req->query->getInt('per_page', 15); if ($perPage <= 0 || $perPage > 100) { if ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'status' => 'error', 'message' => 'The optional packages per_page parameter must be an integer between 1 and 100 (default: 15)', ), 400)->setCallback($req->query->get('callback')); } $perPage = max(0, min(100, $perPage)); } $paginator->setMaxPerPage($perPage); $paginator->setCurrentPage($req->query->get('page', 1), false, true); $metadata = array(); foreach ($paginator as $package) { if (is_numeric($package->id)) { $metadata['downloads'][$package->id] = $package->downloads; $metadata['favers'][$package->id] = $package->favers; } } if ($req->getRequestFormat() === 'json') { try { $result = array( 'results' => array(), 'total' => $paginator->getNbResults(), ); } catch (\Solarium_Client_HttpException $e) { return JsonResponse::create(array( 'status' => 'error', 'message' => 'Could not connect to the search server', ), 500)->setCallback($req->query->get('callback')); } return JsonResponse::create($result)->setCallback($req->query->get('callback')); } if ($req->isXmlHttpRequest()) { try { return $this->render('PackagistWebBundle:Web:search.html.twig', array( 'packages' => $paginator, 'meta' => $metadata, 'noLayout' => true, )); } catch (\Twig_Error_Runtime $e) { if (!$e->getPrevious() instanceof \Solarium_Client_HttpException) { throw $e; } return JsonResponse::create(array( 'status' => 'error', 'message' => 'Could not connect to the search server', ), 500)->setCallback($req->query->get('callback')); } } return $this->render('PackagistWebBundle:Web:search.html.twig', array( 'packages' => $paginator, 'meta' => $metadata, )); } elseif ($req->getRequestFormat() === 'json') { return JsonResponse::create(array( 'error' => 'Missing search query, example: ?q=example' ), 400)->setCallback($req->query->get('callback')); } return $this->render('PackagistWebBundle:Web:search.html.twig'); }

Page 30: Min-Maxing Software Costs

CHANGE KICKS IN AFTER

CREATION STOPS

Page 31: Min-Maxing Software Costs

Creation→ Change

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change

Page 32: Min-Maxing Software Costs

Creation→ Change

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change

Enterprise Project

Page 33: Min-Maxing Software Costs

Creation→ Change

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change

Enterprise Project

Enterprise Project

Page 34: Min-Maxing Software Costs

FORCE DYNAMICS

Page 35: Min-Maxing Software Costs

CONVENTION-BASED FRAMEWORK

Page 36: Min-Maxing Software Costs
Page 37: Min-Maxing Software Costs

Your first feature

Controlled Code

Page 38: Min-Maxing Software Costs

Controlled Code

Page 39: Min-Maxing Software Costs

Your second feature

Controlled Code

Page 40: Min-Maxing Software Costs

Controlled Code

Page 41: Min-Maxing Software Costs

Controlled Code

Page 42: Min-Maxing Software Costs

Delegated Code

The framework / library code

Controlled Code

Page 43: Min-Maxing Software Costs

Delegated Code Controlled Code

Page 44: Min-Maxing Software Costs

Delegated Code

Change

Controlled Code

Page 45: Min-Maxing Software Costs

Delegated Code

Change

Controlled Code

Page 46: Min-Maxing Software Costs

Delegated Code

Change

Controlled Code

Page 47: Min-Maxing Software Costs

Owned Code Delegated Code

Change

Controlled Code

Page 48: Min-Maxing Software Costs

Owned Code Delegated Code

Change

Controlled Code

Page 49: Min-Maxing Software Costs

Owned Code Delegated Code

Change

Controlled Code

Page 50: Min-Maxing Software Costs

Owned Code Delegated Code Controlled Code

Page 51: Min-Maxing Software Costs

Owned Code Controlled Code

Page 52: Min-Maxing Software Costs

– An engineer

“Ah, to hell with that!”

Page 53: Min-Maxing Software Costs

Owned Code

Page 54: Min-Maxing Software Costs

Owned Code

Change

Page 55: Min-Maxing Software Costs

Owned Code

Page 56: Min-Maxing Software Costs

ENTERPRISE FRAMEWORK

Page 57: Min-Maxing Software Costs
Page 58: Min-Maxing Software Costs

Controlled Code

Your first feature

Page 59: Min-Maxing Software Costs

Controlled Code

Page 60: Min-Maxing Software Costs

Controlled Code

Your second feature

Page 61: Min-Maxing Software Costs

Controlled Code

Page 62: Min-Maxing Software Costs

Controlled Code

Change

Page 63: Min-Maxing Software Costs

Controlled Code

Change

Page 64: Min-Maxing Software Costs

Controlled Code

Change

Page 65: Min-Maxing Software Costs

– A business person

“Why does it always take so long?”

Page 66: Min-Maxing Software Costs

Controlled CodeOwned Code

Change

Page 67: Min-Maxing Software Costs

Controlled CodeOwned Code

Change

Page 68: Min-Maxing Software Costs

Controlled CodeOwned Code

Change

Page 69: Min-Maxing Software Costs

Controlled CodeOwned Code

Page 70: Min-Maxing Software Costs

Owned Code

Page 71: Min-Maxing Software Costs

CONTROL HAS COST

Page 72: Min-Maxing Software Costs

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change Cost of Control

Page 73: Min-Maxing Software Costs

CONTROL IS A LIMITER FOR ACOST OF CHANGE

Page 74: Min-Maxing Software Costs

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change Cost of Control

Page 75: Min-Maxing Software Costs

CONTROLLINGTOO FEW TOO LATE

Page 76: Min-Maxing Software Costs

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change Cost of Control

Page 77: Min-Maxing Software Costs

CONTROLLINGTOO MUCH TOO EARLY

Page 78: Min-Maxing Software Costs

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change Cost of Control

Page 79: Min-Maxing Software Costs

OWNING MORE THAN YOU CONTROLIS UNSUSTAINABLE

Page 80: Min-Maxing Software Costs

CONTROLLING EVERYTHING

IS EXPENSIVE

Page 81: Min-Maxing Software Costs

MIN-MAXING SOFTWARE COSTS

Page 82: Min-Maxing Software Costs

4 RULES OF MIN-MAXING

1. Begin from owning nothing ( )

2. Take ownership reluctantly ( )

3. Control everything you own ( )

4. Continuously reassess your control ( )

Page 83: Min-Maxing Software Costs

HEALTHY YOUNG PROJECT

Owned Code Delegated Code Controlled Code

Page 84: Min-Maxing Software Costs

UNHEALTHY YOUNG PROJECT

Owned Code Delegated Code Controlled Code

Page 85: Min-Maxing Software Costs

UNHEALTHY YOUNG PROJECT

Owned Code Delegated Code Controlled Code

Page 86: Min-Maxing Software Costs

HEALTHY MATURE PROJECT

Owned Code Delegated Code Controlled Code

Page 87: Min-Maxing Software Costs

UNHEALTHY “MATURE” PROJECT

Owned Code Delegated Code Controlled Code

Page 88: Min-Maxing Software Costs

UNHEALTHY “MATURE” PROJECT

Owned Code Delegated Code Controlled Code

Page 89: Min-Maxing Software Costs

1. BEGINFROM OWNING

NOTHING

Page 90: Min-Maxing Software Costs

2. TAKEOWNERSHIP

RELUCTANTLY

Page 91: Min-Maxing Software Costs

3. CONTROLEVERYTHINGYOU OWN

Page 92: Min-Maxing Software Costs

4. CONTINUOUSLYREASSESS YOUR

CONTROL

Page 93: Min-Maxing Software Costs

Project Lifetime

Beginning 3 months 6 months 9 months ...

Cost of Creation Cost of Change Cost of Control

Page 94: Min-Maxing Software Costs

Control everything you write.Avoid writing anything.

Page 95: Min-Maxing Software Costs

Deliver business impact,not software.

Page 96: Min-Maxing Software Costs

THANK YOU FOR YOUR TIME!

Konstantin K.@everzet