Clean Code in Small Companies Stock photo, not actual developer - - PowerPoint PPT Presentation

clean code in small companies stock photo not actual
SMART_READER_LITE
LIVE PREVIEW

Clean Code in Small Companies Stock photo, not actual developer - - PowerPoint PPT Presentation

Clean Code in Small Companies Stock photo, not actual developer Stock photo, not actual developer Stock photo, not actual developer Robert C. Martin Uncle Bob 1. Reading code is hard 1. Reading code is hard 2. We all have to read code


slide-1
SLIDE 1

Clean Code in Small Companies

slide-2
SLIDE 2
slide-3
SLIDE 3

Stock photo, not actual developer

slide-4
SLIDE 4

Stock photo, not actual developer

slide-5
SLIDE 5
slide-6
SLIDE 6

Stock photo, not actual developer

slide-7
SLIDE 7

Robert C. Martin

“Uncle Bob”

slide-8
SLIDE 8
slide-9
SLIDE 9
  • 1. Reading code is hard
slide-10
SLIDE 10
  • 1. Reading code is hard
  • 2. We all have to read code
slide-11
SLIDE 11
  • 1. Reading code is hard
  • 2. We all have to read code
  • 3. Surprises are bad
slide-12
SLIDE 12

Code in these Slides

slide-13
SLIDE 13

$iAmAVariable

slide-14
SLIDE 14

class UserController extends Controller { } Class name Parent class name

slide-15
SLIDE 15

class UserController extends Controller { private $memberVariable; } Access modifier

slide-16
SLIDE 16

class UserController extends Controller { public function someMethod( Request $request ) { } } Method name Parameter type hint

slide-17
SLIDE 17

https://pasztor.at

slide-18
SLIDE 18

A few words on testing...

More on this later

slide-19
SLIDE 19

class UserController { public function __construct( UserBusinessLogic $userBusinessLogic ) { } }

slide-20
SLIDE 20

function testRegistration() { }

slide-21
SLIDE 21

function testRegistration() { $userBusinessLogic = new UserBusinessLogicFake(); }

slide-22
SLIDE 22

function testRegistration() { $userBusinessLogic = new UserBusinessLogicFake(); $userController = new UserController( $userBusinessLogic ); }

slide-23
SLIDE 23

function testRegistration() { $userBusinessLogic = new UserBusinessLogicFake(); $userController = new UserController( $userBusinessLogic ); //Test the user controller }

slide-24
SLIDE 24

Dependency Injection

Don’t look for things!

slide-25
SLIDE 25

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( $this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')

) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-26
SLIDE 26

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( $this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')

) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-27
SLIDE 27

$this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')
slide-28
SLIDE 28

$this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')
slide-29
SLIDE 29

$this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')
slide-30
SLIDE 30

$this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')
slide-31
SLIDE 31

UserController

slide-32
SLIDE 32

UserController Magic?

slide-33
SLIDE 33

UserController Magic? security.authorization_checker

slide-34
SLIDE 34
slide-35
SLIDE 35

class UserController extends Controller { }

slide-36
SLIDE 36

class UserController extends Controller { }

slide-37
SLIDE 37

class UserController { public function __construct( ) { } }

slide-38
SLIDE 38

class UserController { public function __construct( SecurityAuthorizationChecker $securityAuthorizationChecker ) { } }

slide-39
SLIDE 39

class UserController { private $securityAuthorizationChecker; public function __construct( SecurityAuthorizationChecker $securityAuthorizationChecker ) { $this->securityAuthorizationChecker = $securityAuthorizationChecker ; } }

slide-40
SLIDE 40

class UserController { private $securityAuthorizationChecker; public function __construct( SecurityAuthorizationChecker $securityAuthorizationChecker ) { $this-> securityAuthorizationChecker = $securityAuthorizationChecker; } /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ($this->securityAuthorizationChecker->isGranted('ROLE_SUPER_ADMIN')) { return $this->redirectToRoute( 'admin_dashboard'); } } }

slide-41
SLIDE 41

class UserController { private $securityAuthorizationChecker; public function __construct( SecurityAuthorizationChecker $securityAuthorizationChecker ) { $this-> securityAuthorizationChecker = $securityAuthorizationChecker; } /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ($this->securityAuthorizationChecker->isGranted('ROLE_SUPER_ADMIN')) { return $this->redirectToRoute( 'admin_dashboard'); } } }

slide-42
SLIDE 42

Dependency Injectors

Moving the Magic out of your Program

slide-43
SLIDE 43

UserController UserBusinessLogic UserStorage

slide-44
SLIDE 44

class UserController { public function __construct( UserBusinessLogic $userBusinessLogic ) { } }

slide-45
SLIDE 45

class UserController { public function __construct( UserBusinessLogic $userBusinessLogic ) { } } class UserBusinessLogic { public function __construct( UserStorage $userStorage ) { } }

slide-46
SLIDE 46

class UserController { public function __construct( UserBusinessLogic $userBusinessLogic ) { } } class UserBusinessLogic { public function __construct( UserStorage $userStorage ) { } } class UserStorage { }

slide-47
SLIDE 47

$uc = new UserController( new UserBusinessLogic( new UserStorage() ) );

slide-48
SLIDE 48

$injector = new Injector();

slide-49
SLIDE 49

$injector = new Injector(); $uc = $injector->make(UserController::class);

slide-50
SLIDE 50

class MySQLConnection { public function __construct( string $server, string $username, string $password, string $db ) { } }

slide-51
SLIDE 51

$injector->define(MySQLConnection::class, [ 'server' => 'localhost', 'user' => 'root', 'password' => 'changeme', 'db' => 'app' ]);

slide-52
SLIDE 52
  • PHP: Auryn, Laravel Service Container, Symfony Service

Container

  • Java: Gource, Dagger, Dagger2, Opsbears Web Components

DIC

  • Python: dependency_injector
  • Javascript: InversifyJS
slide-53
SLIDE 53

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( $this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')

) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-54
SLIDE 54

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( $this->container

  • >get('security.authorization_checker')
  • >isGranted('ROLE_SUPER_ADMIN')

) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-55
SLIDE 55

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( $this->injector

  • >make(SecurityAuthorizationChecker::class)
  • >isGranted('ROLE_SUPER_ADMIN')

) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-56
SLIDE 56

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( $this->injector

  • >make(SecurityAuthorizationChecker::class)
  • >isGranted('ROLE_SUPER_ADMIN')

) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-57
SLIDE 57

Static Function Calls

Might Be Bad For Your Code Quality

slide-58
SLIDE 58

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( $this->injector

  • >make(SecurityAuthorizationChecker::class)
  • >isGranted('ROLE_SUPER_ADMIN')

) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-59
SLIDE 59

class UserController extends Controller { /** * @Route("/user/account", name="user_account") */ public function accountAction(Request $request) { if ( SecurityAuthorizationChecker ::isGranted('ROLE_SUPER_ADMIN') ) { return $this->redirectToRoute('admin_dashboard'); } // Other stuff here } }

slide-60
SLIDE 60

$uc = new UserController();

slide-61
SLIDE 61

Immutable Objects

Avoiding Surprises

slide-62
SLIDE 62

class User { private $id; public function setId($id) { $this->id = $id; } public function getId() { return $this->id; } }

slide-63
SLIDE 63

new User()

slide-64
SLIDE 64

class User { private $id; public function setId($id) { $this->id = $id; } public function getId() { return $this->id; } }

slide-65
SLIDE 65

class User { private $id; public function setId($id) { $this->id = $id; } public function getId() { return $this->id; } }

slide-66
SLIDE 66

class User { private $id; public function __construct($id) { $this->id = $id; } public function getId() { return $this->id; } }

slide-67
SLIDE 67

class UserStorage { private $users = []; public function store(User $user) { $this->users[$user->getId()] = $user; } }

slide-68
SLIDE 68

class UserStorage { private $users = []; public function store(User $user) { $this->users[$user->getId()] = $user; } public function retrieve($id) { if (isset($this->users[$id])) { return $this->users[$id]; } else { throw new UserNotFoundException($id); } } }

slide-69
SLIDE 69

Less Code in One Class

Your All-In-One Weightloss Program

slide-70
SLIDE 70

class UserController { public function register() {} public function search() {} public function get() {} public function update() {} public function delete() {} }

slide-71
SLIDE 71

Route::get( '/users', function ( ) { return 'User list'; } );

slide-72
SLIDE 72

Route::get( '/users', function ( UserBusinessLogic $userBusinessLogic ) { return 'User list'; } );

slide-73
SLIDE 73

class UserRegisterController { public function __construct( UserBusinessLogic $userBusinessLogic ) { } public function register() { } }

slide-74
SLIDE 74

Static Typing

Saves you from a **** ton of issues

slide-75
SLIDE 75

function search( $needle, $haystack ) { }

slide-76
SLIDE 76

function search( string $needle, array $haystack ) { }

slide-77
SLIDE 77

mypy

Python

builtin

Java

phpstan

PHP JavaScript

Typescript

slide-78
SLIDE 78

Strict Typing

Because your String is not an Integer

slide-79
SLIDE 79

<?php declare(strict_types=1);

PHP

slide-80
SLIDE 80

<?php declare(strict_types=1);

Typescript

PHP JavaScript

slide-81
SLIDE 81

Structuring your Code

Because your Code is not a Clown Car

slide-82
SLIDE 82

/controller UserRegisterController.php UserListController.php … /model /view

slide-83
SLIDE 83

/user /controller UserRegisterController.php UserListController.php … /business /storage /blog /controller /business /storage

slide-84
SLIDE 84

Testing

You test your code, right?

slide-85
SLIDE 85

Application

slide-86
SLIDE 86

User Interface

Application

slide-87
SLIDE 87

User Interface

Application

Test Code

slide-88
SLIDE 88

User Interface

Application

Database Connector Test Code

slide-89
SLIDE 89

User Interface

Application

Database Connector Test Database Test Code

slide-90
SLIDE 90

User Interface

Application

Database Connector Test Database Test Code

slide-91
SLIDE 91

Application

slide-92
SLIDE 92

Application

Test Code

slide-93
SLIDE 93

Application

Test Code Fake Database Connector

slide-94
SLIDE 94

Application

Test Code Fake Database Connector

slide-95
SLIDE 95

Test Code Fake Application User Interface

slide-96
SLIDE 96

function testGetShouldReturnUser(){ //region Setup $userStorage = new UserStorageFake(); $userStorage->backingStorage['test-user'] = UserFactory::create( "test-user", "Test User", "test@example.com", "*" ); $business = new UserGetBusinessLogicImpl($userStorage); //endregion //region Execute... //region Asset... }

slide-97
SLIDE 97

function testGetShouldReturnUser(){ //region Setup... //region Execute $user = $business->getById("test-user"); //endregion //region Assert assertEquals("test-user", $user->getId()); //endregion }

slide-98
SLIDE 98

Putting it together

Building an actual system

slide-99
SLIDE 99

Many thanks to: Cristina Laskar

slide-100
SLIDE 100
slide-101
SLIDE 101
slide-102
SLIDE 102
slide-103
SLIDE 103

API Business Logic Storage MySQL or HSQLDB Single Page Application

HTTP

slide-104
SLIDE 104

API Business Logic Storage DataMapper / ORM Routing / Object Decoding MySQL or HSQLDB Single Page Application

HTTP

slide-105
SLIDE 105
slide-106
SLIDE 106

Non-technical Ways

Customer Communication is Important

slide-107
SLIDE 107

UX design by @gogospaso

slide-108
SLIDE 108

More information

Because one talk is not enough

slide-109
SLIDE 109