On holiday in France. It's nice here!
Lots of interesting references here, and memorable quotes (as is often the way with tef's posts).
"If some data means two different things to different parts of your program or network, it can be exploited - Interoperability is achieved at the expense of security."
Examples from the Perl/C interface, TCP/IP, confused deputy, XSS.
"Notably, HTML5 gained a standardized parser, not for security reasons, but to ensure that bad HTML looks the same on every browser."
"Interoperability doesn't just mean working in the same way, but failing in the same way too."
Sensible notes on API design from someone who has very much been in the trenches.
- Public APIs are forever: one chance to get it right.
- Make it easy to do the right thing, difficult to the wrong thing, easy to evolve.
- Just powerful enough to satisfy requirements.
- Gather requirements, and make a 1-page spec. Share. Pretend to code against it. Take example programs very seriously.
- Aim to displease everyone equally.
- Do one thing and do it well. Good names drive development.
- When in doubt, leave it out.
- Don't let implementation details "leak" into API. Design serialized forms carefully.
- Minimize accessibility of everything.
- Documentation matters. Document everything in your public API.
- Bad decisions can limit performance; but don't warp the API to gain performance. Good design usually coincides with good performance.
- API must coexist peacefully with the platform: transliterated APIs are almost always broken.
- Minimize mutability. Prefer immutable; if mutable, keep state space small & well-defined.
- Don't make the client do anything the module could - reduce boilerplate.
- Don't violate the principle of least astonishment.
- Provide programmatic access to all data available in string form!
- Use consistent parameter ordering across methods.
- Avoid return values that demand exceptional processing (e.g. return an empty collection instead of not_found).
Cute tutorial on using ed. Fun to work through. There's a lot of other interesting stuff at this site, e.g. the "Unix as IDE" series.
A set of notes on things that may limit an Erlang system's scalability:
- Avoid NIFs if possible; e.g. use MessagePack rather than JSON;
- Be careful what BIFs you use (example of erlang:decode_packet/3 in Cowboy);
- Use binaries rather than lists, including for buffering/streaming;
- Don't hesitate to create a custom pool of processes to do what a single gen_server might; similarly, a custom supervisor might sometimes be the right thing.
- Use ets public or protected tables for LOLSPEED(tm).
Clearly-written details of how goroutine stacks work (and how they soon will).
Now: "segmented" stacks grow by allocating new segments with accounting information to find the previous outgrown. This can cause a "hot split" issue where the stack keeps growing and shrinking at the segment boundary, and releasing the new stack segment each time is expensive.
Soon: "stack copying" creates a new segment double the size, and copies the old data to it. There's some accounting work that needs to be done here for pointers to stack data, and the Go devs are currently rewriting a pile of the runtime in Go to make this doable.
This will also enable concurrent garbage collection in future - something which really helps in Erlang - though there are open issues with how this will work for shared heap objects in Go. I tend to prefer the Erlang shared-nothing approach ...