Hacker News new | past | comments | ask | show | jobs | submit login
Exercises in Programming Style (henrikwarne.com)
381 points by henrik_w on Mar 19, 2018 | hide | past | web | favorite | 55 comments

The author of this book launched a new open access journal called The Art, Science, and Engineering of Programming last year. Professor Lopes serves as editor-in-chief. Much like the book, the journal focuses on the practice of programming and its styles.


> There is also an example with types, but this becomes very awkward to show in Python.

With the book having been published in 2014, and type hints [1] being introduced with Python 3.5 released in 2015 [2], without knowing how the book did it I guess this is one part of the book that could have been made better in 2018.

[1]: https://docs.python.org/3/library/typing.html

[2]: https://www.python.org/downloads/release/python-350/

I am planning on adding this book to my wishlist, but I agree with the reviewer's note at the end:

> My only criticism of the book is the naming of the styles...In many cases, there are already establish names for the styles, but instead of using them, the author came up with her own. For example: Trinity instead of MVC, Things instead of Objects, Hollywood instead of Callbacks, Bulletin Board instead of Pub/Sub and Kick Forward instead of Continuation-passing. Those names are OK, but it is much better to stick to the industry standard ones.

I'd definitely include this change in a 2018 edition, too.

MVC = Model View Presenter? Objects = Structs or Workers? Callbacks = Continuations? Pub/Sub = Observer pattern?

Depending on what programming language background you come from, you may not use the "established" names either.

Generally speaking, solution to a terminology problem isn't to create terminology n+1.

That depends what the terminology problem is. If the problem is that you're going to be criticized by a bunch of pedantic linguistic prescriptivists who want you to use their terms in the way they want, creating new terms avoids that criticism.

> avoids that criticism

is that really important to avoid? and one is just gaining new criticisms in trade, no?

and of course, going bespoke and inventing everything yet again has it's perks. maybe you'll get to be the person who "invented" a term, should it catch on. great for the resume. :)

The good old: Oh look, there are n different services, but all of them have not completely nailed it and my specific use case is not covered.

I'll create a new service that does all of the stuff the old services already did, aswell as this new thing, thus making the old n services obsolete. Everyone will be thankful for the unifying service and hail me for reducing the number of choices from n down to 1.

That's how we ended up with n+1 different services.

MVC is not MVP see also https://stackoverflow.com/questions/2056/what-are-mvp-and-mv...

Objects vs Structs - a struct is just a collection of data, while an object is a collection of data AND behavior (methods).

Callback vs Continuation - I wouldn't expect a continuation to be called more than once, while I callback can.

Pub/Sub vs Observer - with the observer pattern you register for updates directly on the object that is responsible for them, while with pub/sub there is a central component involved and you don't even need to know who originally published it.

So no, for none of the examples you gave you can just replace one term with the other.

That was intentional, see [1]

[1] https://youtu.be/Gw4WJJoDl3U?t=14m30s

Basically, she came up with her own names so that the examples could work stand alone without everyone bringing their "but to be called X it needs Y!" baggage and quibbling about it.

So it seems like @kerkeslager's reasoning in a sibling comment was correct, that it ignited a naming war.

That said, maybe a list of tags for the styles would help? "Also called: [functional, imperative]" etc.?

As as understand it, those hints are only hints to human readers. There is no standard tooling that actually does any type checking, either statically or dynamically (although such tooling can be built using Python's reflective capabilities). So while adding the hints may be valuable documentation, it wouldn't solve the problem of "showing how types protect against errors in the Adversity section".

Like the other commenter said, check out mypy.


There's mypy.

Sorry, by "no standard tooling" I meant "no standard tooling" in the sense of no tooling in the standard Python distribution.

Seeing that mypy is under github.com/python/, you can easily argue that it is in fact the standard tool for type-checking python code.

And also that the second highest contributor is Guido van Rossum (https://github.com/python/mypy/graphs/contributors).

Fair enough, those are reasonable arguments the grandparents could (and should) have made.

I believe the premise of the book is to expose the reader to an element of style that bridges different programming environments. Thus, "style" here is meant more in the terms of a restrictive technique to allow an exposure of these techniques, not writing in idiomatic, or latest-and-greatest Python.

I'd suggest this book even to experienced engineers to focus on different types or a style of programming that he/she may not be familiar. And when you recognize some of the styles it'll be a re-enforcement technique that you were doing something that is seen over and over again (much like a pattern language). I recall going over styles that are seen more in systems programming (like C). The book will contribute to an understanding of code architecture styles across different languages.

For the new engineer, I'd also highly suggest this book as you may begin to see a variety of ways to solve a problem. And I would not concern myself with idiomatic Pythonic styles as that will come with time.

Just one short note of appreciation for this book: Chapter 24 (Quarentine) helped Haskell IO and monads "click" to me. Now I understand what they mean when they say, for example, that "`IO String` represents not a string but a computation that will return a String. You can store this computation (and chain them), but they won't produce a value until you run them".

The code associated with the book is all on Github: http://github.com/crista/exercises-in-programming-style

This is very interesting. Not completely unrelated, a friend once told me he can tell a lot about the personality of a person by looking at their code. Years later I actually understood what he meant. Style does have some correlation with personality. Psychology of code...

Rubbish. Style has to do with habits picked up along the way. Nothing more nothing else. Stop with the psuedo science. When programming in the large (Enterprise). My style is Javaish very long names reactivateSuspendedUser().

When coding for myself, I prefer snake case to camel case and shorter variable names.

Likewise in code, For work, I abstract and decouple to keep the code open for future updates. For personal code, I write throwaway code. Given 2 classes that I have developed for work or play. You will not be able to tell it's from the same person.

I think you're too quick to dismiss. All that your examples prove is that your personal preferences are different to business style code. The fact that you prefer snake case, shorter variable names and throwaway code is quite telling; I enjoy programming puzzles like Advent of Code, and I always use long names in camel case and try to never repeat code. I find that it reduces the mental load and allows me to confidently code faster.

Also it's not pseudo-science. There are real, live techniques for identifying programmers based on binaries:


Identifying programmers based on their style is different than assuming people with a certain style exhibit certain personality traits. Programmer A and Programmer B could have almost identical styles, but that doesn't mean they have similar personalities.

Fair point, but I still think the comment I replied to was too quick to dismiss. Especially the last sentence.

You're taking this too seriously. This is not even pseudo science. Just Pseudo.

Yeah, I'd go further and say that preferences only should come into play early in a project when you're deciding on what the style of the project should be. For most of the lifetime of a project, writing in a style that is uniform with the rest of the codebase should come before your personal style.

This sounds like it's gearing up to some Myers Briggs or Learning Styles garbage. I don't think you'll get very far with correlating personalities with code. I think you might be able to learn some temporary behavioral traits by studying code, but nothing like a "personality".

Can you give some examples of how personality traits manifest themselves in code?

That sounds kind of fun, can you give some examples?

Maybe not exactly, but this was recently in the news:

"De-anonymizing programmers from executable binaries"


It's quite hard to examplify once I actually think about an example, but I'll try. It's more a global vibe of a piece of code rather then semantics but they do play a part (using Python as example):

A young person (say 24), has experience coding of a few years, but very enthusiastic, loves reading programming blogs, a real stickler of doing it the "right" way, and sometimes forgets other people might have to read their code. They are not as pragmatic as they would be 10 years down the road. They would use vim or emacs in vim mode because that's more pro. Their code might have a good few "clever" one liners that do something complex in a very concise manner. Took a while to compress into a single line and will take a week to read back and understand. Clever, but only if it never breaks or never needs maintenance. They write factories, sometimes of factories. They have 110% test coverage, including trivial stuff that doesn't require it. They would refactor a piece of code many times until it feels it's the right shade of clever. I like these coders because I can learn something from them, but if you have tight deadlines they might actually get in the way. Great to have a couple of these in your car, but don't let them drive.

    from itertools import chain
    first_set = set(['one', 'two']).union(set(chain.from_iterable([next.key for next in some_yielding_iter()])))
    other_value = make_value_factory_factory(first_set).make_value_factory()
10 years down the line these guys realise you write code once and it's read many times over, and the above turns into a more vanilla multi line readable expression of the same idea.

A less enthusiastic version of said 24 year old, codes because they knows how to, but has no aspirations to get better at their craft. Less organised individual. Pep8 is a new variation of Pepsi Cola? They are not bad coders, just sloppy. Their code works but can be better. They would benefit pairing with the above person.

    def someFunction(value):
        if (type(value) == ThisClass):
        elif (type(value) == str):

After pairing, maybe they were inspired a bit. Maybe they refactor to this:

    from functools import singledispatch

    def process_value(value):

    def _(value):

    def some_function(value):
        return process_value(value)

I think a good exercise is to look at a person you know and try ot match their personality to the code style. Then look at some code which might or might not be theirs and try to assert if it is.

I"ve been coding professionally for the last 12 years -- I'm 34 now -- and my code definitely still looks like example 2.

Maybe it's because I code in multiple languages daily, but I tend to not use a lot of the language features for each language. A part of it is definitely thinking about the ones that come after me, and wanting everyone -- from every background -- to be immediately able to reason about the code without having to look up what every syntax feature does.

I guess it's a fine line between depth of language features used vs. readability once one is gone from the project.

Its not an exact science, or even close to approximate. It's more for fun than anything else. The correlation between style and personality is 'loose'. And a lot of it is in the perspective of the observer and what he knows about the person upfront. I guess. Consider this a "fun" or "not fun" exercise, and nothing more :)

So what you're saying is that you guess and then rationalize your successes? (If the correlation is loose, you've really got to measure it to know for sure it even exists.)

I'm pretty much the same, been coding since 16 and I'm 28 now. I've gone through phases but I mostly code like the 2nd style. I mostly use JavaScript but occasionally pipe in another program (say python or C) when needed. I use new language features if it helps make things easier- ES6 has some really cool things, but I try not to let my code become cryptic. :)

Like another commenter on this thread, I too find the second example the most readable and I write code like the second example even though I have many years of experience with Python.

The third example is cool but I don't see the immediate value in writing code that way unless I am designing a framework of some kind.

I am of the opinion that code should be written in as simple manner as possible so that programmers from different background can get up-to-speed with the code with little trouble.

An OO language that has the ability to do dispatching on types ought to be exercised in that way.

Checking for the types explicitly in your code creates a brittle system. For a one-off bit of code, fine. For anything that may be extended in the future, it's a bad idea and will have to be refactored to become maintainable.

IMO, having functions that accept different types (when the types are unrelated) is an anti-pattern in most cases, it doesn't matter if you make it more "maintainable" by using single dispatch.

It's fine when you have related types, but in the example `someFunction` accepts both ThisClass and str, which (I assume) have very different functionality.

You see this anti-pattern a lot in dynamically-typed languages. As an example, both these examples are valid and do the same thing in `knex`, an SQL query builder for node:

    knex.select('name', 'email').from('users')
    knex.select(['name', 'email']).from('users')

Second is example is most readable, I agree. What I was trying to convey there was first the use of "type" vs "isinstance", and second the use of non pep8 snake case in Python which is frowned upon. Then I wanted to show there is another way of handling (larger) blocks of "if this type/instance then this, if that then that, etc.". I use it as a getter when I have either an id or an instance and it feels smoother to me. Python's version of overridden methods. Both are fine of course.

I'm not trying to start an offtopic discussion, but the not enthusiastic 24-year old looks like the clearest and best option to me. Personally, I would refactor it to three lines.

Except grabbing types like that in code is usually a code smell. It can become brittle and hard to extend as time goes on. It's suitable when you need something now or you know you'll only ever have a few (less than 4 or 5, preferably no more than 2) cases. But either way you ought to be refactoring to something more like the third example.

Well, calling type() is usually bad, isinstance() is a little better. But if you're expecting a ThisClass and only falling back on strings, as implied by the example, surely this is the classic example of where duck typing is handy:

    except ValueError:
Where you've written processObject so that it only works on duck-like objects:

    def processObject(value):
        except AttributeError:
            raise ValueError('I was expecting something like a duck!')

Personally, I consider code I don't understand after reading it thrice a much worse code smell.

Less sarcastically: I think you're being too dogmatic. I don't like the idea of 'code smells', because it encourages you to judge code not by performance, maintainability, or readability, but by the property that someone has decided it's a code smell. Often it's true that the pattern can be used to write utterly shit code. Code smells are, IMHO, being used as a substitute for common sense. My common sense tells me that the first example is most clean solution. If the code keeps you from obtaining the performance you need, or if you add more checks in other places which make the code unreadable, by all means, refactor it.

Interesting example to give. I always think it's good to have programmers with quite in-depth knowledge, and programmers who are more superficial in their programming knowledge but get stuff done.

In my experience, it's not so much about age, hence I'm not sure if that is relevant in there. (For example, I'm not sure if using VIM is something younger programmers tend to learn, and I'd guess more of the 'older generation' will know it).

Yeah age is not relevant really, but I went for a complete example. As for vim, or emacs in particular, I actually met a few of these 20 something programmers with enthusiasm who went there. Some stayed, some came back frightened. But they all tried (and I modelled the exampled on them)

I fail to see how this relates more to a person's individual personality than programming habits or attitude. It's not unreasonable to see two programmers of different skill levels producing the same code simply because they're both showing up to collect a paycheck. It wouldn't matter if one is a perfectionist, depressed, hyperactive, high-strung, lazy or proactive. I'm relatively sure code style is tied more to experience rather than personality.

I had this book as a student of Prof Lopes' class at UCI. One of the best classes I had. Programming patterns/styles that senior programmers got through experience were covered, which I liked a lot. As students we had to compulsorily buy the book though.

This sounds like a very interesting book. The one small concern I might have (I have only read the review) is that the sample problem might not be a good case for some of the more complex techniques, such as introspection and metaprogramming. I think we have all seen code that seems to have been designed primarily to showcase all of its author's knowledge regardless of whether it helps, and I would not want the book to be misunderstood as an endorsement of that practice.

Note: its available on Safari Books Online. I would guess that a fair number of people here have SBO subscriptions.

I like the review author's approach of writing his own version of the task before reading, then looking for its closest match among the presented styles.

Thanks for this! Added to my reading list ...

Amazing stuff!

Registration is open for Startup School 2019. Classes start July 22nd.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact