Ariya Hidayat: Keynote – JavaScript API Design Principles.


Jenny Donnelly: I’m so excited to announce
our final keynote speaker of the day. Ariya is one of the most wisest and deepest engineering
talents I’ve ever met. This is the gentleman that brought us the eminently useful Esprima.
He’s going to be talking to us about design principles for JavaScript APIs. Please give
him a warm welcome. Thank you. [applause] Ariya Hidayat: Thank you so much. Glad to
be here. I realize that I stand here between you and whatever party you’re going to have
tonight, so let’s make it quick and painless. I work for a startup called Shape Security
dealing with web content security, and I’m a big fan of web platform. You might have
seen or used or hated some of my handiworks over there. When I moved to the web platform for the first
time a couple of years ago, I already know some of the other programming environments.
I know C++, I know Java. In that particular world there has been already good references,
very good, excellent references on how to design API. For example, with Java most people
refer to that fantastic work from Joshua Bloch. For C++ there’s a very nice Qt API Design
Principles that a lot of people adopt in their projects. Now you might think that, well, I don’t build
libraries, I don’t build YUI or Alloy or any other kind of frameworks, so why should I
care about API? It turns out that API stands for Application Program Interface, and as
long as you adopt the best practices of modular application architectures you will have coupling
between modules. Your application won’t be monolithic, and therefore it’s very important
to pay attention to those kind of interfaces. I don’t think I need to convince you why we
need good API. First of all, nobody reads API documentations. At least I can speak for
myself. If I see a shiny library I’ll download it, I’ll pick an example, and I’ll tweak it
to suit my needs. Whenever I have problems then I’ll look at the documentation. One thing that you might notice a lot is that
you usually write the code once, or even a couple of times if there are bugs there or
if you are very sloppy, but you’re trying to read the code many, many times. I don’t
know about you but I happen to read some piece of code and realize that it’s garbage and
then I try to figure out which idiot wrote that kind of garbage, and it turns out to
be me from five years ago or two years ago. In some cases if you do a pull request workflow,
you need to review someone else’s code, you need to read that code. Although that guy
might have written it only once. It’s very important for the subsequent discussion to
realize what kind of impact that you need to take into account if you ahead of time
know that your code will be read many, many times. When I go round and ask people, hey, I’m new
to this JavaScript world, I want to write these beautiful application libraries, what
kind of advice can you give to me to make a very nice API? This is a typical answer
that I get. Your API needs to be readable, it has to be consistent, and it has to be
crystal clear. These are clichés and slogans at best, or
wishful thinking. Because who doesn’t want to have readable API? I never want intentionally
my API to be completely unreadable. So that’s not what I’m going to show here. Some of the collection of rituals that I’ve
practiced for a while and digesting from someone else’s experience are just three things. To
ensure consistency we can apply the concept called static polymorphisms. When you already
have consistency in place, the next step is to watch for all kind of traps caused by many,
many kinds of shortcuts. Last but not least is you already have consistent API, you don’t
have any crazy shortcuts, how can we make sure that that kind of code makes sense? In
other words there’s no confusion. Without further ado, let’s go to polymorphism.
When we speak about polymorphism in object oriented programming usually that means a
particular function or properties that you can apply to different type of objects. With
static polymorphism we use the polymorphism term here loosely, meaning that we observe
those function properties etcetera as part of different types. A quick example. If I have these three radio
buttons and I have one check box and I have one push button, a bad API will force me to
write this kind of thing if I want to change all the text that corresponds to those form
elements. Because I line it up nicely here you can see that they are not consistent in
the sense that if I need to change the text for a radio button I need to use a property
called value, but apparently it’s different if it’s check box, and it’s also different
if it’s a push button. Once you see that kind of piece of code then
you realize that you need to change or tweak the property name so it looks like this. It might seem obvious, but the lesson learned
from this is that whenever you try to create new objects, new components, new widgets,
and you search for the name of the properties, look at the existing names. Don’t try to invent
new names unless there’s a very, very strong reason to do so. This doesn’t apply only for buttons or button-like
form elements. Progress bar versus slider. They serve different purposes. For example
you can’t really change the value of progress bar unless you change it programmatically.
There’s no user input to change that. But there should not be any differences in the
way that you change the appearance of a progress bar as opposed to a slider. I’ve seen an API that you need to use a different
property name if you change the value for slider, and when you look at the progress
bar it’s also different property names. When you apply the polymorphism to properties then
a set of property names that the user or the developer might use tend to convert to a particular
pattern. What about functions? Let’s say you have pointer.
You need to move it to somewhere else, and you also have a rectangle you need to move
it somewhere else. It’s a matter of applying translation to this point and rectangle. But
in some cases they might have different names. In this bad example apparently to move a rectangle
you have to use translateBy. There’s an additional two letters there. That’s completely unnecessary. In this example, again, it’s very obvious
because it’s one after another, but those might be separated by several thousand lines,
they may live in different files, and therefore it’s not so obvious. If you pick function names, try to look at
existing objects that have similar functionalities or similar types, and then try to infer static
polymorphism from there. We see the choice of naming properties and
functions, but there are also many cases where you have to have a little bit of different
ways to create an object. A rectangle can be characterized by a corner point and the
dimension, the width and the height. I can write the code like that where I create the
corner first and I create the dimension, and then I go on and create the rectangle that
takes the corner position and the dimension as the parameters. But then there’s also another constructor
in that rectangle that accepts four numbers, as opposed to one object that represents a
corner and one object that represents dimensions. Apparently in that bad API example, if you
create the rectangle by passing four numbers, it has to be the top left position and the
bottom right position. It’s easy to fix if you’ve seen this code because all you need
to do is to change that particular constructor to accept also four numbers that more or less
represent the corner position and the width and height as the dimension. Again, that’s
the difference. On the left side it’s x1, y1, x2, y2, which
doesn’t really match with the corner and dimension arguments in the first type of constructor.
Whereas on the right side you have XY and width and height that loosely match as if
you will have written the construction by using corner and dimension. This is the perfect moment to inject my complained
about JavaScript. You can have a variable that contains NaN, not a number. Oh, I want
to check whether this X is NaN or not so you can use isNaN which gives you true. But apparently
if you compare X to NaN it gives you false. So this is some stuff that really, really
confusing in JavaScript. This is why I have an annual tweet about this. NaN stands for
Not a NaN. [laughter] This is an example of a bad API where you
will expect that it’s NaN and comparing X with NaN will return the same value, but they
don’t. The world is fantastic. You have double rainbows,
no inconsistency. But as programmers we are lazy so we tend to write shortcuts written
to make ourselves feel convenient by avoiding the need to write a lot of lines of code.
Therefore we invent shortcuts. If you ever play Romeo and Juliet, what’s
in a name? That which we call a rose by any other name would smell as sweet. It’s obvious
that Romeo and Juliet neither one of them was a computer programmer, because name plays
a huge role, plays an important role there. If you ever have the joy of working with Symbian
S60, what Android and iOS developers refer to as webview, it was called BrCtl, which
stands for Browser Control. I don’t know the limitation of the number of characters that
you can use, but not having any vowels at all there makes it really difficult. If you
communicate to your fellow programmers, hey, I just created a new example using BrCtl,
it doesn’t make any sense. Names are very important. The biggest offences probably with respect
to shortcut is DOM event. Yeah, this is really crazy examples. Anyone can tell me what this
true, true, no, no, false, false, false, false, 9, 0 there means? [laughter] This is a case where you want to pack as much
information in the constructor so you don’t need to set the properties or call function
at a later stage. You want to put everything in one line. But there’s no way for any normal
mortals to understand what this code means as soon as you don’t have your DOM API documentation
next to you. If you try to review some code like this, well good luck. But there are also other types of shortcuts
which is popular and is called Boolean traps. Say I want to create a slider. There’s two
possible appearances of sliders, horizontal and vertical. Anyone ever seen a diagonal
slider? If you have two possible choices then usually
the logical way to implement this is by using Boolean. You choose true for probably horizontal
and you choose false for vertical. You might end up having this kind of code. s1=new Slider
(true). If you don’t put the comment line there, there’s no way for someone else later
on to figure out that true there means horizontal. Same thing with vertical. Now it doesn’t only apply to constructor.
It could be any other functions. I know that YUI adopted config objects, so this can be
solved easily by having a special non-Boolean object that sort of gives meaning to the particular
slider. If you have a function that accepts one Boolean,
be careful. Be suspicious. Think about how people are going to use that function. Another bad case of Boolean is if you want
to modify the behavior of a particular function. I have a rectangle here, or widget, or component,
anything that is rectangular, and I want to resize it. Because my application needs to
be very cool I want to animate while that particular component resizes. Then I came
up with an idea, oh, let’s just put additional Boolean values there to indicate whether I
should animate that resize or not. You end up having this code. Resize, some numbers,
and then true. Without looking up the API doc, who will imagine
that true here means please animate this. Even more confusing if you put false because
does that mean we should not resize the size? It’s totally confusing. Of course the easiest way to solve this, again,
to pass a rich object there, or probably create a completely different function that indicates
that you also want to animate as the user resizes particular components. Another typical code smell, if you see some
particular code that has Boolean as the last parameters, whether 1 or 2 or 3, you need
to think twice and see what the code is doing. If you create an API that promotes that kind
of behavior you might want to introduce different function or different countermeasures to the
particular behavior. If one is fantastic, how about two? Imagine
if you have this tree and the tree item can collapse or expand. You also want to animate
that because your application is really cool. This is like having an object with two personalities.
treeItem.setState(true, true), so that means you expand it and you animate it. That’s still
probably not so much confusing compared to the next line where it says treeItem.setStat(
true, false). If someone reads that code and doesn’t understand the meaning of those Booleans,
it’s like do we set the state to true and then change it to false or whatever? The next
one is as confusing as the second one as well. If you have a function that accepts only Boolean
parameters, think again. It might be a huge code smell. Forgive my lack of modesty for a while, but
when John Carmack learned about this Boolean trap, my friend suggested to me that you should
not do anything else because it’s going downhill from there. Even the legendary John Carmack
nearly falls into the trap of Boolean traps, so what chance do we have? The last thing is about confusion, ambiguities,
etcetera. Now that we don’t have any more Boolean traps, every name follows the principle
of static polymorphisms, does that mean that our code is not confusing anymore? Apparently
not. Here I’m going to show you some examples. Double negatives. This is one of my favorites.
For a non-native speaker like myself, it’s always a problem. When I moved to the US four
years ago I never lived in an English speaking country before. Therefore as a non-native
speaker you tend to think differently than a native speaker. For example if Tilo asked
me hey, Ariya, would you might if I borrow my pen? My answer would be yes. Yes you can
borrow my pen. I don’t mean yes, I do mind that you borrow my pen, I answer to the spirit
of the request, not the particular grammatical semantics of that request. Because I don’t
think that way. My mind doesn’t think that way. That means in some cases you might want to
consult your fellow non-native speaker to see if your API makes sense. Like X.disabled
false. We can just write X.enabled true. Or Y.setHidden(true), you just put setVisible(false).
Or caseInsensitive=true. This is even confusing. Does that mean capital A equals lower case
A if caseInsensitive=true? It’s even more confusing if every component,
every object adopts different behaviors. Some has enabled, some has disabled, so if you
want to control the state of this by this property then you have to put a Boolean node
up in front of that. That’s just really, really messy. So be careful about double negatives. We usually talk about the existence of some
things, not the lack of existence. 20 per cent translucency is a bit difficult to understand
compared to 80 per cent opaque. If you’re a big fan of Starbucks or Peets try to do
AB testing to your barrista. Go there and then say my cup is three quarters empty, or
my cup is one quarter full, can you refill it. I want to see which one is easier to understand.
Usually we understand the concept of we have heat not we don’t have lack of coal. It’s very important to choose particular words
that give the existence of things. Nonverbal actions. This is like the passive
aggressiveness world of API design. Again, non-native speakers usually have problems
with this. If I see status.message ready it doesn’t tell a lot about what does this function
do. Can it be more explicit? Or in typical navigation API, forward and backward. If you think these are not explicit then you
can change it so it indicates some sort of action is happening there. goForward and goBackward,
they are much more explicit then just forward or backward. Same with showMessage, because
then you can have hideMessage for example. So there are APIs where if you pass nothing
to message then it hides the status. This is all confusing. But if you have status.showMessage
and status.hideMessage then it’s easier to follow. It causes less confusion. Conversational style that is adopted into
APIs is also really bad. If you have a calendar picker and then you choose the property names
as yearFrom and yearTo, it kind of makes sense when you discuss this with your fellow programmers.
But what you should really choose as the property names is something that makes sense. You have
to be able to say the minimum year of this particular calendar picker is this number,
or the maximum year and this number. A little bit more different is like this.
If you try to check in you can say hey, my name is Adam, my flight is from San Francisco
to New York. You can write this kind of code. this.callMe Adam, and flight.from and flight.to.
But according to the previous example that I’ve shown, it will be easier if you can read
it aloud. You may need to change the choice of your property names there. It should indicate
that the name of this person is Adam and anything that involves source and target departure
or destination airports and so on. Just because you can converse in that style doesn’t mean
that you have to write it that way. String extraction. This is really, really
crazy. JavaScript has this function called substr, and you pass two numbers. If you pass
3 and 8 you get this string. Conf2013 because you start from the third position which means
fourth because the index starts from zero, and you get 8 characters. But if we flip the
arguments then obviously you start from the eighth position and you get 3 characters.
So far so good. But apparently there’s another function called
substring. Substring works differently. You still need to pass the numbers, but the first
number indicates the beginning and the second indicates the end. If you pass 3 and 8 to
substring you’ll get conf2 instead of conf13 because you stopped at the eighth position
which means you have only 5 characters there. If you flip the order then substring is smart,
it automatically swaps it. Substring(8, 3) is exactly like substring(3, 8). You still
get conf2. This is getting better. There is a function called slice. Slice, if
you pass 3 and 8, works exactly like substring. But if you pass 8 and 3, apparently it’s not
that smart. You try to slice something from the position that is behind the beginning
so it returns an empty string. If you have your documentation handy, it’s
easier to realize what’s wrong with this. If you Google for this there’s tons of Stack
Overflow questions just explaining this question. Slice is probably not that dangerous because
it has a complete different meaning than substr and substring, but substr and substring it’s
always confusing which one should I use, because they accept the same amount of arguments,
they behave almost the same, getting portion of strings. But the outcome can be day and
night. If you try to invent an additional function
that has almost the same name, be very careful. Apparently string is not as worse as array.
If I have an array it has three elements and I do a slice on that , my original array remains
the same. But I get the new array from the second line of code, which means slice from
the position 1 to 2, which means I get only one element. This is straightforward, easy
to understand. But apparently there’s another function called
splice. Just one character difference. The impact is huge. First of all, splice modifies
your array. If I call a.splice(1, 2), a changes. It mutates my original array. What I get from
splice, which is b, is also completely different from what I get from slice. This is the problem of immutable versus mutable.
If you just look at the name of the function you will not know whether hey if I call this
function am I safe? Am I going to be changed by this function? Because nothing there tells
you about that. And of course the fact that it returns the different outcome although
they may have the same name refers to the original problem of string functions. I don’t know about you but I have fixed bugs
just because of this and because of the confusion between substring and substr. If you have a function that is a verb, it
makes sense to make sure that it implies some actions. If I have a point and I call translate,
you would expect that that point moves because I apply that translation there. But if you
try to infer that behavior to different things, like trim, what do you think is going to happen
to s? This particular JavaScript trim comes from
Java implementation of trim which works on immutable strings. Nothing will change in
s. It returns a new string that has all the space of string. If I read that code, p.translate,
it modifies p and I write the code. s.string, well apparently it doesn’t modify s. One way to solve this is by having an explicit
immutability feature or mutability if you may say so. For example, p.translate means
because it’s a verb implies an action on that object, but if I want to return a new object
that is p but translated then I have to call it p.translated. Obviously I need to assign
this to different variables. If we have that luxury then we can work on
trim, like trim and trimmed, because the second one returns a fresh new string that’s exactly
as but with all the spaces removed. Now that you’ve seen static polymorphism,
then just shortcuts and then consistency or confusion because of semantics, let’s see
some of the best practices. I’m hesitant to call these best practices just because there
are so many best practices out there. But more like what kind of processes and frameworks
that you can put in place just to make sure that you don’t have this hall of shame of
bad API. First is you have to make everything private
by default. Never, ever, ever expose anything, because once it’s public you cannot take it
back. There is a nice story about this particular
Windows API function, shell function called StripMneumonic because if you can see there’s
a typo there. There’s a whole story behind this. The idea is that, or the short version
of the story is that this was internal function but it gets used by a lot of teams in Microsoft.
Therefore the order came that this function needs to be public and that escapes a final
review. Also because once a function that has a wrong name is being used by one hundred
applications, you need to change all those hundreds. It’s a mess. So when you change, oh I’ll just write a simple
function, nobody’s going to use it, also please be careful with the naming. It’s like the toothpaste. If it’s out of the
tube then good luck trying to put it back. And you can only make it public by some sort
of justification. A good guide that a lot of people practice is that if you create a
function then write examples that use that function. Don’t just invent a particular property
just because you think someone will use it. Maybe nobody’s going to use it. Maybe you
think highly of yourself. But if you write the function then you get
to see all the codes, all the bad examples that I’ve seen before you can catch it immediately
as soon as you write examples that use your particular API. If you create the function
then make sure you come up with examples. Maybe you can force it even in a pull request.
Hey, you created a new public function, where are those examples. Otherwise reject it. Mandatory API review is also very useful.
Before every release, before you create even preview release, it’s very nice to just print
out all the names of new functions or that are introduced or new properties or new objects,
and then have a lot of eyes check that and see that, review that and get the feeling
whether that’s good or not. In the worst case if you need the functionality
but you’re not sure about the naming then you can still make it private. The third time’s the charm, because I have
this theory that you’re going to fail your first two attempts anyway, so make sure you
write really quickly and therefore in the hope that the third time will be fantastic. You probably might have seen this in a marketing
twist of any organization because they will launch the first version as super revolutionary,
and then the second one as super fast, it’s 10 times faster than version one, which is
a way to say we screwed up. Then the third time is designed from the ground up to be
better than the previous first two versions. Again, another way to say the engineering
team screwed up again. If you have this API review then you can have
your Gandalf moment. You want to make sure that no bad API will escape to the public. The last best practice is API tools because
tools separate us from this Neanderthal JavaScript programmer. He didn’t use tools and therefore
he is gone. The basic idea of tools is to get the semantic
understanding of your code. Usually you can do this by having a parser. If you have a
build parser the first state just tokenization splits your code into multiple tokens. In
this example if our answer equals 42 I need to identify which one is the keyword, which
one is an identifier, punctuators, such as equal signs, numbers, etcetera. From there
we can create the syntax tree that more or less represents the syntactical structure
of your particular code. There is a nice standard called SpiderMonkey
Parser API. Again, same examples. You can get this object from JSON that is the textual
representation in a tree of the diagram that I have shown in the previous slide. You can
play with this visualized tree version. Just go to that URL and pass your code and then
you’re going to see the syntax tree as a tree. Now if you already have this then you can
do a lot of analysis on the syntax tree level. For example, you can get the meta information
or metadata or meta-object about your particular module. This is just a hypothetical framework.
If this is the way I create a module then you can parse the code on the left side, traverse
the syntax tree and then extract all the property definition functions belonging to this object,
the object name, etcetera. One of the particular uses of this is that
you can, for example, blacklist all those double negatives if they show up in the property
names. Or even you release new version, you have to make sure that no function got deleted
accidentally. So you compare the meta object of both versions. This is very important for
backwards compatibility, or even forward compatibility. If we talk about blacklisting, in particular
a specific set of property names, if I have a code foo.bar and you parse it and you get
the syntax tree, some portion of the syntax tree might look like this. There’s a MemberExpression.
This is the terminology used by the ECMAScript standard as well. The object for that MemberExpression
is foo and the property name is bar. You could totally write some code that traversed the
syntax tree and will figure out if that node is a MemberExpression or not. If that’s the
case then you can print out the property name. If you do this on your whole program, it’s
going to print out all the name of the property. Then you can do grab or whatever to analyze
whether it’s blacklisted or not. You can collect all those expressions. You can also detect Boolean traps that I mentioned
before. This is reload(x, y, false). If you look at the syntax tree produced by that code
it will have the callee, which is reload, and then it has three arguments. First argument
is just a normal identifier, x, y, and the last one is the one that we’re concerned with,
which is a Boolean literal. You can have a function that checks the node, sees if that
node has an arguments property, and if the few last ones are Boolean literals. You can
do this to one argument function, two argument functions, etcetera. There’s also a way to blacklist function names,
just like those double negatives. setDisabled(false) will generate this kind of syntax tree. You
have the callee which is setDisabled, and we don’t really care about the arguments.
The code to do this is left as an exercise for you. What about API usage? We talk about the design
of API but if the API is already being used by tons of applications and libraries, how
do we detect that? I’m not really aware of some tools that allow you to do that right
now, so this falls into the category next generation for our future. For example, it would be lovely to have these
two warnings. You call this immutable function but you never sign its written value. This
is an example where I trim string but I didn’t do anything with the outcome of that trimming
action. Or translated something. But that requires knowing that if you have this function
name that is immutable then you have to assign it to somewhere. You need to understand the
convention behind that. There is another tool in the C++ world that
can do the second thing, which is you check the return values of this function a gazillion
times but one time you forgot it. Was that intentional or was it an honest mistake? It
would be lovely if we can have that kind of feature. To recap, make sure you apply static polymorphism.
If you invent shortcuts for your convenience, be careful, it may be dangerous. Judge every
single possible shortcuts. And read your code, because that makes a huge difference with
respect to confusion and its semantics. If you do a code review with respect to API,
for example you want to detect all Boolean traps, you might want to collect all those
kind of API tools or API detection problems in your CI system. For example someone creates
a pull request then when that job gets delegated to the Travis CI it will tell you if this
particular patch suddenly creates a function that has Boolean traps. Therefore before a
human reviews that code there’s already a warning that that might not be the best thing
to do. Thank you very much. [applause] Andrew: We do have some time for some questions.
Do we have any questions from the audience for Ariya? Audience member: Testing, testing. There we
go. Emily, you’re on. Emily: Regarding the double negatives type
thing, you mentioned disabled as being something that’s kind of frowned upon in your view.
Do you have any suggestions for if you are working with a very large code base and you
find the sudden need that you need to be able to disable an action but it’s used everywhere
and you can’t realistically add an enabled flag everywhere, so instead you decide to
say disabled true. Therefore at a high level when you say are checking for whether or not
this thing is disabled, you can just check to see is disabled true. Ariya: Yeah, you mean a flag that applies
to the entire thing so you don’t need to disable each individual components. I don’t think
I have an answer for that. I think it may require completely different properties that
signify the nature of everything that’s being disabled. It could be a function name so you
need to call it potentially. As for the Boolean check, personally I still
prefer isEnabled, just because it doesn’t have a double negative. I think it boils down
to preference. If in some scenarios the code makes sense then it’s fine, but what would
you want to avoid at all costs is to have a mixture of both, inconsistency between the
use of negative and double negative. Audience member: Thanks, it was a good talk.
Good points. There was a discussion on Rebecca Murphey’s blog some months ago. Maybe a year
or more ago. It was about the distinction… At what point do you have too many parameters
in your function? I was wondering if you have an opinion on that, taking individual parameters
versus taking an object with property names. Is there a certain breaking point that you
feel is a good point? Ariya: I don’t have an opinion. Am I live?
Yes. The number of parameters before it becomes too long, I don’t have any specific threshold
for that. I think it depends on the team. If you have experienced programmers, if you
still pass four or five arguments, it may still survive. It may not. Audience member: Sorry I’m going to cut you
off there too. Ariya: Sure. Audience member: Then the other question I
had was that you didn’t mention anything about optional parameters. Do you have opinions
about optional parameters, where they should be? Should they be there, should they not?
That sort of thing. Ariya: Optional parameters in my opinion is
not that bad, meaning that it may not cause crazy disasters like some of the examples
that I’ve shown before. I would totally leave it up to the team’s decision as to whether
you want to use that practice or not. Audience member: But let’s say you had a function
that had four parameters, three of which were optional. Does that mean you pass in a value
for the first one… Well, so the first parameter is always required as opposed to one of the
four being required. And then do you lock down the signature to
say you pass in the optional one in the index that it must be placed in? Or do you scan
the signature to see if something was passed in the first two then it means this, and if
something was passed in the first three then it means this other thing. Ariya: This is kind of solved with ECMAScript
6 because you can have syntax that tells that argument to be optional. Then you can build
static analysis tools that looks for that particular usage and see whether you call
it or not. But whether I want to lockdown or not… I’ve used both. I also abuse optional
arguments in some cases. It doesn’t cause a lot of damage so that’s fine. I think it
needs to be on a case by case basis. Audience member: I know your talk was primarily
to do with the public API. In YUI generally every method is public. We just denote privacy
with an underscore prefix. But I’ve been guilty of doing a couple of these things for some
of these private methods because I feel like I’m the only one who’ll be using them. Especially
having a lot of arguments or having optional… Is that something I shouldn’t be doing? Do
you think I should take… At what point do I use these concepts? Is it just for the public
API, or even if I’m making these internal methods which I’m calling and I don’t expect
anyone else to call. Should I be this rigid in that sort of set up as well? Ariya: It’s more like an undocumented function.
It exists, but you should not use it. At least the public should not use it because we may
change it. It would be fantastic if you apply all kinds of good API practices to that, but
the worst case is still not supposed to be used by the world. It’s not the end of the
world. However, at least collect all those new APIs
during the API review and then prioritize the one that needs to be public. If you have
resource time etcetera then include the view of all those functions marked with underscore.
Other than that, if you tell the customers or the users we may change this, we mean it,
then it’s not really your fault if you have to change that. Andrew: Do we have additional questions? Any
more questions? Okay, go ahead. Audience member: Am I on? Alright. Do you
make a distinction between public but documented to be private versus true private? Because
in my own experience true privates are a pain in the neck when it comes time to debug or
hotswap or anything like that. If you need to do any sort of customization then true
private’s really difficult to work with, or test actually. Ariya: In an ideal world, yes, we should leave
it true private, but we also have other priorities so I can… Personally I can totally understand
if you set aside this is something that we will fix in the near future and therefore
doesn’t fall into the analysis of good API. I think as long as you create something that
exposes modules and objects, whatever, then at the very least you want to make sure that
the usage is not confusing. Yes it may have Boolean traps, yes it may have other kinds
of possible shortcuts that you have, but the disaster like slice and splice, that should
be in your radar. That’s the thing that may cause bugs as opposed to it just looks ugly. Audience member: Just as a side note, substr,
substring and slice also deal with negative indexes differently, which is bonus fun. Audience member: Okay, so great talk. We had
a lot of fun I think, everyone had a lot of fun. I just have a question. What’s your take
on functions versus classes? For instance you said that for instance it could be a way
to solve the problem in which you have some methods that mutate the object, some others
that don’t. For instance instead of using trimmed you could say I can have a function
trim that takes the string and returns a string. Ariya: Functions versus plain vanilla function
calls? Audience member: Yeah, so function versus
classes for solving this kind of problem. Ariya: For the trim example, I think having
a class is a bit of over kill. Audience member: The string class array has
it, so… Ariya: Any similar things where you just want
to apply a certain operation to the object that you have… Having a consistent set of
two different groups of functions that this is going to be mutable and this is not, I
think it’s easier. Yes it’s nice to have another additional or optionally mutator object that
works on your object, but I think it’s too much of an effort. I don’t think that gives
a lot of benefit. Andrew: Okay, we have time for one more question.
Alright, thank you so much Ariya for coming this evening. Ariya: Thank you. [applause]

Leave a Reply

Your email address will not be published. Required fields are marked *