Knowing how to program involves learning a programming language. Like languages in general, there are many different kinds of programming languages which offer different (and maybe subtle) structures. Languages can share similar roots (such as Latin based languages), and therefore some attributes such as grammar. Languages can be a reflection of a culture and also lead to different ways of thinking, so knowing multiple languages is a great benefit to advancing your skills (in programming or beyond).

I saw a recent post asking why someone should learn Swift, so I started thinking what are some of the things I’ve learned from programming languages.

Basic and then Visual Basic taught me some of the magic of creating from virtually nothing to a working useful program. In retrospect, it also showed me how easy UI programming could be with a UI builder; programs that can help with programming are very useful tools.

Turbo Pascal taught me general imperative style programming with records. It also made me aware of operators and all these years later, I still wonder about having an explicit := operator versus overloading =.

C taught me about pointers, memory managment, heap allocation versus stack allocation, and type casting. It drove home the pains of manual memory management and the random segfault.

C++ taught me about classes and inheritance, polymorphism and virtual methods (e.g. dynamic dispatch versus static), templates, and namespaces. It was the first programming language where I felt that the syntax with all the templates and operator overloading was a bit much, especially when reading the source code for things like Boost.

PHP taught me about the ease which you can put a website on the web. In retrospect, it also showed the great power of having a single request/response context lifecycle. Not having to worry about multithreaded access to a variable, concurrency deadlocks, etc. makes for a much simpler programming model.

Java taught me about interfaces/protocols, bytecode and virtual machines, garbage collection, package management and distribution (e.g. Maven), schemas and the advantages/disadvantages of XML, multithreading in a server based environment, exception handling, and enterprise design patterns (for better or worse). JavaDoc was also very influential as well as automated unit based testing.

Scheme taught me about functional programming and side-effects. It also showed me how beautiful and ugly parentheses are.

JavaScript taught me the power of what a runtime enviornment can do and the power of a platform. The prototype based inheritance is interesting, but JavaScript’s ability to continue to evolve and power so many critical functions today (within just the browser) is amazing. Of course, the actual JavaScript language in the early days of the web is very different than today. The DOM, event handling, closures and capturing of contexts, and callbacks are other things that I learned with JavaScript. Promises and the async/await coroutines are also some recent things I’ve picked up. While all of these are great leaps and strides over the original language, it is really the power of the web platform that has made the continued investment in this language worthwhile.

Objective-C taught me about reference counting and dynamic messaging passing. From the Cocoa framework, it taught me about the power of immutability versus mutability, practical design patterns, and framework and API design. Grand Central Dispatch (a.k.a Dispatch) taught me about different ways to think about concurrency.

Ruby taught me about the power of duck typing. While not particular to Ruby, the community around Ruby on Rails taught me about the power of community derived conventions and common abstractions. It also taught me about monkey patching, and how programming languages/libraries/frameworks should really be meant to be joyful. Ruby is also the language where I learned how TDD is almost a must have skill for some languages.

Node.js taught me about event loops and how one can really re-purpose a language from one environment to another. It also showed me how micro-libraries and the framework of the hour can both help and harm the community.

Swift is teaching me about protocol oriented programming.

Go is teaching me more about co-routines and different ways of looking at interface design.

Rust has taught me about memory ownership in ways that I like and dislike.

If I were to name the most influential languages, I would have to say C, Scheme, and JavaScript. Each one of them has a fundamental trait (e.g. memory management, functional programming, and closures) that practically define the usage of the language. Rust may also be along the same lines eventually as I use it more.

From an API/framework point of view, Foundation/Grand Central Dispatch/Cocoa (Objective-C/Swift), and Ruby’s libraries are perhaps the most fun to work with. Swift’s Standard Library and Rust’s have perhaps the most modernized abstractions (which can be great but also frustrating like working with individual characters in Strings even though it is correct and safe).

If I were to suggest a programming today, JavaScript is something everyone will probably eventually work with. However, for fundamentally changing how you program, Scheme (for functional programming) or Rust (for a modernized take on all the previous systems programming langauges) would be my choices with a nod towards Rust for practicality.

One of the benefits of basing an API on schemas is the ability to use code generators. Generated code can have some disadvantages like generating hard to understand code and difficulties in customizing a request beyond what the generated code allows. Personally, in many cases, I find manually written code to more elegant. However, for schema-based code, code generation is a tool that can quickly and consistently build good solutions.

Generated code should be consistent across all API requests and responses. Therefore, once a request is made and a response is processed, the usage knowledge should apply to all requests and responses. If there is a bug in the generated code, a fix can be consistently applied to all of the applicable code. Furthermore, if there is a need for clients in different programming languages, code generation can ensure that all languages are able to get access to the new APIs with minimal effort. In effect, a code generator can be a codification of how clients should interact with an API.

Code generation applies to more than code for APIs, but it is especially suited to API client SDKs. Client SDKs are tedious to maintain, and eventually maintaining multiple programming language bindings will be required (if not immediately, eventually). Schemas can help maintain and verify API behavior but generating code can ensure a consistency from the clients as well. When a new API needs to be exposed, instead of an engineer having to recall how to write the SDK code (and keep the code consistent with the rest of the SDK), the code generator can be given the schema and output the code.

In API SDKs, there is usually a base protocol client such as a HTTP client. The client can be coded manually and expose unique features per platform. The generated code is usually the requests, responses, and domain specific objects.

The generated code can also be generated in a way to allow custom protocol clients to use the code. Therefore, the code can still be of some value where someone wants to quickly interact with the API but wants to customize the protocol behavior. Imagine an app that has specific requirements for timeouts or an app that needs to use a specific pool of HTTP clients for outbound requests. If the generated code is not coupled with the protocol client, it can still possibly be used to serialize/deserialize the request/response.

While I’ve not had a strong preference towards code generation in the past, code generation can be a great tool, especially when API SDKs are needed.

While a successful 2xx HTTP response is what most clients should look for, additional metadata is usually included in the HTTP response. For instance, a correlation ID can be provided.

A correlation ID is useful in identifying a request. It is commonly used where the initial API endpoint (usually a load balancer or a request router) creates an ID, and then the ID is propagated throughout the service’s systems (e.g. when calling downstream internal services). Logs and metrics can use the correlation ID as part of their context, so it is easy to lookup related logs/metrics using the correlation ID. In effect, the correlation ID can be used to trace a request’s execution path across service boundaries. The correlation ID may be propagated to the initial client as part of the HTTP response.

If you are operating a client to a third party service, it is generally benefical to store correlation IDs for a period of time. When there are issues with processing a request, giving the correlation ID can save time for you and the support team.

Another tip is that you may want to keep correlation IDs for both failed requests and successful ones. There may be times when “successful” requests need to be investigated.

Correlation IDs are also commonly called request IDs, trace IDs, and debug IDs. While there are possible subtle distinctions, in the end, they are useful in isolating relevant data when communicating to a support or development team.