We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Writing usable APIs in practice

00:00

Formal Metadata

Title
Writing usable APIs in practice
Title of Series
Number of Parts
150
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Programmers, explicitly or implicitly, when working on complex systems, end up designing some APIs to accomplish their tasks, either because the product itself is some kind of general purpose library or because they need to write some libraries and packages to put some common code of their applications. There is plenty of information available about how to write clean and maintainable code, but not a lot about writing usable APIs. The two things are related, but they are not the same. In fact, clean code is code that is clean from the point of view of its maintainers, usable APIs, on the other hand, refer to code that programmers (other than the original author) find easy to use. We’ll see how usable APIs help in writing clean code (and vice-versa). In this session I will introduce the concept of API usability, explain its importance – e.g., impact on productivity and defects – and show its relation with clean code, as well as some (sometimes surprising) research results from literature. I will also give some practical advice on how to start writing more usable APIs.
31
59
Thumbnail
1:00:41
89
Thumbnail
1:00:33
90
Thumbnail
1:00:33
102
TwitterEuclidean vectorInterface (computing)SoftwareJava appletFunction (mathematics)Video game consoleComputer fileField (computer science)VolumenvisualisierungError messageUsabilityNichtlineares GleichungssystemPerspective (visual)Bloch waveCodeSoftware developer1 (number)BitSpherical capContext awarenessUsabilityMathematicianDemosceneCalculationMultiplication signRevision controlLie groupProduct (business)Decision theoryMusical ensemble40 (number)Network topologySocial classArithmetic meanMobile appSystem callThumbnailPoint (geometry)Rule of inferenceSoftwareQuicksortParticle systemDifferent (Kate Ryan album)ExistenceCartesian coordinate systemStaff (military)ResultantClassical physicsPerspective (visual)CASE <Informatik>Functional (mathematics)Military baseService (economics)Connectivity (graph theory)MereologyProjective planeException handlingCAN busElement (mathematics)Process (computing)Computer configurationParameter (computer programming)Endliche ModelltheorieMetropolitan area networkFactory (trading post)Message passingFrustrationType theoryLibrary (computing)Physical systemPlanningComputer clusterPower (physics)Interface (computing)Software testingError messageNichtlineares GleichungssystemInformation technology consultingAlgorithmSemiconductor memoryCodeBound stateJava appletAuthorizationGoodness of fitOrder (biology)Pattern languageSoftware bugProper mapVisualization (computer graphics)Programmer (hardware)Information overloadSpring (hydrology)Open sourceMathematicsImplementationJSONXMLUMLComputer animation
CodeUsabilityIntegrated development environmentGroup actionException handlingJava appletLine (geometry)Process (computing)String (computer science)Computer fileFile systemOpen setDimensional analysisMaxima and minimaAbstractionLevel (video gaming)Radio-frequency identificationSoftware frameworkSoftware developerPerformance appraisalFeedbackImplementationConsistencyComputer fileLevel (video gaming)Different (Kate Ryan album)Performance appraisalImplementation2 (number)System callSocial classFlow separationAbstractionContext awarenessJava appletPoint (geometry)Extension (kinesiology)Programmer (hardware)Software frameworkMultiplication signConsistencyMaxima and minimaArithmetic progressionBuffer solutionCodeDimensional analysisLine (geometry)Core dumpPattern languageLink (knot theory)Term (mathematics)AdditionBitCategory of beingDefault (computer science)Process (computing)Revision controlReading (process)Group actionUtility softwareFormal languageInformationUsabilityFunctional (mathematics)Integrated development environmentObject (grammar)CASE <Informatik>Exception handlingSet (mathematics)View (database)MereologyPointer (computer programming)Tap (transformer)Sign (mathematics)Staff (military)Source codeLibrary (computing)PlanningVideo gameElectronic mailing listSquare numberComputer configurationCellular automatonSurfaceSubsetSpacetimeWebsitePhysical systemGraph coloringComputer clusterComputer programmingSampling (statistics)Frame problemComputer animation
Java appletSystem programmingComputer fileString (computer science)Software frameworkLine (geometry)Process (computing)Performance appraisalConsistencyOpen setTuring testPerspective (visual)Context awarenessError messageTraffic reportingProgrammer (hardware)Formal languageConstructor (object-oriented programming)OvalTelephone number mappingData typeTouchscreenChinese remainder theoremControl flowInterface (computing)CodeSocial classDifferent (Kate Ryan album)Optical disc driveHash functionFormal languageMultiplication signBoolean algebraImplementationInstance (computer science)Perspective (visual)Level (video gaming)1 (number)Error messagePattern languagePoint (geometry)Object (grammar)Software testingVideo gameLine (geometry)Interior (topology)Performance appraisalJava appletUsabilityComputer fileException handlingAbstractionSoftware frameworkSoftware developerDependent and independent variablesWeb 2.0Single-precision floating-point formatComplex (psychology)Game controllerSimilarity (geometry)Universal product codeExpert systemBitUtility softwareReal numberAddress spaceQuicksortConformal field theoryFocus (optics)Perfect groupLogical constantSystem callArithmetic meanBoss CorporationStaff (military)Civil engineeringPort scannerProduct (business)Computer clusterPhysical systemResultantGraph coloringWebsiteFrame problemDisk read-and-write headProcess (computing)Key (cryptography)Computer animation
Interface (computing)Service (economics)Boolean algebraSoftware testingAbstractionLimit (category theory)Software frameworkPerformance appraisalComponent-based software engineeringCodeConsistencyLine (geometry)Equals signException handlingBuffer solutionString (computer science)Perspective (visual)Error messageJava appletObject (grammar)Logical constantStreaming mediaConvex hullMIDIEmailStatisticsWindowFingerprintSummierbarkeitIntegrated development environmentContext awarenessRun time (program lifecycle phase)Computer fileStreaming mediaObject (grammar)Context awarenessLogical constantLevel (video gaming)Point (geometry)Perspective (visual)WritingHypothesisCodeInternet service providerBitDifferenz <Mathematik>Database transactionReading (process)Integrated development environmentExecution unitDifferent (Kate Ryan album)Line (geometry)Library (computing)Serial portCartesian coordinate systemProbability density functionSoftware frameworkSoftware testingSocial classConnectivity (graph theory)Pattern languageImplementationFlow separationBounded variationCommunications protocolRevision controlSign (mathematics)WordAbstractionTest-driven developmentHecke operatorNumberData conversionCASE <Informatik>Rule of inferenceSystem callProcess (computing)Metropolitan area networkSoftware developerCombinational logicInterface (computing)Projective planeArchaeological field surveyUnit testingWebsiteFactory (trading post)Online helpMultiplication signArithmetic progressionMessage passingConsistencyLattice (order)Shape (magazine)Computer configurationStaff (military)Functional (mathematics)Video gameAeroelasticityRight angleConstructor (object-oriented programming)Civil engineeringArithmetic meanoutput1 (number)Core dumpCausalityMereologyExtension (kinesiology)Computer animation
Integrated development environmentContext awarenessRun time (program lifecycle phase)Function (mathematics)Social classConcurrency (computer science)Traffic reportingError messageCodeUsabilityData recoveryException handlingMessage passingData managementMultiplication signLevel (video gaming)Exception handlingError messageData recoveryCASE <Informatik>Data managementCartesian coordinate systemConvolutionQuicksortSoftware testingCodeImplementationSocial classAlgebraic closureSoftware frameworkMereologyChemical equationLoginTraffic reportingExistenceRevision controlSystem callUsabilityMessage passingType theoryJava appletContext awarenessGroup actionForestThread (computing)Mixed realityGraphical user interfacePoint (geometry)Concurrency (computer science)Functional (mathematics)View (database)Design by contractPattern languageConnected spaceDirected graphFehlererkennungscodeRun time (program lifecycle phase)Perspective (visual)Descriptive statisticsComputer fileFunctional programmingParameter (computer programming)Software design patternState of matterWordPosition operatorPhysical systemKeyboard shortcutWindows RegistryCAN busBitSoftware developerIntegrated development environmentSet (mathematics)Reading (process)ExpressionExtension (kinesiology)Metropolitan area networkSingle-precision floating-point formatAxiom of choiceRow (database)PentagonStaff (military)Data storage deviceWindowPlanningGraph coloringNormal (geometry)NeuroinformatikComputer clusterProcess (computing)PreconditionerExistential quantificationSubsetString (computer science)Local ringLoop (music)Arithmetic meanMassDifferent (Kate Ryan album)Game controllerComputer programmingComputer animation
Data integritySystementwurfPhysical systemSoftware bugConstraint (mathematics)Error messageObservational studyUsabilityConstructor (object-oriented programming)Factory (trading post)Pattern languageContext awarenessTask (computing)Performance appraisalObject (grammar)Parameter (computer programming)Software frameworkCognitionDimensional analysisCommitment schemeLink (knot theory)Computer programmingInterface (computing)Field (computer science)Stylus (computing)Maxima and minimaWebsiteObservational studySystem callFrame problemAxiom of choiceQuicksortComputer programmingOperating systemFeedbackFactory (trading post)Latent heatMetrePosition operatorRevision controlSign (mathematics)Service (economics)Set (mathematics)Mathematics19 (number)Bus (computing)Point (geometry)Multiplication signAreaStaff (military)Time zoneINTEGRALPhysical systemDivisorCASE <Informatik>CAN busComputer architectureStandard deviationView (database)Constructor (object-oriented programming)Social classEvent horizonSoftware bugCategory of beingComputer configurationVector potentialDirection (geometry)Complete metric spaceDecision theoryForm (programming)Level (video gaming)Film editingTerm (mathematics)Computer clusterMereologyProcess (computing)Projective planeResultantLink (knot theory)SubsetException handlingPattern languageProgrammer (hardware)Optical disc driveSoftware frameworkError messageControl flowCode refactoringWordMeta elementOperator (mathematics)Flow separationParameter (computer programming)CodeJava appletState of matterLimit (category theory)Bit1 (number)Computer animation
JSONXMLUML
Transcript: English(auto-generated)
Can you hear me? I don't have any answers, so I suppose nobody hears me. Okay. So writing usable APIs in practice. Now, I have to tell you that if you have
Googled about this, there are some other versions of this talk I gave at other conferences. However, they are not identical. I always modify the material a bit, update stuff a bit, and generally speaking, I update it with the stuff that at that point in time
annoys me the most. Basically, my talks are born out of frustration of what I see in my daily job. I work as a freelance consultant and contractor, and I write code. Generally, I land on legacy code bases where some interesting decisions were taken. As far as APIs go, in this case, an API
Now we'll see. But this talk is not only about APIs as when you download, I don't know, Spring API or Hibernate or something like this. But it's also about the stuff you do at work, yeah? Your internal project. If you actually are careful and disciplined
in refactoring your code, you will end up with plenty of packages or libraries or the alert, things that represent some sort of API subsystems you use in the rest of the system, okay? So the idea is that I'll talk about things that are relevant both for the public, if you publish APIs for third parties or use
them in your own internal projects, okay? I want to start with the definition first. In this case, when I'll be talking about APIs, I'm not talking about the Amazon APIs or stuff like this, but it's more like, and we'll be using this definition, any
well-defined interface that defines the service that one component, module, or application provides to other software elements. As a practical example, Java IO package in Java 7, this provides an API, okay? I use it as an example because then I have a running example with this thing. So basically, this is all the interfaces,
classes, the exceptions are part of the API, the errors, but also you don't see them here, but also the public methods, stuff that the users of this package use, yeah, are part of the API in this context, okay? By the way, if at any point in time you have
questions, observations, and stuff like this, please raise your hand, yeah? And then talk about usability. So what is usability about in this context? It's about efficiency, yeah? Something is usable for you, allows you to be productive in what you do. You want to do something, you know, without
wasting time, yeah? It's about effectiveness, so we want to be able to actually solve the problem we are trying to solve in a proper way, yeah? It's about error prevention. A good software API, a well-written one, will help you to
avoid some stupid mistakes, yeah? And it's also about ease of learning. How many of you have come across APIs that actually you can guess what method to call in which class, stuff like this, or the order of parameters? I've seen some, very, very few, yeah? But it's about this.
The ease of learning is about the fact that you can navigate it in simple ways without too much effort. And then, since I've seen Uncle Bob with questions yesterday, I saw Jeff Watts with the questions.
I said, okay, I want my own equation in my talk now. I'm jealous. There it is, this ability equation, where usability, this is the big O notation, so it means that, you know, the upper bound for this is one on B. I don't know exactly which kind of function is, yeah? But that's an upper bound. And B is the brain power necessary to achieve your goals, yeah?
Okay. Sorry, I thought I deleted this one. Sorry. The question is made up and totally arbitrary. It was just jealousy on my side for the other guys. But the serious message is that, actually, if you think as a rule of thumb that, you
know, you don't want to overload the brain of people doing their work, yeah? Why do we want to bother with usability anyway? It's from a company perspective, actually. APIs can be quite a great asset, but also a huge liability. Practical example, I work a lot with
investment banks, yeah? And typically, I work on the big systems they use in the backend, pricing, risking, this kind of stuff. And they use APIs written by the quants that are the mathematicians that come up with their own algorithms, yeah, to calculate risk or price of an option
or some other things. And those APIs are actually a company secret. To see them, to be allowed to see them as a developer, you have to do a special authorization most of the time, yeah? Because the algorithms are secret. So they are actually one of the main assets of the company. The problem is that, usually,
there are also huge liabilities. Let's say, as Kevin would say, the code is usually written in ungood ways, yeah? Is often written badly, with memory leaks, is a mess, difficult to change, no tests, then you wonder why you have problems
in the markets. But really, sometimes some important functions have no tests, no automated tests whatsoever around those, yeah? And so, when they want to implement new models or change something in the technology, they may have huge problems. So a project, for example, I work in a bank that was a project to go from visual C++ 6 to, I think,
Visual 2008, probably, took ages, can take years, simply because the code was written in horrible ways, yeah? Leave alone the fact that Visual C++ 6 is not really C++ in many ways, but it was mostly because of the way the things were written, yeah?
But also, there is the other perspective, that is, how many of you here are programmers, write code every day? Any managers? Architects?
Oh. So, from a programmer's perspective, yeah, having an API that is actually usable means that I have fewer bugs to take care of. Since, for example, I can guess how to use the classes and the methods and the data, yeah, it's easier for me to write code that makes sense. Of course, my code, as a consequence, will have higher quality,
which would be easier to maintain, and I'll be also more productive, yeah? It'll do what I'm supposed to do in less time. Recently, really a few days ago, I was working with a C API to do,
that I need to use in some C++ code. I actually spent two days to understand how a particular bit of functionality worked. To achieve my goals. Because of the patterns they followed in writing it, because of the documentation around it, but you see two days. So let's say that I didn't really feel very productive, yeah?
So I had an impact, and I work as a contractor, and I'm paid by the day, which means it has an impact on my customers as well. And also, here I distinguish between two types of IPIs, just as I mentioned before.
So there are the public APIs, the ones that are given to third parties, yeah? You may work for a company that produces some libraries or packages to give outside, or the typical open source software that we download and the libraries we use. And the private ones, in this case, are the ones for internal use. So as I said before, if you refactor your application, modularize it properly,
you'll end up with several APIs to achieve different goals in the different parts of your application, yeah? As we see, there is one main difference between these two, which is basically the private ones, you can do whatever you like with them,
are internal of your project. So if you make a mess, you cause a mistake, you have a bad design decision, you can always change it, yeah? With the public ones, you can't. Or, well, you can, but with great, great effort, yeah? Because they are used by other people, other teams, and sometimes they even rely on your bugs.
So in fact, I claim that any non-trivial software application involves writing one or more APIs. And also, I think that when we talk about good code, as developers,
what we mean in a way is also code that is usable from a developer's perspective, yeah? When you read a good fragment of code, it's like you think it's good because you know what you can do with it, you know how you can possibly modify it,
you understand what it does, yeah? So it's usable from a programmer's perspective, yeah? Any questions so far? Okay. Now I will introduce some concepts, usability concepts. The idea here is that I want to give you
some information that you might not have come across, that I hope it will be useful for your work day-to-day, you know, to help you think in slightly different ways when you write something, some classes, packages, functions. After this, I'll talk also about some simple techniques you can use directly,
you know, go back to work, you can do that. The simple techniques are chosen not because they are the only ones, it's just a small subset, and these are things that are, as we'll see later, actually not difficult at all. Somehow, we always forget about that stuff, yeah? All the code I see keeps having the same issues.
So first concept, affordances. An affordance is a quality of an object or an environment that allows an individual to perform an action. A door affords opening and closing, yeah? This thing has a lesser pointer,
well, you can't see it very well, but affords pointing, yeah? We can apply exactly the same concept to APIs. Let's think this is Java for reading a file line by line, yeah, was kind of interesting, yeah? You can see that the affordance is there,
you can read the file line by line, but also you can also see that sometimes the affordance is not that visible, yeah? It's not immediate. So if you had like immediate experience at that time of flight, I need to do this, how do I do that? Then the first point of call is, let's look at the class file, nothing in there to help you. And then start to read all the classes and methods in the Java UI,
at some point you arrive at this thing, yeah? So the affordance is there and may not be that visible. The second point is that part of the affordance is also the errors, yeah? Basically, what can you do in case of errors? What does the API tell you? Something happens,
what can you do about that? So the exceptions are part, have their own affordances as well, yeah? And as you can see this example, there is plenty of stuff going on, just to read the file line by line and processing. This is an example with Java 7. They introduced a new package.
It's still doing the same thing. Here is a bit clearer in the code what you can do, yeah? Somehow. Because there is a concept of file path, there is a concept of char set, which you may or may not care about. Sometimes we just want to read the file line by line like this. And then there is something, this read all lines method. Still there are some things like
files is a static class, has a similar name to the other one, but then I'll talk about this a bit more in depth later on. Then somebody that looked at one version of this talk on InfoQ actually criticized me for saying, well, the example with the file
is not relevant. It should have used the Java class, Java util scanner, yeah? Admittedly, this code is cleaner than the first example, yeah? Fewer things going on. But if you have a few minutes of patience, I will explain it why I don't think it's still a good API kind of thing, yeah?
And this is what you do in Python. Which I put this because what you do in Python or Ruby, these kind of languages, is usually kind of obvious. This is why the duck typing languages have the property that usually somehow written in a way that the obvious stuff you want to do 80% of the time is just easy to find, yeah? And then there are some cognitive
dimensions. By the way, I put at the end of the slides, I'll make them available. Somehow there are references, books and link references also. Here you see I put also where I took the material as well in terms of things.
So you can check the sources, yeah? So the first one is the abstraction level. Minimum and maximum levels of abstraction exposed by the API. Think about the file example. We see it again, but the first example, there was the concept of file, but then there was the concept of reader and buffer reader and things that are actually
a different level of abstraction in that context, yeah? Working framework. How much stuff have you got to know to be able to achieve your goal, yeah? How many classes, methods, packages, how many of these things are involved, yeah? Progressive evaluation.
So to what extent you can execute partially completed code, how many of you, when you try some new library, you want to achieve something, how many of you actually copy and paste some example code and then start tweaking it and maybe removing some and start to execute bit by
bit and add more? How many of you do that? So an API that is amenable to this, that you can do that, allows you some progressive evaluation, basically helps you in understanding how it works. And penetrability, that is the extent to which you
must understand the underlying implementation details. For example, things like sorting lists, yeah? For that one, it's very important to understand if the implementation is kind of N log N or N squared or whatever else, yeah? You can't see it from the surface,
from reading the API. You have to understand, in a way, it's internal, yeah? Somebody has to tell you, but in a way, it's internal if you don't know, yeah? Or is it thread-safe or not? Sometimes people don't tell you these things, but maybe you need to know that because the context in which you are using it, if it is not thread-safe, you may have a problem.
And then you don't know if it is thread-safe, and to be sure you add the lock around it, and then maybe you discover that it was thread-safe and you have plenty of, you know, far too many locks and you start to have other kind of things, yeah? So how much you need to know about the details so you can be effective in using it. And then consistency.
How much can you infer of the API once you know part of it? And here is the realm of naming conventions or the central, the core patterns of your design of the API, yeah? It's the kind of the map of the system, yeah? How easy it is for people to actually understand it.
Let's look at the examples again with the cognitive dimensions on the side so we have a reference point. So abstraction level. In this example, there is quite a lot of stuff going on because, you know, I want to read the file line by line. For me, the concept here is that I have a file and it has got
lines, but here you have to know about file readers, buffered readers, yeah? And stuff like this. It's like there is more than abstraction level. There are many things at different levels you have to know to be effective with it. If I'm not clear,
raise your hand and ask questions, yeah? Then think about the working framework. Again, you need to know about several classes and exceptions and things, yeah? Progressive evaluation. Well, in a way, it allows you to do that because you can always create a reader and file reader and compose
them, you know, one at a time and get there. So, yeah, there is some. Penetrability. Well, in this case, it's like you don't really need to know much of the internals. So it's okay. At least it's all public stuff in
this package. We are not thinking about any trading issues here or stuff like this, so kind of okay. Consistency. Well, I'd say that Java is consistent in making your life difficult sometimes. So in a way, it's consistent to an extent. But let's look also here. This is an interesting point
that will come up in a minute. So everything is in the same package, yeah? So I'm looking just at the Java IO API thing here, yeah? I need to just browse in that package. I'm able to do this, yeah? The example with Java 7. So this is a different one.
Here, the abstraction level is actually much better because I've got the concept, well, of file and file system, path, and chart set that is, well, depending on what you read is probably interesting, even if probably most of the time you will end up with the default chart set anyway, yeah? So the abstraction level from this point of view is much better.
Working framework, again, doesn't really require to know a lot. It's fine. Progressive evaluation, you can do that. Penetrability, just like before. Consistency, again, same Java stuff. However, and also everything comes
from the same package, yeah? So if you know about this package, you can browse it. But now I want to attract your attention to one thing. This thing is in addition to the JavaIO package, yeah? So basically now in Java 7, you have different ways of achieving the same goal using different subsystems, different APIs, yeah?
Which have things with similar names, yeah? I actually checked the files class. There's also some methods that are like the file class on the other one, except the file is not started, yeah? The files is mostly static methods, the other is not. So it's kind of, if you know about both,
you may end up actually being confused. So living in the same system, these things actually may make your life not easier, yeah? And then the example with the scanner, yeah? The code is cleaner, I agree on that, yeah? And probably abstraction level, you have this concept of scanner.
Scanner of what? What does a scanner scan? You can scan many things in many ways. What does it mean, yeah? And then if you look also at what a scanner does, basically it scans text to give you some, and chops it in various ways. But then also the scanner takes a file.
So it's kind of odd. Here I don't think the abstraction level is quite much up. The code is cleaner, yeah? But look at this. It's two packages, two different ones. So you have to know about the JavaIO file and the JavaUTIL scanner. Leave alone the fact that calling something UTIL is always a bit, you know, it's like the Arctic.
You don't know where to put stuff. You put it in UTIL, yeah? So the guy that criticized me on the web was like, you just have to use the scanner, your example is not relevant. Well, you know, the example was not about writing the code test. It was about talking the usability of the APIs here. So I maintain that even if the code here is cleaner, actually, it's not more usable.
I would contend that actually using the first example is probably easier for you to find. Because you have to browse one place that is the obvious one, deals with files, yeah? And then you end up digging there. But it never comes to my mind, say, oh, it's not here. Let's look at UTIL, yeah?
And then, of course, the same example with Python, just to hear the abstraction level is exactly what you want, basically, yeah? You have a file. You have your lines. Working framework requires one class and the red lines. Method on the class, which is pretty obvious, yeah?
And progressive evaluation is pretty easy. Actually, with Python, it's interesting. The first time I used it, I needed to solve a problem at work. But I didn't know the language at all. I got a Python in a nutshell book on the weekend. But basically, I ended up on the Monday having production-ready code. But most of the code I wrote, I could kind of guess.
You know, it's like, well, this class can be. And that was an interesting experiment. Because basically, you can see that the APIs there are written in a way that address the 80% case, yeah? Maybe they are not just as flexible as the Java IO. But I don't care. Most of the time, you don't care about these things.
Any questions so far? Now, some techniques. As I said, these are techniques that are not new.
It's nothing I've invented. It's nothing have shutting or anything with these. But it's something that I see again and again the same problems. Basically, to actually improve our code,
sometimes we just need a bit of attention and just apply very simple techniques that we all should know. And I like this quote from Alan Perlis about this. None of the ideas presented here are new. They are just forgotten from time to time. It just describes my feelings about these kind of things. So I talk about things like user perspective, naming,
explicit context, error reporting, and also incremental design. For who in this room these things are completely unknowns, you cannot even guess what this stuff is.
As you can see, it's nothing particularly new. But first thing, we developers are in the habit of doing our own stuff. Then somebody cannot use our code, our APIs, comes to us and we say, oh, how is it possible? Look, it's simple. You just do da, da, da, da, da, da, da, da, da.
It's obvious. The problem is that you really need to ask, what would the user do? And you are not the user. We are creating the thing. You are not the user. So you really need to do something to make sure that whatever you are doing
makes sense to the user. First thing, these should be trivial. Use language constructs to make intent clear. Make TV. If you read something like this on the code, you say, well, maybe you know that it's code about some TV related stuff, television related stuff.
I'm creating a TV instance. But what the hell is true and false? I see code like this all the time. Then you go and dig into the implementation. And I say, ah, it's color. And then I guess it's color.
The other one must be black and white. And then it's CFT or flat screen or something like this. What if we had just an enum? As I say, this, how many of you have never seen code with a Boolean like this?
How many of you always write code in ways similar to this? OK. Well, I include the, you know, I'm just like you. It's not that I'm perfect. Just to be clear.
And then you can end up with this. So basically, if the API for making TV had exposed this kind of enum, also this ability would be much, much easier. Because from the person having to call them, it would be much easier to guess what to do. And also, reading the code, you say, ah, now I understand what it does.
But sometimes when we develop our own stuff, we lose focus on this perspective. Because we are too engrossed into the ideas we have in our heads and forget about these aspects. Because after all, if you are doing it, we are the experts. So we are not too tough with the complexity.
And with the code I'm dealing with right now, it's even worse. Because I don't have Boolean. I don't have Booleans. I have int and hash define instead of constants to define the various ints, which is even worse. Because you look at the, you know, Boolean at least has two values. So it's like, OK. But then an int, you know, two times 32 or something values.
Which ones are actually allowed and which are not? Questions so far? These are the things I call it, give control to the caller.
Now, who can answer this? What's wrong with this? Have a look at the code a minute and tell me. By the way, this comes from real production code I've seen. OK? So I didn't make it up. So if you find it strange, it's not
because I wanted to be, you know, to make a point. It just comes from real production code. Anybody willing to tell me what's wrong with this? OK, let's have a look. The first one is startable. So as a mental start, that returns a startable.
But if you call the start again, we'll throw an exception saying, oh, this already started. Sorry. So if you, in your code, if you come up with a startable, you can start it. But then it's like, you can't do much about it. And then there is the stoppable one. That does work basically the same pattern.
Returns to your stoppable. But if it is already stopped, you cannot stop it. So users of this API are actually forced. Well, first of all, it's obvious that these things go together. So they are actually forced, if they get a startable, to downcast to a stoppable. So basically they have to know an implementation detail
to be able to do something with their own active object. Is it clear? You get a startable somewhere, you start it, but at some point you need to stop it. You know that it has to be a stoppable, so you have to cast it to the stoppable things.
These kind of things can make your code incredibly brittle, because then you change something, the casts don't work anymore, you have all sorts of problems. This had been written by someone that had a very interesting idea about single responsibility principle.
After a while, we refactored the whole thing to this, which was, you know, it's a service, has a start, has a stop, and you know if it is started or not, you know what to do with it. But this kind of code actually happens again. I see this again and again of variations on the team.
Things like you provide an API, but then to do something you have to downcast and have to know the implementation class underneath. You have the interface, but you have to know the implementation class, downcast to do something interesting to you. As I said, these are very simple things to do. Unfortunately, code like this is still out there.
Who does TDD in this room? At least write unit testing, even if not TDD. The same people?
A few more. Now, if you actually write your APIs using TDD, it puts you in the shoes of an user. Because if you write the test first, the thing you don't want to be in your test is like, I need to redefine line by line, but of course not. Do TDD, let's start with a file reader,
then a buffered reader, then blah, blah, blah, blah. At the end, you have the file. If you use TDD, usually you tend to say, you know what? I want to have a file in which I can read lines. Because in that point in time, you become the user, and it's kind of tedious to do the long-winded way. And also, because it helps you with outside development,
basically you look at what you are trying to achieve exactly from the user perspective first, not from the internals, not from the other side. If writing a test is painful, the design may be wrong. Now, this is an important thing, because I work with teams that use TDD,
and they couldn't read their tests. So they were confused by their tests. So that was a very strong sign that something was wrong somewhere. And this is something that is very easy to spot, because you see, as soon as you get confused, something is wrong.
And that is actually a strong signal that maybe you should change something in your design. Not only this. The test will provide up-to-date documentation and examples of use. How many of you, before using a new API, the very first thing to do is, let's download the PDF manual and read about it?
One. That's the first one. How many of you, instead, download snippets of code, copy, paste, try to compile and see what it does? If you use TDD, providing the tests,
actually, also to the user, this provides the examples of use. The snippets of code to get them started. And of course, with TDD, helps with various things, the abstraction level.
As I said, it helps you to limit the number of abstractions in the mainline scenario, simply because you're writing the test first. You probably are lazy, just like I am, and you don't want to write a blot of stuff just to get to the main point. The tendency is to get to the main point first and then work around it. Helps keep the working framework smaller
pretty much for the same reason. You don't want to instantiate a zillion classes or dependencies first. And in fact, if you have to mock, to instantiate 50 mocks before actually being able to test your class, your design might be slightly wrong.
Helps with the progressive evaluation as well. Because the tests themselves are written in a progressive way. So somehow naturally, your code follows the same kind of pattern. Provides examples on how the various components interact with each other. So helps with the penetrability as well.
So people can see they are in the test that's passing what they can do. And consistency. If you are doing TDD properly, you refactor. I don't know how many of you talked this morning about TDD, what went wrong. The refactoring bit is always the bit that everybody seems to forget.
Well, he mentioned that. And this will help you to actually maintain the consistency as well. Because if you refactor, you'll end up actually taking care of these things. So if we think about the first example, reading a file, probably if it was like, if the read line was considered an important function,
they are in Java, and was developed TDD, this is a hypothesis. A potential test would have been something like this. You get some expected lines, you instantiate the file, read the lines, and check that they are exactly what you expect. So probably you would end up with code
more similar to this. I'm pretty sure you wouldn't end up with this thing. Anybody thinking that I'm talking rubbish here? Questions?
Naming. We talk always about naming, and we have also big heated conversations usually in the team about these things. But the rules are actually simple, well, simple rules, not necessarily simple to implement. So first one is, reserve the simplest and most intuitive names
for the entities using the most common scenarios. So if the scenarios that are the mainline ones, reserve the best names for those things. Pick one word per concept. This particular point is advanced stuff in investment banking. I've seen applications where in the same application, the same concept was called trade,
deal, contract, and transaction. The same code base. So this seems to be an easy thing to do. Well, it's easy to say, but requires some discipline. And use easy to remember conventions.
So maybe get set is not a great convention, but for example in Java, is an important one simply because also some libraries rely on it anyway. You can use that. Or whatever it is you choose, make sure you follow it. So this will help people to guess. The names will make the API
actually easier and more consistent. I've done this in several projects, and it's actually a bit hard to do at the beginning. But then if the conventions are clear and not complicated, without nitpicking on tiny details, just you need a few simple ones,
you'll end up with a much, much better thing at the end. Don't be cute. Don't use funny names. Don't be funny. Don't do like one guy, I work in a code base, he wrote things like, there was something to make a difference between transaction, banking transactions,
and he called in transaction diff guru. That's not fun. That's a problem, because if I'm new to the project, I look for something for the difference and then I read gurus, like what the heck is this thing? And this is an example of not to do taken from Java again.
I'm not trying to pick on Java, it's just that it's full of good examples for these kind of talks. Now, something called JavaIO object stream constants. Obviously, it's obvious what it does, and also it has some documentation. This is a comment, constants written into the object serialization stream.
Anybody can guess what this thing does? Then I go inside and say, ah, Satikint, and then it's beautiful also that the constants have the comments like base wire handle, first wire handle to be assigned, protocol version one, a stream protocol version.
What the hell is going on here? Then if you think about it actually, this is a kind of DSL for the serialization. They use these constants to mark various points in the serialization stream. So it's actually DSL, expressed with constants, but it's a DSL. But the naming of the class,
it tells you this is implemented using constants. It's not telling you what it does, what it's supposed to do. And the comments here, they just, it's the kind of comments that is basically copy the code, paste the code, and put spaces in between the various upper case things.
But this is a very common thing I see again and again. Explicit context. What I mean with this? So we have some assumptions when you produce an API.
We have assumptions about the external environment. And also there are some kind of context when they're interested in it. There is a deployment context and the runtime one. So assumptions about the external environment is also things about
who controls the application, things like this. Typically if you have GUI APIs, often they want the main thread. They own the main thread, main loop, stuff like this. And also the context of deployment runtime are kind of the deployment dependencies on other APIs. Which version should you have of this other thing
for this one to work? Assumptions on deployment parts. Sometimes you can deploy some things only some parts of your system for whatever reason. Or I work with APIs that I think with user permissions, licensing things or stuff like this. So things you have to keep in mind and have to be very clear.
Example of interest in deployment context in a bank. I was working the system that used an internally developed login framework. Well, the login framework was used in the application. So I joined the team. Something was not quite working. And then I said, OK, look at the logs. And I couldn't see any logs.
After a couple of hours of confusion because I knew that the application was going through those parts. I asked a colleague and said, ah yeah, I forgot to tell you. No, it depends on this setting on the Windows registry file. If you don't set this in the registry, you can't actually, it won't log anything in your application.
OK, I use some colorful Italian expressions at that point. This is an assumption on the deployment context and was not even made public. Besides what you may think or not about this kind of choices, yeah, I don't have a positive opinion on this, but still, yeah,
was an important one. And then there is the runtime context. Initialization and finalization steps. Depending on the API developed, sometimes you have to, you need some method called at the beginning, initialize and finalize at the end. I don't know maybe if you have, for example, a middleware. Typically, if you have used core, bind the past, or mice,
or some middleware system, sometimes you have to initialize the thing that will connect you to the external world, yeah? Stuff like this in the main. Pre-conditions for calling methods or functions or instantiating classes. How can I use this? What, as a user of the API, what am I supposed to do to be able to use the functionality?
Assumptions about global application state. This is my preferred one. Because the global state, now global is not actually cool anymore. In recent years, we haven't done with, you know, we are done with globals. No more globals with singletons.
Who thinks that a singletons is not a global variable? Because my description of a singletons is that it's a global variable with a raincoat and dark glasses, yeah? Trying to look inconspicuous, you know, and unnoticed. The thing is that if you put this, if you have global set in your API,
you can actually cause trouble to the users. Because, sorry, they can be difficult, very difficult to use in a concurrent environment, yeah? Probably if you went to the closure talks and things, they might, I wasn't there, but they might mention these kind of things, yeah? The functional languages are big on this. You don't want any global stuff.
Not even global, not even changing stuff most of the time, so even stronger than that. They can make test setup extremely hard. Now, I interviewed quite a few times people that said their new design patterns. Typically, this is a hint that I have to ask them
some interesting questions that is, okay, what have you read? That is always the gang of four books, nothing else. Which pattern have you used? The singleton, ha ha. Have you had any problems with that? No. Do you test your code? Of course. How did you test with the singleton? Ah, yeah, we had to do this trick in the linking so we could have the singleton
for testing purposes. That was actually not a problem. I know that I think of it, yeah, it was a bit of, you know. Can make penetrability really hard by having dependencies. If you use singleton, yeah, I now use the word singleton
for the global state just for the sake of argument. It's just you have a call onto the singleton inside your function, but it's invisible from outside, yeah? So as a user of the API, I don't know that you call something there that is global state. So I may have horrible surprises. And I've had quite a few headaches because of this kind of stuff, yeah?
As I said, all this stuff so far sounds obvious, yeah? Yet, raise your hand if you have seen applications where there were singletons that gave you problems with testing or concurrency or whatever, yeah?
And there is plenty out there. Error reporting, the next one. This is extremely important for usability because if things go wrong, I need to know what I can do about that, yeah? Users need to know how errors are reported,
what is reported when, sorry, I clicked one more, what they can do about them. The code base I'm working right now, the people, since they are using C++, and in C++, when you throw, you can throw everything, even the kitchen sink. You know, you can throw,
in the throw clause, you can put strings, ints, whatever type you like. They throw char star, which means that if something happens, I have no way to decide programmatically what kind of error was, yeah? Java code, I dealt with in a previous contract. The guys that worked on this framework,
wonderful persistency framework for the bank, so they gave out the API that had only one exception that was thrown in all cases, you know, wrong connection error, data error, whatever. The only way to decide what the problem was was parsing the message string, yeah?
So these are actually awful things that can cause incredible trouble, and you can't recover from error easily if you have that, yeah? So actually, with error reporting, you need to make recovery easy to do. So then you can use error codes,
possibly, or exception classes, or often a mix of the above, yeah? Sometimes I see exception classes with error codes inside, because depending on what you do, having a forest of exceptions is just as bad as having none, yeah? So there is a matter of balance. But whatever it is has to be easy from a programmatic point of view, yeah?
So the user has to be, the person, the developer that is writing code in your API has to have a way to take action in case something bad really happens. A question. Yes. The face of the user? The user in this talk is the programmer.
Using the API, okay? The user in this context is the user of the API, okay? Yeah, you throw them in their face. As I said, text messages are not good enough, yeah? And something that is not clear
to many people is that error management and reporting need careful design from the very beginning. The problems I've seen are due to the fact that very often error management is an afterthought. Most of the time, I have the same experience. And this is incredibly bad because it can cause trouble in the code using your API.
They have to make all sorts of convoluted mess just to understand what is going on there, yeah? Possibly knows implementation details so they know what kind of thing to expect, yeah? And the other thing that is sometimes not clear to many people is that what is an error at one level
may not be an error at another one. This is something that confuses the hell out of many people. So if you read the file and the file class tells you throws an exception, say file not found exception at the file class level, that is obviously an error, yeah? So says what? You told me to read something that doesn't exist.
I'm telling you I cannot do anything, sorry. From the perspective of the caller might not be an error, might be something that just happened, yeah? We take data from some call that comes from the user, yeah, that made a typo there, yeah? And then it's not really that
you report back, look, you gave me a wrong, the name of something doesn't exist. If it is a typo, you can't consider that like as an exception at that level. Something that happens you have to deal with it, yeah? It's not exceptional in any way. So the error at that level has a different connotation, okay?
Because sometimes people think that whatever exception is at the bottom level has to be, you know, major error that has to be reported all the way through. No, you don't want that. You have to keep in consideration that keeping into account that from the caller point of view may not be an error. So you have to be clear, yeah, about your design there.
And then the final thing, incremental design. I put this quote from Fred Brooks. Who of you knows about Fred Brooks and read this book, The Mythical Man-Month? Okay, so he is often quoted for, you know, saying, talking about clean
architectural design. The interesting bit is that this quote is not about the internals of the system, it's about the APIs exported, yeah? I will contend that conceptual integrity is the most important consideration in system design. It is better to have a system omit certain anomalous features and improvements,
but to reflect one's set of design ideas than to have one that contains many good but independent and uncoordinated ideas. So we often use the conceptual integrity to talk about the internal architecture of our systems, yeah? But here, what Fred Brooks refers to is like from the outside point of view. He was the project lead
of the IBM 360 operating system, yeah? So basically his users were programmers. Now, when we talk about API design, we always talk about flexibility. We need to be able to do everything, yeah? You need to do this?
Ha, my API can do that. You need to do that completely differently. We can do that as well. Well, my suggestion is start specific and small and be focused, yeah? Start with the 80% case first. And also, I would say, remember that when you talk about APIs,
often they're associated with the word framework. Framework means that there are frames around it. Frames put some constraints, yeah, to what you do. A framework is made to limit your choices, not to extend them. Yeah? Quite a counterintuitive thing, yeah?
But if you do that, actually, you'll be in a much better position because it's actually easier to extend your API later on. Because if you start big, and we need to solve this problem and that problem, then you think,
OK, then we make it flexible. But flexibility is not truly flexible. It's flexible in a specific direction. If the changes go into a different one, you have a problem. How many of you have dealt with the flexible frameworks, possibly written by you or by teammates on your project, that the flexibility
ended up being something that was just dead code to carry on and maintain? So I might suggest in solid-start, specific and small, you have more options later on. When you know more, you know in which direction to actually add stuff. Yeah? It's easier to add than to remove,
always. And you are not going to need it anyway. YAGNI. Yeah? We are very bad at predicting what we are going to need later on. Of course, sometimes we know that something is absolutely necessary. I'm not saying that is always the case. So if we know that, we do that. But most of, very often, we just don't. We guess.
Then there is the caveat, I mentioned before, that public APIs are more difficult to refactor. In fact, some errors may actually become features. Think about Excel. I don't know if any of you has done any programming with Excel.
Has an interesting concept of date. So the dates are integer from, I think it's the 31st of December 1899. But then there is a bug in Excel that they thought that 1900, I think, was a leap year. And basically, this screws up the whole thing. So everybody knows about the mistake. So all the code is written around that bug when they have
to deal with dates in Excel. That's a feature. If they fix that, they will break tons of code. And you can change them. But the techniques to refactor usually involve some form of deprecation and versioning. So it can be quite a complicated affair. It's not really a quick feedback loop of a few hours.
It can be months, years. It can be a very, very long thing. Yeah. Or you can choose the C++ way that you just pile up craft on top of craft and keep everything. And now that you have some time, six minutes, so I wasn't sure if I could get to this point or not, but yeah.
I want to show a couple of studies that are, oh, sorry. They have quite something that surprised me in a way. The first one is the factory pattern. How many of you do Java in this room? C sharp? How many of the APIs you use involve some form of factory
to instantiate stuff? Now, I have a more limited experience in C sharp than in Java. And in Java, certainly, it seems that is, if you have an API without a factory, you are not cool. But according to this study, the factories are detrimental to usability
in several situations. I put a reference to the study also in the slides. You can download it from the web. Actually, the constructors are much better. Now, I have to say that personally, my personal experience, I agree with this. OK. I didn't do the study, but I always find it
awkward to work in factories also, because often they involve factories or factories. You go to the meta level. It's like, what the hell? I just want one of these. Sometimes, even if they reduce usability, you still need them for various reasons. You don't want to expose some things. But often,
you can do without. So it's basically, if you are writing something that involves factories, take a step back and see if there are other ways to get around the problem. And then there is another one that is even more surprising for me, the constructors. Apparently, according to this study, programmers strongly preferred and were more effective with APIs
that did not require constructor parameters. So basically, without parameters and then set properties later, which I found a bit odd. I did the study, so maybe I need to read it again to see if there are any caveats in the way
they did the study. But I find this very interesting. In this case, in my opinion, doesn't really matter what they say. I would still go with the constructor and the parameters, because it's easy to forget setting stuff. And then, if you find yourself, you know, construct, set, set, set, construct, set, set, set, you say, you know what, I'll put a factor in.
And I say, now I have two problems. But these are kind of surprising things. When I was researching for material, I wasn't really expecting this stuff. I don't know, especially in this one,
why, but apparently it's like that. Nowadays also, with IDEs, I don't think it's actually that problematic anyway. You know, you can only see the parameters there with auto-completion. That said, I'm done. Any questions?
Questions, remarks? These are links to all the resources there and then there are also some books I suggest. But have you got any questions, or remarks, or events, something that contradicts whatever I've said?
Yes. But still, yeah, you can do that. So we said, the example is a startable
and stoppable thing. Instead of throwing, you just ignore it if you had already started. That solves the problem of the exception. But introduce a new one. How do you know that it started? Basically, what you'll end up doing is any part of the code where you need the thing to be started,
you will start it all over the place. Because it's like, I'm not quite sure here if it is in the state in which I want, so you know what? I make sure it is. Which will make your successive refactoring actually quite hard.
Sorry? Restart method. Yeah. Well, I have seen in the refactor example. So basically, the refactor example is a potential, yeah, is what we did. It was a better solution. I'm not saying that that is a best solution. But the whole point was that if you have
something like this, you want the programmers that use your API to be able to do something with it, to take decisions. If I start it, I want to be able to say, well, is it started? I want to be able to stop it without recurring to strange tricks. This was the point there. Then you can solve the problem maybe in many other ways,
that my solution was an example of a solution. Any other? OK. Thank you very much. Time for coffee.