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

Task Based UIs

Task Based UIs

PHP Benelux 2015 - Why do we organise our screens as grids, as if they were database tables? And why do we make forms that manipulate their records? Our user interfaces are very often based on the underlying database structure, while adding minimal value to the user’s workflow. A good user interface should not focus on data, grids or forms, but on the task at hand. It should show relevant state in order to make informed decisions. It should also guide the user to perform specific tasks. We will cover how we can make these tasks explicit in the user interface, but also how they can drive a whole architecture. In the end, a good user interface helps users achieve their goals.

0cab45c75f109eb044564efbd28af603?s=128

Stijn Vannieuwenhuyse

January 23, 2015
Tweet

Transcript

  1. TASK BASED UIS

  2. STIJN VANNIEUWENHUYSE @STIJNVNH

  3. THIS TALK IS NOT ABOUT UI DESIGN

  4. THIS TALK IS ABOUT SOFTWARE DESIGN

  5. None
  6. None
  7. None
  8. CRUD CREATE READ UPDATE DELETE

  9. None
  10. None
  11. None
  12. $ git push origin master To https://github.com/stivni/doodis.git ! [rejected] master

    -> master (non-fast-forward) error: failed to push some refs to 'https://github.com/stivni/doodis.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes (e.g. 'git pull') before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details.
  13. None
  14. None
  15. None
  16. None
  17. SOFTWARE SHOULD GUIDE ITS USERS THROUGH THE BUSINESS PROCESS

  18. SOFTWARE SHOULD DELIVER VALUE TO THE BUSINESS

  19. HOW?

  20. None
  21. None
  22. None
  23. $customer->moveTo( new Address( $street, $number, $zip, $city, $country ) );

    $order->pay(Money::EUR(100)); $order->checkout();
  24. None
  25. None
  26. COMMAND PATTERN

  27. File a bug Acknowledge a bug Decline a bug Describe

    a bug Categorize a bug Close a bug
  28. FileBug AcknowledgeBug DeclineBug DescribeBug CategorizeBug CloseBug

  29. class FileBug implements Command { private $id; private $description; public

    function __construct($id, $description) { //… } public function getId() { return $this->id; } public function getDescription() { return $this->description; } }
  30. class FileBugCommandHandler implements CommandHandler { private $bugRepository; public function __construct(BugRepository

    $bugRepository) { //… } public function handle(FileBug $command) { $this->bugRepository->add( new Bug( $command->getId(), $command->getDescription() ; } }
  31. class SimpleCommandDispatcher implements CommandDispatcher { /** @var CommandHandler[] */ private

    $commandHandlers; public function dispatch(Command $command) { $commandType = $this->getTypeFromCommand($command); $this->commandHandlers[$commandType]->handle($command); } public function registerHandler(CommandHandler $commandHandler) { $commandType = $this->getTypeFromCommandHandler($command); $this->commandHandlers[$commandClass] = $commandHandler; } //private function getTypeFromCommand(Command $command) //private function getTypeFromCommandHandler(CommandHandler $command) }
  32. { “commandName”: “\\NameSpaced\\FileBug”, “payload”: { “id”: “1”, “description”: “The software

    doesn’t work” } }
  33. class SimpleJsonCommandDeserializer implements CommandDeserializer { public function deserialize($data) { $reflectionClass

    = new ReflectionClass($data->commandName); return $reflectionClass->newInstanceArgs($data->payload); } }
  34. class CommandDispatcherController { // /api/command/dispatch public function deserialize($serializedCommand) { $command

    = $this->commandDeserializer->deserialize( $serializedCommand ); $commandDispatcher->dispatch($command); return new Response(“OK”, 200); } }
  35. DOODIS SOON ON MY GITHUB

  36. BUT HOW DOES THIS AFFECT THE UI?

  37. None
  38. None
  39. None
  40. None
  41. SEPARATE READ MODELS

  42. [ { “bugId”: “1”, “description”: “Checkout fails with order >=

    100 EUR” “affectedFeature”: “CheckoutOrder”, “usageOfFeature”: “2233” }, … ]
  43. class BugStatistic implements JsonSerializable { private $bugId; private $description; private

    $affectedFeature; private $usageOfFeature; //public function __constructor(…) //public function jsonSerialize() }
  44. class BugStatisticsController { /** @var BugStatisticsRepository */ private $bugStatisticsRepository; //

    /api/bugs/statistics/overview public function overview() { $statistics = $this->bugStatisticsRepository->findAll(); return new Response(json_encode($statistics)); } }
  45. class QueryingBugStatisticsRepository implements BugStatisticsRepository { public function findAll() { $sql

    = ‘SELECT * FROM bugs JOIN usage ON bug.feature = usage.feature’; return array_map( function($record) { return new BugStatistic( $record->id, $record->description, $record->feature, $record->usage ); }, $this->fetchAll($sql) ); } }
  46. CQRS COMMAND QUERY RESPONSIBILITY SEGREGATION PRINCIPLE

  47. None
  48. None
  49. None
  50. None
  51. None
  52. MY APPLICATION IS JUST CRUD

  53. None
  54. PROCESSES ARE HARDCODED I WANT MORE FLEXIBILITY

  55. BUILDING GOOD SOFTWARE IS ABOUT MAKING THE RIGHT TRADEOFFS

  56. None
  57. QUESTIONS?

  58. THANK YOU I’M STIJN VANNIEUWENHUYSE @STIJNVNH PLEASE LEAVE FEEDBACK JOIND.IN/13112