2010 11 03

From TheCommandLineWiki
Jump to: navigation, search

Contents

Feature Cast for 2010-11-03

(00:00:17.798) Intro

  • Monthly support update

(00:03:25.191) Listener Feedback

(00:09:02.608) Hacker Word of the Week:firewall code

(00:10:01.168) Hacking 101: Designing APIs

  • Early on, we probably take API design entirely for granted
    • The emphasis in our coding is learning, followed by doing
    • How any particular function gets invoked
      • Is less interesting than what functions exist to be invoked
    • Lack of awareness when first learning to program
      • May present considerable challenges later
    • APIs inform the way we think about problems to which we apply them
    • I've talked about design before, pretty early on in the Inner Chapters
      • But I think interfaces present a unique challenge
    • Understanding good examples and how to incorporate those lessons
      • Into your own development of modules and libraries is invaluable
    • In many ways, writing code for other developers to use
      • Is like the art of usability in end user interfaces
    • Many of the same principles apply, especially that of least surprise
      • But also consistency, clarity, and simplicity
    • Poorly designed interfaces can muddy the way we think about problems
    • They may tax our minds leaving little left over
      • To address any residual concerns that arise
      • Like iterate on user feedback once a bit of code is delivered
    • I've certainly been in the circumstances
      • Where a user wanted more from a program
      • But my response was that I couldn't easily figure out
        • How to code up what it was that they wanted
    • Conversations with users should always be about what is possible
      • Not weighed down by feeling that you just can't the code
        • Where you need or want it to be
    • Worse, a library with a crummy design could obscure
      • What is even possible, cutting us off from possibilities
    • How many times have you implemented some piece of utility code
      • Only to realize much later that it already existed?
    • How much are you willing to bet that you've done so
      • Because a library author didn't organize their functions well enough?
    • Design can extend even to how you arrange your API
      • In terms of modules, packages or folders
      • Giving them reasonable and clear names that encourage exploration and discovery
  • A well designed API leads its user more naturally to what is possible
    • Any bit of code can be well designed and well implemented
    • It might even be readable making it easier to debug and maintain
    • The idea behind an API, though is to allow the caller some ignorance
    • This saves them on the complexity they have to expend
      • In the effort of assembling a program that makes use of code meant for re-use
    • Too many parameters can cloud a cohesive purpose to a procedure
    • Asking the caller to remember the possibilities
      • Keeping their purpose straight is taxing
    • It erodes the value of saving them some complexity
    • If too much state is required as an input
      • How would that be any different if they managed that state themselves
      • And went ahead and implemented whatever function you are trying to provide?
    • Too few procedures simply may not be expressive enough
    • Clearly the space of what your function can do
      • Is going to be dependent sometimes on how much input is available
    • You want to avoid functions who behavior varies based on input
    • That is too close to automagic and likely to encourage a caller
      • To pass in something you truly didn't expect
    • Interfaces or protocols can server well to all a function to be ignorant
      • Of all but the aspects of your input it needs to know about
    • Think about sorting routines across just about all languages
    • None of them care if the sequence to be sorted is based on fixed storage
      • Like an array, or dynamic storage like a linked list
    • That's a useful structural commonality between them
      • And one that can easily be extended to other kinds of data
    • However, a function accepting a sequence is still limited to that semantic
    • If you had it recognize a file and open it for sequential reading
      • You are probably taking on too much responsibility
      • And have to guess about things like file modes
    • It isn't a huge burden to have a caller sift through a file
      • And put the contents of interest into a sequence for sorting
      • Or to write an adapter that bridges between a sequence and a file
    • In either case, the caller retains control of the file itself
      • Something that is a non-local concern to your API
    • There is no magic right quantity or size
    • You just want to be aware of how squeezing a design too tightly
      • Can constrict its capabilities
      • And conversely how including too much
      • May not be all that useful
  • BREAK
  • Stay focused on intent and communication
    • Resist the urge to be overly creative
    • When designing a library, there is often the urge
      • To use all the design tools and experience at your disposal
    • Beyond the interface which I am arguing needs special care
      • There isn't anything special about coding a shared routine
      • Versus any other bit of callable code your write
    • Use the same practices of simplicity, loose coupling,
      • And reasonable decomposition when building within the API
    • You don't want an overly baroque implementation to inadvertently leak
      • And more than likely you'll want the most maintainable code possible
    • Just like programming for end users, if you are successful
      • Then your API will see use and you will get bug reports and questions
    • Make your expectations of the client program crystal clear
      • That will minimize the non-code communication with client programmers
    • The point of having an API is to alleviate the caller
      • Having to have a deep comprehension of the internals of some library
    • That willful ignorance will include all manner of assumptions
    • You can use documentation to expose conditions you take for granted
    • The problem with just writing out this implicit knowledge
      • Is that it invariably will lag behind the actual code
    • Capitalize on failures by seeing them as an opportunity
      • Specifically to let the caller know what should have been so
        • But wasn't as the internal implementations details required
    • Be as clear as possible in those error messages
    • You don't need to provide a deep explanation of what went wrong
    • Focus on actions, what can the caller do to fix the problem?
    • Did they pass in an invalid value?
      • How, specifically, was the value wrong?
    • Was the system in a bad state when they called?
      • What could they do to check that state?
      • Or to change it into one that will allow their call to succeed?
    • Richer objects as arguments can ease the sting of errors
    • Initialization of that parameter object will potentially catch problems sooner
      • Much closer to where the caller is going to have more at their disposal to fix the problem
    • A stateful object can also provide direct aid in the recovery
    • I've mentioned this before, but a common mistake with less seasoned hackers
      • Is to simply fail to use all of their languages capabilities
    • We tend to think of our data in the simplest terms
      • As bits of text, numbers and flags
    • Just about every language commonly in use today has much more to offer
    • Object oriented languages let you compose related pieces of information
      • And associate behaviors, like code to check assumptions
    • Even function languages give you some great flexibility
      • To pass around and compose behavior for the purposes of supporting
        • A complex API that encodes more than a few assumptions
  • Make considered use of metaphors and idioms
    • Your programming language is a good source of convention
    • It is after all, at the risk of being obvious
      • A language you share with the users of your API
    • All languages come with built in capabilities for a variety of tasks
      • From file I/O to mathematical operations and even in many cases networking
    • The language designers made choices about how to present these
    • Borrow momentum where you can by mimicking their work
    • Doing so will make your API feel more natural and intuitive
    • This may require you to study language facilities you take for granted
    • Read through them and consider how they may have been put together differently
    • Try to divine the intention of the language designers
    • At the very least, when you are presented two equal choices in your own design
      • You may find this study helps break some tie
        • Pushing your design closer to some pre-existing code with which callers
          • May already be well familiar
    • Problem domains also suggest models that can be useful
    • There is a reason that database are all so similar
    • At their core, relational databases solve the problem
      • Of how to store tabular data and relationships within it
    • There may have been more ways to approach this in early days
      • But having a center of gravity around a common problem
        • Makes it easier for everyone dealing with variations of that problem
    • As with studying the design of your language and its libraries
      • Considering similar problems and how other APIs deal with them
        • May shed some useful insights in terms of how to model your solution
    • Be careful as a literal translation of a problem may not be helpful
    • Your solution is not bound by the same constraints as a problem space in most instances
    • If your problem is a physical domain, like the logistics of a ride sharing system
      • Thinking too literally about the relationships and aspects of riders and cars
        • May limit you, prevent you from finding more elegant solutions
        • Like dynamic programming that are not possible when shuffling atoms around
    • Object oriented tools may unfortunately make this case worse
    • In my experience, young programmers especially take object modeling in OO too literally
    • OO is a tool for organizing code
    • It can be useful to lift structures directly from problems
      • But they are also problems, after all, so your solution will need to vary
        • In order to affectively address whatever your are trying to accomplish
    • You may need to add virtual properties to track intangibles more useful to you
      • Than to elements in the problem space
    • Going back to that example of a ride sharing system
      • You may want to impart histories to riders and cars
        • Whereas riders may not directly care about which care they last used and when
  • BREAK
  • It is almost always easier to add to an API later than to take away
    • In other words, when in doubt, leave it out
    • That is consistent with the agile idea
      • Of only writing the code that you need
    • Code that doesn't exist is the only code that doesn't have bugs
    • APIs can benefit from a similar attitude
    • Functions you leave out that you may not have time to document
      • Are ones that you don't have to support or explain
    • More importantly, taking away a function after it has been published
      • Will break code using your component or library
    • Think about that, that once you release a function someone can call
      • It is likely to get embedded in someone else's project
    • The frustration of not yet having some capability that fits your API
      • Is less than any kind of breaking from removing
        • Or even altering a published signature so it causes breakage
    • Being conservative will also keep you focused on the smallest set of functions
      • That covers the need you've decided to fill
  • Find a first user and gather feedback sooner
    • For regular program design, your users test and provide input
      • On what aspects your got right and what still needs work
    • Think on the client programmers who will use your API exactly the same way
    • Ideal first adopters will be ones who can tolerate some churn
    • This is the best way to gauge whether your API communicates clearly
    • A first programmer can also give you feedback on what metaphors feel natural
      • And perhaps which ones don't fit so smoothly into the idioms of your shared language
    • You can also figure out if the error messages in your API
      • Are clear enough for the programmer to figure out how to fix their own mistakes
    • That's the real acid test of building libraries and frameworks for others
    • If you find yourself explaining a lot conversationally
      • Think about how you can make the code encapsulate that knowledge
    • For instance, if initializing a component before use requires steps in a set order
      • A message re-iterate the expected order and more specifically
        • Which step was missed or done out of order
        • Can save a programmer from even having to look at code documentation
  • You may not often need it, but being able to build a decent API is a good skill to have
    • You never know what code may evolve into something others will want to re-use
    • That is the though that informs one of my dictums
      • Always write the very best code you know how to write
    • If you are using good functional decomposition on building your programs, scripts
      • Then you may find yourself considering harvesting out common routines
    • Making those as clear and easy to use for your own ends
      • Will lead to a good starting point if you want to turn around and share them
    • Even if you are the sole hacker on a project, thinking about APIs serves a purpose
    • It can really help clarify your own designs and implementations
    • I am a big fan of the Unix philosophy of small, tightly focused bits of code
      • That cooperate through some shared mechanism
    • An API is nothing nut a mechanism for sharing
      • But also for advertising and explaining what your code does
    • If you keep the notions of good interface design in mind while writing regular programs
      • Then you are more likely to write robust, easier to maintain programs
    • It really reinforces good separation of concerns, clear error reporting and handling

(00:31:04.522) Outro

Personal tools