[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)