[HN Gopher] Interfaces all the way down
       ___________________________________________________________________
        
       Interfaces all the way down
        
       Author : jinay
       Score  : 75 points
       Date   : 2023-07-23 15:48 UTC (7 hours ago)
        
 (HTM) web link (jjain.substack.com)
 (TXT) w3m dump (jjain.substack.com)
        
       | mkoubaa wrote:
       | I would add that interface design is so hard you have to assume
       | you will get it wrong, and think about adaptability as a design
       | goal.
        
       | bombela wrote:
       | In my experience, applying the same mindset and efforts to
       | interfaces for which the principal user is not a developer also
       | yield similar benefits.
       | 
       | Good interfaces are retroactively obvious. Not like my modern
       | microwave.
        
       | kevmo314 wrote:
       | > His advice contradicted my idea that a great senior dev should
       | learn better communication or management.
       | 
       | What are interfaces if not ways to communicate?
        
         | klysm wrote:
         | also they aren't mutually exclusive lol
        
         | sanderjd wrote:
         | Nailed it right here. Lots of people don't think of it this way
         | though :)
        
         | [deleted]
        
         | bombela wrote:
         | Indeed. A way to communicate, reduce mistakes, all the while;
         | hopefully; without restricting the task at hand.
         | 
         | Basically, the opposite of a modern microwave.
        
           | jinay wrote:
           | Sounds like you've got a personal vendetta against modern
           | microwaves.
        
             | tleilaxu wrote:
             | If they have something against modern microwaves, I hope
             | they never discover office printer interfaces. It may be
             | all too much.
        
         | ak217 wrote:
         | Yes, and not just that. A lot of management boils down to
         | aligning teams' responsibilities with their interfaces, and
         | committing the teams to a baseline of usability of their
         | interfaces. See also Stevey's Platforms Rant
         | (https://gist.github.com/chitchcock/1281611)
        
       | 3cats-in-a-coat wrote:
       | I love citing this one (from
       | https://spacecraft.ssl.umd.edu/akins_laws.html):
       | 
       | > 15. (Shea's Law) The ability to improve a design occurs
       | primarily at the interfaces. This is also the prime location for
       | screwing it up.
       | 
       | While this is about hardware interfaces, software interface
       | fulfill the same exact role, and the same exact principle
       | applies. The design is in the interface. The implementation is
       | just grinding until it's done, because the decision of how
       | something will be implemented are already determined by the
       | interfaces and the information we have on the infrastructure
       | we'll be doing the implementation in.
        
       | cpeterso wrote:
       | One of my favorite relevant quotes, whether you're talking about
       | code or user interfaces:
       | 
       |  _The purpose of abstraction is not to be vague, but to create a
       | new semantic level in which one can be absolutely precise. --
       | Edsger Dijkstra_
        
       | 63 wrote:
       | It took me until the last 3 paragraphs to realize they meant ux
       | and not Java interfaces. Maybe I've been writing too much Java
       | recently but I feel like it could be clearer.
        
         | jinay wrote:
         | In a way, I meant both. The buttons and sliders of a UI are the
         | parameters and functions of a Java interface. I appreciate the
         | feedback nonetheless.
        
           | sanderjd wrote:
           | I totally read it as both! And indeed, I think the insights
           | apply to both.
        
       | RyanAdamas wrote:
       | Have we reached adaptive interfaces yet? The kind that mold to
       | the users preference based on the setup of other interfaces they
       | us? Would be nice to have one interface to rule them all,
       | tailored for everyone.
        
       | khaledh wrote:
       | A good interface guides the user to doing the right thing. To
       | quote Brad Adams (who borrowed it from Rico Mariani)[1]:
       | Rico called this the Pit of Success. That concept really
       | resonated with me. More generalized, it is the key point of good
       | API design. We should build APIs that steer and point developers
       | in the right direction. Types should be defined with a clear
       | contact that communicates effectively how they are to be used
       | (and how not to).
       | 
       | This concept is also tied closely with the concept of "making
       | illegal states unrepresntable," popularized by Yaron Minsky[2].
       | 
       | For example, a document workflow system might naively model
       | Document as a single entity that has all possible fields for all
       | possible states. This could result in the need to raise
       | exceptions (or return error codes) when the Document state is
       | invalid, e.g. you can't approve a draft document until it's
       | submitted. A better API models each state separately (e.g. using
       | a union type, if your language supports it); so you'd have
       | `DraftDocument`, `SubmittedDocument`, `ApprovedDocument`,
       | `RejectedDocument`, where only `DraftDocument` would offer a
       | `submit` method, and `SubmittedDocument` offer a `approve` and
       | `reject` methods, returning an `ApprovedDocument` or
       | `RejectedDocument`, respectively.
       | 
       | [1] https://learn.microsoft.com/en-gb/archive/blogs/brada/the-
       | pi...
       | 
       | [2] https://blog.janestreet.com/effective-ml-revisited/
        
         | moonchrome wrote:
         | And what happens when you have orthogonal traits ? You have to
         | implement a matrix of all valid permutations ?
         | 
         | Sounds like "you should wear a straightjacket because you might
         | fall down when running with scissors" kind of a solution.
        
           | Supermancho wrote:
           | > You have to implement a matrix of all valid permutations ?
           | 
           | I think the example was pretty bad, however the union type
           | being referenced is that matrix, afaik.
           | 
           | Let's start with a different example. I have a business
           | process that runs off a plan-document. The plan-document
           | includes things like caps for number of times things can
           | happen over a period (including, all-time), or day parting
           | specifying when things can happen at all (only saturdays),
           | and absolute controls like "active" or "inactive", on top of
           | the creation/deletion paradigm.
           | 
           | When the process runs, what is the state of the business
           | process at any given time? "inactive because capped out" or
           | "inactive because day parting"? This set of labels will grow,
           | in permutations, over time as well as discoverable business
           | needs. eg Was it "inactive" because it was created that way
           | or someone manually deactivated it with an update? Now the
           | program needs to reference a history of changes as well as
           | referencing run-state.
           | 
           | A business that is building a new product, especially within
           | a domain that few people understand, requires more than
           | building a set of states and assume they will always meet the
           | needs. This is a recipe for lots of large-scale rework and
           | bugs. A set of states (be it a bitfield or json blob or
           | whatever) fed into a rules engine (or component) will likely
           | be more extensible over time than looking at simple labels.
           | 
           | Granted, this is predicated on the software being a non-
           | trivial system.
        
           | greiskul wrote:
           | Then you do something else. Engineering is a matter of
           | tradeoffs. There is no silver bullet, we don't throw off an
           | approach because it doesn't solve everything.
        
           | lmm wrote:
           | > And what happens when you have orthogonal traits ? You have
           | to implement a matrix of all valid permutations ?
           | 
           | No, you'd use polymorphism. As a silly example (but it
           | demonstrates the technique), look at the phantom-typed
           | builder pattern, where you can set the fields in any order
           | you like but you can't build until you've set all of them.
        
       | tosihakkeri wrote:
       | Maybe not just designing the interfaces but their boundaries?
        
       | EGreg wrote:
       | I should also point out that comments are a code smell. The vast
       | majority of the time you feel the need to add a comment, you
       | should probably refactor your code into a well-named function --
       | whether a closure or a method. Your code should read well even
       | without comments!
       | 
       | (There are some exceptions, that have to do with notes eg for
       | security implications, or optimization techniques, or side
       | effects. And also to document parameters in duck-typed languages.
       | But even those should be put into structured comments, like
       | DocBlock or YUIdoc or whatever kids use these days.)
       | 
       | I have learned this with time. Like when you are procrastinating
       | and putting off doing something, that's a sign you need to
       | attract partners.
        
         | jackblemming wrote:
         | [flagged]
        
         | gonzo41 wrote:
         | ---I should also point out that comments are a code smell.
         | 
         | I would encourage you to ponder this a little more. I work on
         | scientific code bases and there's just some processes and math
         | that requires line by line exposition beyond what the code can
         | offer.
         | 
         | There's also nothing worse than digging into a library to view
         | the code and just being left with a ton of small classes and no
         | notes on how it's all meant to interact. Comments here and
         | there are helpful.
        
           | garethrowlands wrote:
           | The book the post mentions, A philosophy of Software Design,
           | has a lot to say about having lots of small classes. It's not
           | in favour. That book is also strongly in favour of comments,
           | lots of them. This book is well worth reading.
        
           | EGreg wrote:
           | Instead of here and there, why not write a manual that ties
           | it all together? As you said, "a ton of small classes" might
           | not be enhanced so much by "a ton of small comments"
        
             | sfn42 wrote:
             | I started out writing Java. I have seen a lot of people
             | complaining about the java docs, but to me they are the
             | best docs I've ever used. Python isn't even close, JS is
             | just a bad language in general, C# docs are pretty good but
             | I still prefer the java docs even though I use C#
             | professionally.
             | 
             | My point is, the java docs are just comments. It's a html
             | page (or you can explore it directly from an IDE) generated
             | from the code and its comments, it describes the code and
             | how to use it. Almost anything I want to achieve I can
             | achieve by exploring the java docs. The type system itself
             | tells me which things fit together and if anything isn't
             | obvious there are helpful comments detailing almost
             | anything I could wish to know.
             | 
             | In my opinion, this is the way to do it. You don't have to
             | painstakingly document every little class you write, just
             | the "public facing" stuff. Not only does this help you or
             | whoever else will be working with it in the future, it also
             | documents the intent of the class/method much better than
             | decent names can. People talk about "self documenting
             | code", I haven't seen much of it. Most of the code I've
             | seen fails miserably at being self documenting.
             | 
             | Keep the "self documenting" internal. If you write a
             | library to be used by other code, document the external API
             | and leave the internals more loosely defined. At least
             | that's what I want when I use someone else's library. I
             | don't need some user manual that explains a few use cases I
             | don't have, I just want simple, to the point, java docs
             | that explain exactly what the code does, what the
             | parameters represent etc. I can figure out how to put it
             | together on my own if I just know what all the pieces do.
        
         | [deleted]
        
         | jinay wrote:
         | That was actually another thing I gathered from the same
         | internship. We had obnoxiously long variable and function
         | names, but that meant our code read like English. Any comment
         | would just be rephrasing how the code read aloud.
        
           | sanderjd wrote:
           | Comments aren't for "what does this code do?", they are for
           | "why does this code do this?".
        
             | jinay wrote:
             | Agreed. I don't advocate for no comments in code, just that
             | many comments tend to explain "what" as a consequence of
             | poor naming.
        
               | sanderjd wrote:
               | Indeed. We agree. People shouldn't do that :)
        
         | Findecanor wrote:
         | You are overgeneralising. There is bad commenting, yes, but you
         | yourself listed several examples of when comments are needed:
         | if we continued, this could be a long thread.
         | 
         | Sometimes you need comments explaining an API that you are
         | using, because its workings are not immediately obvious. Then
         | the smell is not coming from your code but from the code you're
         | calling.
        
         | bartwr wrote:
         | What a terrible advice (sorry). Great comments are not about
         | "what does this code do?". They are about "why does it do it?".
         | 
         | In some domains like scientific or high performance computing
         | they are absolutely necessary to a) provide context to others
         | b) make you not forget c) prevent unintended consequences and
         | regressions.
         | 
         | You reorder some operations or do seemingly weird things for
         | improved performance, numerical stability, or address some not
         | easily testable bug? If you don't comment it, this knowledge
         | will be lost and someone might obliterate it during a refactor.
        
       | eduction wrote:
       | >Great product designs require no manual, and similarly, great
       | interfaces need no documentation. Imagine having to read a manual
       | on how to use a coffee mug.
       | 
       | This could not be more wrong.
       | 
       | Not everything is easy. If a library is addressing a complicated
       | domain, solving by definition a complicated problem, it is fine
       | if it requires some learning.
       | 
       | When did expertise and learning become bad things? If software is
       | an engineering discipline, why would people in it ever promulgate
       | the idea that any random cog can step in to any "engineer"s
       | shoes?
       | 
       | Rich Hickey analogizes this mentality to the world of music,
       | where it taken for granted that learning an instrument requires a
       | lot of study:
       | 
       | " We start with the cello. Should we make cellos that auto tune?
       | Like, no matter where you put your finger, it's just going to
       | play something good, play a good note.
       | 
       | "[Audience laughter]
       | 
       | "Like, you're good. We'll just fix that.
       | 
       | " Should we have cellos with, like, red and green lights? Like,
       | if you're playing the wrong note, you know, it's red. You slide
       | around, and it's green. You're like, great! I'm good. I'm playing
       | the right song. Right?
       | 
       | " Or maybe we should have cellos that don't make any sound at
       | all. Until you get it right, there's nothing.
       | 
       | " [Audience laughter]"
       | 
       | https://github.com/matthiasn/talk-transcripts/blob/master/Hi...
       | 
       | If something can be made easier without undermining its
       | integrity, great. Not everything can be made as easy as drinking
       | from a cup, something most 3 year olds can handle. If you think
       | hitting dot in your IDE and choosing among the options is as much
       | as you should be required to learn, you are asking to use NERF
       | toys instead of power tools. Sometimes you need to read things,
       | welcome to adulthood.
        
         | 88913527 wrote:
         | Opining that "everything should be simple" is a sign of having
         | been in the management class for too long and not being in the
         | weeds.
        
           | morelisp wrote:
           | Most people would do well to learn more than they have, but
           | also most things could be _a lot_ simpler than they are.
           | 
           | Honestly, the best way to achieve the latter is probably to
           | encourage the former.
           | 
           | (Which will never happen as long as companies prefer to hire
           | N interchangable people than M well-trained people, even with
           | M [?] N.)
        
       | krm01 wrote:
       | I wrote an ebook [1] about interface design for engineers after
       | seeing time and time again that the best interfaces I worked on
       | all came about when engineers and designers both contributed to
       | the process.
       | 
       | [1] https://uidesignforengineers.com/
        
         | [deleted]
        
       | seeknotfind wrote:
       | You never come up with the right interface at first because there
       | is no right interfaces. There are better interfaces, but you
       | usually need to encounter more situations to find it. Balancing
       | up front time designing an interface with velocity to test it is
       | a principle problem of software development.
        
         | jinay wrote:
         | I agree that there is no absolute best interface, and a good
         | interface will be battle-tested and motivated by real problems.
         | As with all design, there are certain intuitions you develop
         | over time that are widely applicable. You can eliminate a lot
         | of errors up front that way.
        
         | formulathree wrote:
         | There's another style of programming that has much of the
         | required interfaces predefined in the language itself. A set of
         | universal interfaces that conceptually work universally for all
         | programming.
         | 
         | It's mathematical interfaces.
         | 
         | Commutativity, Identity, Associativity, Ordinality and more.
         | For these interfaces, it becomes less about "designing"
         | interfaces with gut intuition, guessing and checking... but
         | more about finding the final design via calculation.
         | 
         | Math is known to be universal so it makes sense why
         | mathematical interfaces have such wide application. When you
         | use mathematical interfaces and compose everything along those
         | parameters... it's no longer about "you never come up with the
         | right interface at first"... That concept becomes less
         | relevant.
         | 
         | It's hard to agree with me when I'm just saying it here. It has
         | to "click" after you tried it with a language that supports
         | this type of programming first class.
        
           | garethrowlands wrote:
           | Quite so. I'm currently reading Algebra Driven Design by
           | Smart McGuire. It's a valuable perspective.
        
           | n1b0m wrote:
           | Which languages support mathematical interfaces? Is this
           | similar to functional programming?
        
             | nodogoto wrote:
             | What's not mentioned in the comment you're replying to is
             | the postgraduate-level type theory you need to learn and
             | constantly refine to work with these languages at a
             | practical level. So be aware that even if you put the time
             | into learning them, it's unlikely you'll get to use them at
             | work.
             | 
             | Look up Coq, Agda, Lean, and Idris. I would start with Coq,
             | it's the most used. Idris is more like Haskell and
             | programmer-oriented.
             | 
             | Edit: Nevermind, apparently they were just talking about
             | Haskell...
        
               | formulathree wrote:
               | I'm more thinking in terms of logical primitives for the
               | design of modules and components that can be composed,
               | decomposed and recombined. I'm thinking less about proof
               | based correctness.
        
             | formulathree wrote:
             | The language of math itself is functional. In fact
             | "functional programming" is basically programming as if
             | everything was math. Think about it, does math allow for
             | variable mutation inside a mathematical expression? No.
             | 
             | Interfaces that mutate internal values do not exist in
             | mathematics. So, in essence, yes. Mathematical interfaces
             | only support functional operations.
             | 
             | Haskell would be the language.
        
           | sanderjd wrote:
           | I have never come across a codebase written in this style
           | that is any good. I think people inclined in this direction
           | usually seem to fail to reify the domain they're working
           | within, preferring to leave everything in terms of the
           | mathematical primitives. This is much harder to work with
           | than systems that have thought through the concrete
           | interfaces useful in their concrete domain. (And sure,
           | implementing those using "mathematical interfaces" is great.)
        
             | formulathree wrote:
             | I actually somewhat agree. I think there's a gradient here
             | between modularity and useability. The more modular
             | something is, the less user friendly it becomes.
             | 
             | The problem the GP is talking about here is a modularity
             | problem right? He designs (aka guesses) the interface and
             | finds out later that his guess was wrong. Mathematical
             | interfaces deal with this problem better.
             | 
             | However mathematical interfaces are less user friendly and
             | less intuitive, especially for someone not familiar with
             | mathematical interfaces.
             | 
             | The reconciling solution is that the public interface can
             | be very domain specific and made narrow in usage. The logic
             | underneath this public interface can remain mathematical
             | and therefore more amenable to future changes.
        
               | sanderjd wrote:
               | Yep!
               | 
               | > _However mathematical interfaces are less user friendly
               | and less intuitive, especially for someone not familiar
               | with mathematical interfaces._
               | 
               | Actually I think it's less useful for people who are very
               | familiar with the mathematical techniques as well.
               | 
               | Pure math also specializes things by domain. Certainly
               | experienced mathematicians are capable of seeing the
               | generalism underneath the specialization and are able to
               | re-derive it, but to make progress they mostly don't do
               | that, they build on top of the specific "interface".
        
         | samstave wrote:
         | > _You never come up with the right interface at first because
         | there is no right interfaces. There are better interfaces, but
         | you usually need to encounter more situations to find it.
         | Balancing up front time designing an interface with velocity to
         | test it is a principle problem of software development._
         | 
         | You never come up with the right medicine at first because
         | there is no right medicine. There are better medicines, but you
         | usually need to encounter more outcomes to find it. Balancing
         | up front time designing a medicine with velocity to test it is
         | a principle problem of medicine development.
         | 
         |  _Thank you for your template_
        
         | sanderjd wrote:
         | I think good software interfaces are essentially always
         | extracted from already-working systems, rather than being
         | designed. The tricky part is figuring out when to do that and
         | how to successfully advocate for it.
        
           | lpapez wrote:
           | Agree with this. Starting with a "well-designed set of
           | interfaces" usually results in half of them being unused
           | having only one implementation and the other half being
           | rewritten because the requirements changed (worst offenders
           | are interfaces which only have one implementation, not even
           | used for mocks in tests, the runner-up being interfaces
           | accepting multiple boolean parameters).
           | 
           | On the other hand, finding an opportunity to introduce a
           | common interface to a familiar codebase feels like leaving
           | behind a mental burden. Sounds crazy I know, but introducing
           | order into a chaotic mess is just relaxing to me, especially
           | when I know I will have to maintain it.
        
         | krm01 wrote:
         | Totally. Frankly, you will never find the perfect interface.
         | It's an ever evolving process that changes as the market and
         | user behaviors and expectations change.
        
       | kmoser wrote:
       | > Great product designs require no manual, and similarly, great
       | interfaces need no documentation. Imagine having to read a manual
       | on how to use a coffee mug.
       | 
       | It's a fallacy to assume a perfect interface needs no
       | documentation, just as it's a fallacy to assume perfect code
       | needs no comments. Most interfaces are far more complex than a
       | coffee mug. In reality, the more complex something is, the more
       | documentation is needed to describe how it works, how to use it,
       | how _not_ to use it, and why it works that way.
        
         | sanderjd wrote:
         | Yes and no to this, IMO. I think the best interfaces have a
         | "happy path" simple usage that doesn't require documentation to
         | intuit one's way through without any dangerous footguns but
         | also doesn't do very much, and then an arbitrarily deep path
         | into more powerful use cases requiring more detailed
         | documentation.
        
       | moth-fuzz wrote:
       | I agree that interface is key to not just software design, but
       | design in general. Designing parts in isolation, you can do
       | pretty much whatever you want. But people being able to
       | gracefully handle where and when two parts collide is what makes
       | the software world go round. One of my favorite bits on
       | interfaces is this Rust Koan[0], which has a funny twist of
       | pragmatism at the end.
       | 
       | It's a shame too many developers think this huge idea is just the
       | interface keyword, or OOP, or even just the `object.method()`
       | syntax. I hear dot-autocomplete come up in conversation almost
       | every day now. When I was in college people asked me "How can you
       | even _use_ C? It doesn 't even have classes...?", the implication
       | being you couldn't encapsulate your code at _all_ , and I get the
       | same shrinking feeling when people talk about dot-autocomplete as
       | if it's synonymous with interface discoverability. But it's
       | really just one particular implementation (heh) of a much broader
       | and more abstract (heh) idea. It's like calling all tissues
       | Kleenex or all sodas Coke.
       | 
       | 0. https://users.rust-lang.org/t/rust-koans/2408/3
        
         | travisjungroth wrote:
         | Dot autocomplete is only one option, but I've never seen
         | anything work as well for discoverability.
         | 
         | Just talking about it in terms of functions, you usually have
         | at least one argument. Then you're trying to find the right
         | functions and remaining arguments. Single dispatch and the dot
         | syntax support this very well! I've never seen it, but maybe
         | you could do the same thing with functions. Just put in the
         | first arg, maybe more, and then the function name.
        
       ___________________________________________________________________
       (page generated 2023-07-23 23:02 UTC)