Some languages say yes, some say no.
Does a queue type need Pop() and Pop(n), and Peek() and Peek(n)?We can probably analyze for hours the pros and cons of the LINQ extension, or any other API.
There is no one answer, but you should at least ask yourself that question.
Method DeclarationWhat does the following code does?var obj = createSomething()save(obj, true, true, true)It probably saves the obj parameter somewhere, but what do the three Boolean values mean?Without looking at the declaration of “save(…)”, there is zero chance to figure it out, because it does not provide context.
But what about the following:var obj = createSomething()var options = { toRemote: true, asJson: true, forceOverwrite: true }save(obj, options)While the second version forces the user to write more code, it is inherently more understandable.
On another hand, what about this API:GetStudentById(string id)Seems straight forward and simple.
But here we have another kind of waste.
Why not simplify more and just:GetStudent(string id)There is no way to query for a specific student other than its ID, so the explicit context of “ById” is not really necessary.
If you came across this code:GetStudent(“123456789")You could assume that the parameter is the student ID, since it’s probably not his address, phone number, or name.
There is already a lot written about code smells such as too short/long method names, long parameter lists, and so on.
All are relevant and should be kept in mind when designing your API.
No Take-backsIf you write a method in your API, you have to keep supporting it, or improve on it and deprecate the older method.
I’ll explain why with this an example:I unfortunately got the chance to work with a third party system that did not follow this rule of thumb.
Until version 3.
3, their product had some function X.
In 3.
4, they removed it.
Not deprecated, removed.
Our product broke and we had to scramble to find some other functionality within the new API that will do what we needed.
If you are writing an API, you have to think about it as if it will remain forever.
Or at the very least, it’ll be a huge pain to someone when you do change it.
TestabilityTestability is a topic that actually has many facets.
One from the programmer point of view in creating classes and interfaces, and using frameworks for Dependency Injection, to enable unit testing.
Another, from QA point of view, where the code has evidence of operation.
From the obvious one of having the system actually work, to various logs, an operator menu, or whatever else you think is helpful.
A third, is from an team work management point of view.
That in order to complete a piece of work, it has to be defined with testable results.
A new web service responds with 400 when performing a request to it.
An overwrite warning is shown when the user enters a file name that already exists.
Sometimes, considering these factors can mean that our design changes.
It could mean we would add a way to configure the mode of work for each feature, or create our features in a manner that they can operate while disconnected from the entire system.
In the past, We’ve designed a DLL with an API that was free of the context of the entire application, only so that we could later write a console application to use it manually, for verification and validation purposes.
ReadabilityI think I’ve heard the myth of “self documenting code” dozens of times before that significant course.
It would appear in different conversations:When talking about naming conventions: _variable to indicate a private field, var x versus Boolean x, getIndexInArray(…) instead of getArrIdx(…)Or when discussing APIs, or having short methods, or class names, or whatever million of other topics.
I call it a myth since I find it something to strive for, but I can count on one hand the number of times where I encountered a new piece of code and did not need to look at comments or external documentation.
Domain Specific LanguageThe example I think of for self documenting code is StringBuilder.
It always looks like this:var stringBuilder = new StringBuilder();return stringBuilder .
append(’hello’) .
append(‘world’) .
replace(’h’, 'H’) .
toString();If you guessed that the return value is “Helloworld”, you’d be very correct.
The reason for this high readability is called Domain Specific Language.
The idea is to create a sort of coding language for our system.
This language won’t be powerful enough to code everything, but for the specific problem domain, it will be easier to use than a general one.
To do this, the API is usually defined as:Class T { T operation(…) T configure(…) And so on…}First, most of the API will return the “this” object, allowing for this style of code where we concatenate calls one after the other.
Second, the concept is to break down the desired API into something that resembles an actual sentence.
The instance is the subject of the sentence, the methods that do something are verbs, and the rest are the other various parts.
First, a non DSL example of a client side code that tries to send some payload to the server via a HTTP Post request:this.
http.
post(url, payload, { headers: { content-type: 'text' }, observe: "response", params: { containing: "Jones" },}).
subscribe(response => { .
});If you are familiar with web client code, you could probably figure out what this code does.
But what about someone that is less experience?If we write the same logic, in a DSL way:this.
http.
newMessage() .
method(POST) .
to(url) .
with(payload) .
add(HEADER).
named('content-type').
toBe('text') .
add(QUERY_PARAM).
named('containing').
toBe('Jones') .
observe('response') .
send() .
subscribe(response => { .
});I hope that every programmer, no matter the experience level, could look at this code and figure out what every bit of code does.
It’s not easy to create a DSL.
You need to consider that the APIs could be called in any order, and have the ability to handle it.
On the other hand, if you take a look at the Angular HttpClient documentation of the post method, you would see (currently) 15 different overloads, each of them with multiple ways the user can make mistakes.
Since we are little, we learn to read words, sentences, and paragraphs.
If you make your code look as close to what we are already familiar with, it becomes easier to read, even for a complete layperson.
These things now live in my head, and they only grow, expand, and evolve as my experience writing code grows.
My process for writing code is different now that it was almost seven years ago (thankfully), and it takes more time.
But I have never found myself regretting thinking of them before writing the code down.
Oh, and let’s not forget about design patterns and anti-patterns, compartmentalization, class diagrams, looking at open-source and third party solutions, and on and on and on….