[HN Gopher] 99 Bottles of OOP now available in Python
       ___________________________________________________________________
        
       99 Bottles of OOP now available in Python
        
       Author : mattcollins
       Score  : 230 points
       Date   : 2024-11-15 15:39 UTC (5 days ago)
        
 (HTM) web link (sandimetz.com)
 (TXT) w3m dump (sandimetz.com)
        
       | teraflop wrote:
       | HN's automatic title editing strikes again. The title of this
       | submission should presumably be: "99 Bottles of OOP now available
       | in Python".
        
         | Stratoscope wrote:
         | Note to anyone who submits an article: If the title gets
         | mangled like this, _edit_ it.
        
           | codetrotter wrote:
           | It definitely took me quite a bit of time from I joined HN
           | until I learned that if you edit your submission title then
           | you can override the automatic edits that HN makes to the
           | title you originally submitted.
           | 
           | And I would guess that likewise there are still a lot of
           | people that don't know this.
           | 
           | Also, sometimes one might not realize that the title got
           | changed until it's too late to edit the title of the post.
        
             | amelius wrote:
             | I wish HN could just take the url and then fetch the title
             | of the page.
             | 
             | That would save quite a hassle, especially on mobile.
        
               | jdminhbg wrote:
               | In this case, the missing '99' isn't a typo, it's
               | deliberate by HN to eliminate clickbaity headlines like
               | '7 Ways To Be A Better Programmer.'
        
               | layer8 wrote:
               | That would be prone to title injection by malicious
               | pages. ;)
               | 
               | More seriously, HN should instead display an instruction
               | after submitting, informing that the title was changed
               | and that the submitter should check the change and edit
               | if necessary. The issue is that most submitters either
               | don't seem to notice that the title changed or don't hit
               | on the idea that they can edit it after the fact.
        
           | zombot wrote:
           | > edit it.
           | 
           | How???
        
             | Jtsummers wrote:
             | Same as with comments, submissions have an edit link that
             | works for an hour or so after submission.
             | 
             | You can only edit the submission title. If you want to edit
             | the link, email the mods.
        
         | zombot wrote:
         | > HN's automatic title editing strikes again.
         | 
         | Demonstrating for the umpteenth time that automated
         | clairvoyance is an idiotic idea.
        
         | hansvm wrote:
         | Here I was assuming bottles might fit nicely into the Flask
         | ecosystem.
        
           | randlet wrote:
           | There's already a bottle web framework [1]. It came out
           | around the same time as Flask I think. It might have even
           | started as a spoof of Flask even? Or vice versa?
           | 
           | [1] https://bottlepy.org/
        
             | darrenf wrote:
             | IIRC, it's vice versa. Bottle predates Flask by a few years
             | I think.
             | 
             | Edit to add: Bottle's own FAQ says so:
             | https://bottlepy.org/docs/dev/faq.html#what-about-flask
        
         | km144 wrote:
         | Why does HN automatically edit titles??
        
           | corytheboyd wrote:
           | It's supposed to kill clickbait titles. In practice it just
           | randomly mangles titles. I don't get why they don't remove
           | the feature and instead rely on flagging.
        
       | elashri wrote:
       | Previous Discussion
       | 
       | Bottles of OOP - https://news.ycombinator.com/item?id=12129821 -
       | July 2016 (71 comments)
        
         | chirau wrote:
         | that was not for the Python version
        
           | janislaw wrote:
           | I have the book and don't speak Ruby at all. Nevertheless, is
           | so we'll written, that you can take the lessons and apply
           | them in any language with virtual polymorphism. A Python
           | version of the book means bigger audience, to the benefit of
           | the trade.
        
       | lastofus wrote:
       | This is one of my favorite software development books of all
       | time. It's the book that finally offered straight forward
       | guidance and wisdom on how to properly utilize OOP language
       | features.
       | 
       | I'm very happy to see it out for Python!
        
         | crabmusket wrote:
         | Sandi's earlier book, POODR, was also great. While it is
         | focused on Ruby, most of the advice applies more broadly.
         | 
         | Reading these two really helped me understand just how
         | impoverished the concept of OOP has become by C++ and Java,
         | from its Smalltalk roots.
        
           | giraffe_lady wrote:
           | I was so lucky to have run into poodr when I did. Early
           | enough in my career to still feel like I didn't know
           | anything, but with just enough experience to have encountered
           | the problems she was addressing "in the wild." Absolutely
           | formative for me I have no idea where I'd be without it. The
           | only other book to even approach its impact for me is
           | _working effectively with legacy code_.
        
           | inopinatus wrote:
           | Avdi Grimm preaches a similar gospel.
        
         | jonathaneunice wrote:
         | Concur. I took Sandi's workshop based on the 99 Bottles book,
         | in Ruby with a Ruby crowd, but was immediately able to apply it
         | to Python programming.
         | 
         | Very helpful and clear thinking about refactoring out
         | complexity--and not just refactoring for its own sake, but
         | under the constraint that you want to move your program
         | forward, add new functionality, etc. Refactoring with a
         | direction, purpose, and direct payoff.
        
       | kubav1 wrote:
       | Is the book DRM free? Sorry to be this paranoid, but you cannot
       | be sure today.
        
         | bityard wrote:
         | You could check?
         | 
         | The site says, "Available in digital form only (epub, kepub,
         | mobi, pdf). Includes separate books for JavaScript, PHP,
         | Python, and Ruby languages, and beer and milk beverages."
         | 
         | There is no mention of needing special software to read them,
         | so I think it's safe to guess that there is no DRM. And it's
         | sold directly by the author. Publishers are generally the ones
         | who insist on DRM. It would not surprise me if there was
         | watermarking, but that is not DRM.
        
           | kubav1 wrote:
           | I checked it but found only the same pages as you. This is
           | the reason I asked.
        
         | tomstuart wrote:
         | Yes, it is.
        
         | faizmokh wrote:
         | Yes, I have one. It's DRM free.
        
       | robomc wrote:
       | Maybe this is misguided, but it feels a bit to me (comparing the
       | ruby and js versions for example) that this is using the same
       | code examples in both, and neither are really typical of the
       | sorts of code people in either language community would actually
       | write?
        
         | jonathaneunice wrote:
         | The problem: How do you have examples that are simple enough
         | for those learning the refactoring tricks and techniques to
         | quickly grok and be able to work on, and not overly complicated
         | by the kinds of "real-world complexities" that do regularly
         | appear in "real-world code."
         | 
         | I had the same "this isn't realistic!" complaint when studying
         | the book, but the examples nonetheless helped me see, practice,
         | and adopt the techniques so that I could immediately apply them
         | to the complex production examples I needed to improve. YMMV...
         | but as a former skeptic, "trust the process." Walk that path an
         | work those examples for 5 days, then see how you feel. I was
         | already pretty skilled, including in complex refactorings, and
         | it still leveled me up.
        
       | SiempreViernes wrote:
       | > The 2nd Edition contains 3 new chapters and is about 50% longer
       | than the 1st.
       | 
       | I've never really had the problem that I've read an OOP text and
       | felt "this was too short".
        
       | otteromkram wrote:
       | Thank you for using snake_case.
       | 
       | That's all I got. Best of luck!
        
       | cutler wrote:
       | OOP is an industry of its own which generates a ton of incidental
       | complexity. See "Object-Oriented Programming is Bad" by Brian
       | Wills (https://www.youtube.com/watch?v=QM1iUe6IofM) and most of
       | Rich Hickey's excellent videos, especially his keynote at Rails
       | Conf 2012 where he basically told the Ruby crowd they're doing it
       | wrong (https://www.youtube.com/watch?v=rI8tNMsozo0).
        
         | ejflick wrote:
         | > OOP is an industry of its own which generates a ton of
         | incidental complexity.
         | 
         | Code in any form can generate a ton of incidental complexity.
         | The issue isn't the tool rather than the education to properly
         | wield those tools. Especially when you introduce the team
         | dynamic where everyone has varying understandings of what is
         | being built and how it should be built.
        
         | lelanthran wrote:
         | > OOP is an industry of its own which generates a ton of
         | incidental complexity.
         | 
         | And that "ton" is still miniscule compared to front-end
         | development which almost completely eschews OOP and has 10x
         | more incidental complexity.
         | 
         | I guess my point is that, while OOP's incidental complexity is
         | large, it's still insignificant compared to other technology
         | stacks which developers are showing a great appetite for
         | anyway. Things like "incidental complexity" is irrelevant to
         | developers anyway, today, at the tail end of 2024.
         | 
         | IOW, OOP introduces significantly less $BAD_THING, when the
         | clear majority of developers don't even care about the quantity
         | of $BAD_THING in the first place, making the whole "should we
         | use OOP" argument moot.
         | 
         | Doesn't matter if you use it or not, the extra introduced
         | incidental complexity is still going to be insignificant due to
         | the complexity load of the entire project, more so in front-
         | end.
         | 
         | Hence, there's no point in having the argument in the first
         | place.
        
           | bnchrch wrote:
           | Is your argument that
           | 
           | 1. its ok to add incidental and unnecessary complexity
           | 
           | 2. so long as it's less complex than your most complex
           | component?
           | 
           | Because that's a formula we can all agree leads no where good
           | nor productive.
        
         | chipdart wrote:
         | > OOP is an industry of its own which generates a ton of
         | incidental complexity.
         | 
         | I think you're confusing "OOP is used in projects and I've seen
         | accidental complexity in projects" with "OOP generates
         | accidental complexity".
         | 
         | The truth of the matter is that developers create complexity.
         | It just so happens that the vast majority use OOP.
         | 
         | I challenge you to a) start by stating what you think OOP is,
         | b) present any approach that does not use OOP and does not end
         | up with the same problems, if not worse.
        
           | galangalalgol wrote:
           | a) I'm not sure what OOP is, and it doesn't seem like the
           | people who tout it are either. I'm sure someone would look at
           | code I think is good and call it OOP, and someone who
           | wouldn't. It is so many buzzwords old at this point that
           | using it is more a label of a viewpoint than a coding style.
           | Combined with the book's apparent focus on TDD and carefully
           | selecting names, it zeros me precisely in on a set of people
           | I have worked with over the years. I don't, as a rule, like
           | the code those people generate.
           | 
           | b) The best style is no style, or at least pick a more
           | recently popular dogma like FP, at least it gets you
           | easy/safe parallelism in exchange for throwing some of the
           | tools out of your toolbox.
        
             | layer8 wrote:
             | The core of OOP is encapsulation (into objects) and
             | polymorphic interfaces. You program against interfaces with
             | well-defined contracts. Implementation details are
             | encapsulated behind those interfaces. The same interface
             | can have different implementations. The same interface-
             | typed variable can point to different implementations at
             | different times within the same program execution. The
             | caller who invokes operations on an interface is supposed
             | to not care about the implementation details behind it, and
             | thus be decoupled from them. Interfaces can have an
             | inheritance/subtyping relationship. (Implementations may as
             | well, but that's optional.) This enables abstracting over
             | the commonalities of several related interfaces without
             | having to introduce an adapter/proxy object. That's
             | basically it.
        
               | ryao wrote:
               | After making those interfaces, the moment you need to do
               | something that breaks those interfaces, you suddenly have
               | a headache. I wrote a program in college that daemonizes
               | by being an instance of a daemon class. Years later,
               | people wanted the option to not daemonize. With C, this
               | would be easy. With the way that I did things according
               | to OOP principles in C++, I need to delete all of the
               | code related to starting the program and write it from
               | scratch.
               | 
               | You could say that I just did not do it right, but that
               | is the problem. You need to know precisely what the
               | future will want to do it right and that is never
               | possible to know in advance. OOP encapsulation is heavily
               | overrated. There are a ton of headaches in C++ that do
               | not exist in C because C does not try to do these things.
               | Ever hear of the diamond problem? It does not exist in C.
               | Nonsensical types that span multiple lines when trying to
               | figure out why there is a type error? Not an issue in C
               | either.
               | 
               | C++ was advertised as reducing complexity, but in
               | reality, it that encourages developers to drown
               | themselves in complexity. If it were not for C never
               | gaining a widespread STL equivalent, C++ would be far
               | less popular. Sun Microsystems did make libuutil to
               | provide such facilities, but sadly, it never caught on
               | outside of Sun Microsystems technologies. The BSD
               | sys/queue.h is the closest we have to it, but it is only
               | for lists, and we need trees too to get a good equivalent
               | to the C++ STL. That said, libuutil is available through
               | ZFS, so it is not that people cannot adopt its awesome
               | AVL tree implementation on other platforms. It is just
               | that people do not know about it.
        
               | carmackfan wrote:
               | Your problem was a misuse of inheritance, not
               | encapsulation or interfaces.
        
           | InDubioProRubio wrote:
           | OOP is a mental crutch that breaks complex problems down into
           | a easy mentally discoverable world/domain model with objects
           | that have a life of their own, that is capable to derive
           | correct results to complex problems via the relations of the
           | objects.
           | 
           | Meanwhile its creators can not hold the whole complexity in
           | mind (often barely in spec) and still can produce a artifact
           | that produces correct results.
        
           | nailer wrote:
           | A. OOP as practically implemented for the last 25 years is
           | glueing functions to state
           | 
           | B. Functions and structs.
        
             | corytheboyd wrote:
             | In the real world, where many people of varying backgrounds
             | and skill levels are editing the same code, if the OOP
             | method becomes a mess, why wouldn't the functional approach
             | also become a mess? I think that is more the point OP was
             | making. In a vacuum with a single perfect Adonian
             | programmer, seems like the OOP and functional approaches
             | would becomes the same level of maintainable, because we're
             | in a vacuum of perfection anyway.
        
               | lioeters wrote:
               | In my experience, the mess created using OOP is harder to
               | untangle than the mess created using a functional
               | approach. With the latter, it's simpler to replace a
               | different function for any part of the logic, and the
               | data is always just data; whereas with OOP the method is
               | usually tied up with shared state and other functions.
        
               | chipdart wrote:
               | > In my experience, the mess created using OOP is harder
               | to untangle than the mess created using a functional
               | approach.
               | 
               | OP complained about accidental complexity, not subjective
               | takes on how hard it is to refactor code.
               | 
               | Even so, anyone who has any cursory experience with
               | TypeScript projects that follow a functional style can
               | tell you without any doubt whatsoever that functional
               | style is incomparably harder to refactor than any
               | "enterprise-grade" OOP.
        
               | nineplay wrote:
               | > OP complained about accidental complexity, not
               | subjective takes on how hard it is to refactor code.
               | 
               | The biggest problem with accidental complexity _is_ how
               | hard it is to refactor code. Refactoring code is a huge
               | part of software development.
        
             | chipdart wrote:
             | > A. OOP as practically implemented for the last 25 years
             | is glueing functions to state
             | 
             | I see you opt to go with a huge amount of handwaving over
             | the question.
             | 
             | > Functions and structs.
             | 
             | That's what a class is, and thus OOP, except it supports
             | information hiding and interfaces. So your alternative to
             | OOP is... OOP?
        
               | Joker_vD wrote:
               | I suspect "functions and structs" here meant "functions
               | _and_ structs, separately, instead of gluing functions
               | together with structs into unholy amalgams ". Basically,
               | Wirth's "Algorithms + Data Structures = Programs" idea.
               | 
               | Compare e.g. to "What should a language have instead of
               | Lua-like tables? Maps and vectors" -- "But that's what a
               | table is, so your alternative to tables is... tables?"
        
               | nineplay wrote:
               | >>> a) start by stating what you think OOP is
               | 
               | >> A. OOP as practically implemented for the last 25
               | years is glueing functions to state
               | 
               | > I see you opt to go with a huge amount of handwaving
               | over the question.
               | 
               | I think the question was answered pretty clearly. You
               | can't ask for an opinion ( "what do you think" ) and then
               | criticize the response as 'hand-waving'.
        
         | kolja005 wrote:
         | As it pertains to Python in particular I think OOP is great for
         | libraries but of limited usefulness at the application layer.
         | Things like pytorch's nn.module IMO is a great abstraction, but
         | every time I've tried to map some concrete business concept to
         | an OOP construct I've regretted it.
        
       | gigatexal wrote:
       | I'm gonna buy the book but I prefer composition over OOP. I
       | prefer to have an init that takes some params where those params
       | are fully baked clients of whatever services I need and then the
       | class just uses them as needed. I don't see a lot of value in
       | having a Python class that might have a few or more classes that
       | it extends where all the functions from all the classes crowd up
       | the classes namespace.
       | 
       | Class Foo.__init__(self, db, blob_storage, secrets_manager, ...)
       | 
       | Instead of class Foo(DB, BlobStorer, SecretsMgr)
       | 
       | Etc
        
         | yxhuvud wrote:
         | Why on earth do you put composition and OOP as opposing
         | techniques? Composition is just one more technique in the OOP
         | toolbox and there is nothing in OOP that mandates an
         | inheritance based architecture.
        
           | crabmusket wrote:
           | Mainstream OOP languages (looking at you Java) have failed to
           | make composition as convenient as inheritance.
        
             | flakes wrote:
             | The common toolkits today (spring boot, google guice, etc)
             | are much more focused on composition over inheritance, by
             | injecting arguments and implementing pure interfaces rather
             | than extending base classes. Older legacy Java frameworks
             | and bad teachers are more at fault than the Java language
             | itself IMO.
        
               | crabmusket wrote:
               | I take your point, though having `extends` as a first-
               | class language feature surely encouraged that culture and
               | approach in older frameworks right?
        
               | flakes wrote:
               | There are some valid cases where extends really can help,
               | and IMO the language would feel limited without it. Maybe
               | if the language designers had their time back they could
               | have taken an approach like Golang with nested structs
               | and syntactic sugar for calling their attributes/methods.
               | 
               | The main reason I see new devs opt for extends, is
               | because that was 99% of the content in their Java 101
               | programming course, not because it exists in the
               | language. Imagine how many more `friend`s we would have
               | in cpp if that was crammed down everyone's throats? :)
        
             | yxhuvud wrote:
             | How is composition inconvenient?
        
               | mdaniel wrote:
               | Contrast the Java way                   class Delegated
               | implements Base {             final Base b;
               | public Delegated(Base b) { this.b = b; }
               | @Override             public void printMessage() {
               | b.printMessage(x); }             @Override
               | public void printMessageLine() { b.printMessageLine(x); }
               | 
               | with the Kotlin way
               | https://kotlinlang.org/docs/delegation.html#overriding-a-
               | mem...
               | 
               | OT1H, yes, sane people using IJ would just alt-Insert,
               | choose delegate to, and move on with life. But those
               | misguided folks using VS Code, vim, or a magnetized
               | needle and a steady hand would for sure find delegating
               | to a broader interface to be a huge PITA
        
             | _old_dude_ wrote:
             | Very true, in Java, at least in the last 20 years,
             | inheritance is de-facto deprecated, all new bits and bolts
             | like enums, annotations, lambdas or records do not support
             | inheritance.
             | 
             | So you have to use composition.
        
             | watwut wrote:
             | How is composition in Java inconvenient?
        
         | inopinatus wrote:
         | These are complementary not contradictory ideas. One of the
         | principal takeaways from the Ruby edition (and many of Sandi
         | Metz's conference talks) is undoubtedly a mindset of, and
         | techniques for, writing compositional OO code.
        
         | Toutouxc wrote:
         | Then you're going to be pleasantly surprised, because
         | composition is actually a genuine OOP technique and Sandi Metz
         | advocates for exactly this kind of sane OOP focused on
         | encapsulation and objects making sense, instead of masturbating
         | with class hierarchies.
        
           | gigatexal wrote:
           | I used to work at a flask shop that did views with 3-5 or
           | more inherited classes. Nobody could really follow how
           | everything worked. It was insane.
           | 
           | Anyways yeah give me composition and flat classes all day
           | long.
        
           | gigatexal wrote:
           | What's funny is I did composition for a take home project
           | when interviewing at a place and they said the approach was
           | too complicated and failed me for it. They wanted multiple
           | inheritance instead. Fair enough. Their codebase probably had
           | a lot of it and my not showing it probably told them I didn't
           | understand it.
        
           | bccdee wrote:
           | But I've read the book, and her solution to the "bottles of
           | beer" problem involves encoding all the logic into an
           | elaborate class hierarchy!
           | 
           | I'm not rabidly anti-OOP, but the point at which I turn
           | against it is when the pursuit of "properly" modelling your
           | domain with objects obscures the underlying logic. I feel
           | like this book reaches that point. This is her stance on
           | polymorphism:
           | 
           | > As an OO practitioner, when you see a conditional, the
           | hairs on your neck should stand up. Its very presence ought
           | to offend your sensibilities. You should feel entitled to
           | send messages to objects, and look for a way to write code
           | that allows you to do so. The above pattern means that
           | objects are missing, and suggests that subsequent
           | refactorings are needed to reveal them.
           | 
           | Absolutely not! You should not, as a rule, be replacing
           | conditional statements with polymorphic dispatch.
           | Polymorphism can be a useful tool for separating behaviour
           | into modules, but that trade-off is only worthwhile when the
           | original behaviour is too bloated to be legible as a unit. I
           | don't see an awareness of that trade-off here. That's my
           | problem.
        
             | Toutouxc wrote:
             | Well, the entire book is focused on solving a laughably
             | trivial problem, any solution is going to feel excessive.
             | The elaborate object hierarchy that she uses would
             | obviously feel different in real world, complicated domain.
             | 
             | I found the excerpt in the book and I don't see her
             | mentioning traditional class-level polymorphism (of the
             | Java kind) anywhere around it. What SM generally advocates
             | for is using OBJECT hierarchies to implement behaviors and
             | encapsulate logic, the objects usually being instances of
             | simple (and final!) free-standing classes. All thanks to
             | the ability of any Ruby object to send messages to (call
             | methods of) a different object, without knowing or caring
             | about its type or origin, and the other object supplying
             | the behavior without having to check its own type (because
             | the correct behavior is the only one that the object, being
             | a specialized object, even knows). This is done at runtime
             | and is called "composition" (as in "composition over
             | inheritance") and is different from using pre-built CLASS
             | hierarchies to implement behaviors, aka "inheritance" (as
             | in "composition over inheritance"). In Ruby, composition is
             | Dog.new(Woofing.new), whereas using inheritance (class
             | hierarchies) is Dog.new after you've done "include Woofing"
             | inside the class.
             | 
             | I don't know Python well, but it seems like the person in
             | the top-level comment expressed their dislike for the
             | second kind.
        
         | vram22 wrote:
         | >I'm gonna buy the book but I prefer composition over OOP.
         | 
         | The GoF book (the design patterns book) says in a page right
         | near the start, "Prefer composition over inheritance", in the
         | middle of an otherwise blank page, presumably to emphasize the
         | importance of that advice.
         | 
         | As others have replied, composition is one technique you can
         | use in OOP, not something that is the opposite of OOP.
         | 
         | You can also use composition in non-OOP procedural languages
         | like C, by having a struct within a struct.
         | 
         | https://www.google.com/search?q=can+you+have+nested+structs+...
        
       | crabmusket wrote:
       | I'd like to mention that despite OOP being in the title, I
       | thought this book had a lot to teach that isn't specific to OOP
       | architecture or OOP languages. Really, I think the star of the
       | show is TDD and refactoring.
       | 
       | For a short intro to Sandi's style and approach, I always
       | recommend this 35min talk:
       | https://youtu.be/OMPfEXIlTVE?si=Ird6t8uDN86T06Y7
       | 
       | Aside from any specifically educational content, as a talk it is
       | fantastic - funny, smart, well put together.
        
       | dennisy wrote:
       | I have seen quite a few digital books at this price point now.
       | Personally I feel it is quite high, but I assume I am in the
       | minority?
        
       | inanepenguin wrote:
       | While I understand the complaints against OOP, I highly recommend
       | this book to anyone working in an environment where they're
       | working with OOP languages/frameworks. There are plenty of
       | Ruby/Rails shops out there still. At the very least I love the
       | mentality that this book teaches and often recommend Tidy First
       | by Kent Beck at the same time.
        
       ___________________________________________________________________
       (page generated 2024-11-20 23:01 UTC)