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

the Subtle Art of Naming

the Subtle Art of Naming

1. Naming is considered as one of the two complex things in programming. Why is it sometimes difficult to name a class, an interface or variable? Is is something that is complex by nature, or do we, as developpers, make it difficult?

2. To try to answer these questions, we'll use a very simple example. Let's say that all day long, I count peas inside buckets.

3. Let's code it! Creation a peas counter class.

4. Method count with a bucket as argument. Initialization of the number of peas.

5. For each pea shell inside the bucket...

6. ...let's open it (via an external dependency)

7. Now that the shell is opened, we can increment the number of peas accordingly.

8. Once the bucket is empty, we can return the peas count.

9. To use this class, just instanciate a new PeasCounter, and call the count method.
This example, and its code is very simple. It fits my needs, is easy to test and to maintain. And it seems I had no difficulty in naming things.
But there is a lot to say about those 15 lines of code. And we could do totally differently.

10. We could have used a rich model for the pea shell.
Anemic model = class with getters/setters, mutated step by step before being validated
RIch model = class which owns its own business logic and rules, can't be in an invalid state, no need to validate it after a process

11. Instead of getting the pea shell to pass it another service...

12. ...we can open directly the pea shell. Also, that's what happen in reality. We don't need a pea shell opener in real life. That does not even exist.

13. Being a little bit more declarative in our code, could help us to name correctly.
Examples of imperative VS declarative in real life.

14. Here we are imperative. We focus on how we will count peas. With a peas counter.

15. We often name our classes with noums. We rarely use verbs or sentences. Really good when the wording exists. Example in real life. But weird to apply it everytime and to have to invent a concept that does not exist.

16. My intention is to count peas inside a bucket. Ideally.

17. Possible code in PHP. Here our class is named according to our intention.

18. Con: __invoke syntax can seem weird
Pro: more declarative

19. We are used to focus on the developer jargon.

20. Let's say we'd like to opensource our library. And allow the others developers to count peas differently. Creation of an interface.

21. The default implementation of our library implements this interface. But what is this suffix about?

22. We love suffixes. It's comforting. But it leads to a lack of reflection. It prevents from thinking about a good naming.

23. Let's remove the suffix, what happens now? We need to focus on our business. Personally, to count peas, I use a pen and a piece of paper. I draw one stick per pea and count the sticks at the end.

24. Let's call our class PenAndPaper. In our context it makes sense. In another context, it would have a different meaning.

25. Others developers maybe want to count peas just in their head.
One remaining thing to do. How should we call the method of the interface?

26. As there is only one method in this interface, I choose to name it again according to my intention. I want to count peas.

27. We often look for a perfect naming. Precise naming for fuzzy or unclear concepts. Hide business vagueness by giving a "good" name. But we shouldn't. Let's just tell the (hard) truth.
No example in my peas story, it's too simple.

28. Akeneo, entity with family to extract from product to be able to use it in another entity. No "name" for that. Not sexy, but when you use Akeneo and you're aware of the family concept, you clearly know what it means.

29. Examples from a meetup live coding session, where there was one product owner and one developer. Not fancy, but precise and reprensents reality.

30. Ok, let's recode our example by using those concepts.

31. We use a piece of paper and a pen to count peas.

32. To count peas inside a bucket.

33. For each pea shell inside the bucket.

34. We can open it, take the peas inside, and draw a stick for each of them.

35. One the bucket is empty, we can count the sticks.

36. To use this class. We take our pen and paper to count peas inside the bucket.
The code is totally different but does exactly the same thing. The major difference it that is uses only real life/business works.
Not to use everywhere, everytime.
Not a recipe to follow as is. Plenty of others things of this kind to help naming.

37. The worst naming in this presentation is its title.
There was nothing subtle or artistic here.
Naming is "marketing".

38. Instead of naming, we should describe.
To describe,we need to understand the business/the problem we try to solve. Which implies to listen, talk and ask questions to the business experts.
cf. ubiquituous language and event storming

Julien Janvier

October 27, 2017
Tweet

More Decks by Julien Janvier

Other Decks in Programming

Transcript

  1. The Subtle Art
    of Naming
    ___
    Julien Janvier
    @jujanvier
    https://joind.in/talk/b59b0

    View full-size slide

  2. class PeasCounter
    {
    public function count(Bucket $bucket) {
    $peasCount = 0;
    foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    foreach ($openedPeaShell->getPeas() as $pea) {
    $peasCount++;
    }
    }
    return $peasCount;
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13

    View full-size slide

  3. class PeasCounter
    {
    public function count(Bucket $bucket) {
    $peasCount = 0;
    foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    foreach ($openedPeaShell->getPeas() as $pea) {
    $peasCount++;
    }
    }
    return $peasCount;
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13

    View full-size slide

  4. class PeasCounter
    {
    public function count(Bucket $bucket) {
    $peasCount = 0;
    foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    foreach ($openedPeaShell->getPeas() as $pea) {
    $peasCount++;
    }
    }
    return $peasCount;
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13

    View full-size slide

  5. class PeasCounter
    {
    public function count(Bucket $bucket) {
    $peasCount = 0;
    foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    foreach ($openedPeaShell->getPeas() as $pea) {
    $peasCount++;
    }
    }
    return $peasCount;
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13

    View full-size slide

  6. class PeasCounter
    {
    public function count(Bucket $bucket) {
    $peasCount = 0;
    foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    foreach ($openedPeaShell->getPeas() as $pea) {
    $peasCount++;
    }
    }
    return $peasCount;
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13

    View full-size slide

  7. class PeasCounter
    {
    public function count(Bucket $bucket) {
    $peasCount = 0;
    foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    foreach ($openedPeaShell->getPeas() as $pea) {
    $peasCount++;
    }
    }
    return $peasCount;
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13

    View full-size slide

  8. class PeasCounter
    {
    public function count(Bucket $bucket) {
    $peasCount = 0;
    foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    foreach ($openedPeaShell->getPeas() as $pea) {
    $peasCount++;
    }
    }
    return $peasCount;
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    $peasCounter = new PeasCounter(...);
    $peasCount = $peasCounter->count($bucket);

    View full-size slide

  9. anemic models rich models

    View full-size slide

  10. foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);

    View full-size slide

  11. foreach ($bucket->getPeaShells() as $peaShell) {
    $openedPeaShell = $this->peaShellOpener->open($peaShell);
    $openedPeaShell = $peaShell->open();

    View full-size slide

  12. imperative declarative

    View full-size slide

  13. $counter = new PeasCounter();
    $peasCount = $counter->count($bucket);

    View full-size slide

  14. $counter = new PeasCounter();
    $peasCount = $counter->count($bucket);
    class PeasCounter
    {
    public function count(Bucket $bucket): int
    {
    }
    }

    View full-size slide

  15. $peasCount = CountPeas($bucket); // ideally

    View full-size slide

  16. $peasCount = (new CountPeas)($bucket);

    View full-size slide

  17. $peasCount = (new CountPeas)($bucket);
    class CountPeas
    {
    public function __invoke(Bucket $bucket): int
    {
    }
    }

    View full-size slide

  18. developer
    jargon
    natural
    language

    View full-size slide

  19. interface CountPeasInterface
    {
    //...
    }

    View full-size slide

  20. interface CountPeasInterface
    {
    //...
    }
    class CountPeas implements CountPeasInterface
    {
    //...
    }

    View full-size slide

  21. interface SomeRandomBehaviorInterface
    class AnImplementationThatFollowsThisPattern
    class SomethingBadHappenedException extends \Exception

    View full-size slide

  22. interface CountPeas
    {
    //...
    }

    View full-size slide

  23. interface CountPeas
    {
    //...
    }
    class PenAndPaper implements CountPeas { //… }

    View full-size slide

  24. interface CountPeas
    {
    //...
    }
    class PenAndPaper implements CountPeas { //… }
    class InMemory implements CountPeas { //… }

    View full-size slide

  25. interface CountPeas
    {
    public function countPeas(Bucket $bucket): int;
    }
    class PenAndPaper implements CountPeas { //… }
    class InMemory implements CountPeas { //… }

    View full-size slide

  26. look for
    perfection
    tell the
    (hard) truth

    View full-size slide

  27. interface EntityWithFamilyInterface {}

    View full-size slide

  28. interface EntityWithFamilyInterface {}
    interface ReserveSeats {}
    function doesNotExceedOverallTrainCapacityLimit($seatsRequestedCount)

    View full-size slide

  29. class PenAndPaper implements CountPeas
    {
    public function countPeas(Bucket $bucket): int
    {
    foreach ($bucket->peaShells() as $peaShell) {
    foreach ($peaShell->open()->peas() as $pea) {
    $this->drawOneStick();
    }
    }
    return $this->countSticks();
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12

    View full-size slide

  30. class PenAndPaper implements CountPeas
    {
    public function countPeas(Bucket $bucket): int
    {
    foreach ($bucket->peaShells() as $peaShell) {
    foreach ($peaShell->open()->peas() as $pea) {
    $this->drawOneStick();
    }
    }
    return $this->countSticks();
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12

    View full-size slide

  31. class PenAndPaper implements CountPeas
    {
    public function countPeas(Bucket $bucket): int
    {
    foreach ($bucket->peaShells() as $peaShell) {
    foreach ($peaShell->open()->peas() as $pea) {
    $this->drawOneStick();
    }
    }
    return $this->countSticks();
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12

    View full-size slide

  32. class PenAndPaper implements CountPeas
    {
    public function countPeas(Bucket $bucket): int
    {
    foreach ($bucket->peaShells() as $peaShell) {
    foreach ($peaShell->open()->peas() as $pea) {
    $this->drawOneStick();
    }
    }
    return $this->countSticks();
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12

    View full-size slide

  33. class PenAndPaper implements CountPeas
    {
    public function countPeas(Bucket $bucket): int
    {
    foreach ($bucket->peaShells() as $peaShell) {
    foreach ($peaShell->open()->peas() as $pea) {
    $this->drawOneStick();
    }
    }
    return $this->countSticks();
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12

    View full-size slide

  34. class PenAndPaper implements CountPeas
    {
    public function countPeas(Bucket $bucket): int
    {
    foreach ($bucket->peaShells() as $peaShell) {
    foreach ($peaShell->open()->peas() as $pea) {
    $this->drawOneStick();
    }
    }
    return $this->countSticks();
    }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    $penAndPaper = new PenAndPaper();
    $countPeas = $penAndPaper->countPeas($bucket);

    View full-size slide

  35. The Subtle Art
    of Naming
    ___
    Julien Janvier
    @jujanvier
    https://joind.in/talk/b59b0

    View full-size slide

  36. Don’t name,
    Describe
    ___
    Julien Janvier
    @jujanvier
    https://joind.in/talk/b59b0

    View full-size slide