Around IT in 256 seconds

#58: Consumer-driven Contracts: TDD between services

Consumer-driven Contracts is an approach to testing integration between services. In a distributed system, many components talk to each other. Typically via request/response protocols or message queues. The client must know and understand the API provided by the server. What kind of endpoints are available, what formats, request/response schema. Without consumer-driven contracts (CDC for short), we are often reckless when it comes to testing. Maybe we have a bunch of smoke tests against a mocked server. Maybe we copy-paste typical responses from the server's documentation. But both client and server can evolve, breaking the integration in unexpected ways. CDC attempts to codify the API without explicit schema and coordination.

#57: Kotlin: Much more than "better Java"

Kotlin is a programming language that runs mainly on Java Virtual Machine. This means it's fully interoperable with Java and even other JVM languages. Developers can gradually rewrite their applications from Java to Kotlin. Or use Java libraries and frameworks inside Kotlin. But why bother with a new language? Kotlin has plenty of improvements over good old Java. Sometimes it's placed between Java and Scala in terms of capabilities. It seems more modern, agile, and powerful.

#56: Test-driven development: It's not about testing

Test-driven development (TDD for short) means developing software by writing tests first. I hope you all write unit and integration tests. But do you write them *before* the actual production code? This approach to software development is just that. You must write a failing test first. And you are not allowed to write even a single line of production code without a failing test. Think about it. If all your tests are green, it is forbidden to write production code. Everything must start from a red test.

#54: Immutability: from data structures to data centers

Immutability means that when something was once created, it can't be changed. This concept is tremendously important across our whole industry. Probably you've heard about immutable data structures. Let's take an immutable list as an example. If you create such a list with a few items, you can't add more items to that list. It's written in stone. Any action attempting to modify that list returns a modified copy. The original instance is left intact. Modifying a single item, adding or removing, sorting - each of these operations return a copy.

#53: CDN: Content Delivery Network: global scale caching

CDN is a set of geographically distributed servers for fast content delivery. Without CDN all requests are routed to your own server, located somewhere in the world. For example, in San Francisco. If your visitor lives in Australia, the experience is rather poor. But now imagine the traffic to your website is proxied through a global caching layer. Your visitor in Australia downloads data from an edge server nearby. A different visitor in Cape Town, Africa, will be routed to a completely different CDN server. The routing is done by the CDN itself, typically via DNS. It's transparent to your visitors. Of course, all CDN servers contain the same data. Moreover, pretty much no-one contacts your own server in San Francisco. Only the CDN network itself. Technically, visitors don't even know the address of your origin server! They use domain name like `example.com` and DNS routes to appropriate cache server.

#51: Cloud computing: more than renting servers per minute

Cloud computing is a broad term. In general, it refers to using hardware and software managed by someone else. Typically with very flexible pricing: we only pay for what we use and for the time we use it. We don't build data centers ourselves. We don't buy large servers and provision them. We simply rent a server on a per-minute basis. The cloud provider has a pool of servers and they are reused and recycled. Once we are done, we no longer pay and some other customer can use that same server. Just like we don't own a taxi. We barely pay for kilometers and minutes. When the server breaks for some reason, the provider takes care of repairs and replacements. We simply, almost transparently, get a new machine.

#50: Property-based testing: find bugs automatically by generating thousands of test cases

Property-based testing is an approach to automatically test software against well-defined rules. We don't specify desired output for a few inputs. Instead, we barely define properties that should always hold. It's best explained with an example. How do you make sure that your compression algorithm works? Ordinary unit tests verify a handful of inputs that you came up with. If you are experienced developer, you will include edge cases. I mean, the weirdest inputs, like an empty string or a long sequence of the same character. And what are the properties of a good compression algorithm? Its output should take less space, obviously. But even more importantly, lossless algorithm should be capable of decompression. What if I told you, there is software that can check these properties automatically? With thousands of randomized tests?

#49: Functional programming: academic research or new hope for the industry?

Functional programming means programming using functions. See, I need much less than 256 seconds for that! Unfortunately, this definition is as useful as saying that object-oriented programming means programming with objects. So let's dive deeper. First of all, I mean *pure* functions as defined by mathematicians. In math, a function always returns the same output for a given input. A length of a string is a function. A form validator is typically a function as well. For the same form inputs it always returns the same result: valid or invalid. On the other hand, returning the current date for a given location is not a function. Or reading a file.

#48: Distributed tracing: find bottlenecks in complex systems

Life used to be simple. In a traditional monolithic application, when a failure occurred, you could easily find the problem. When an exception bubbles up, it appears throughout all stack frames. You can easily examine which methods or functions were invoked from each other. You can see application layers involved. Moreover, it's fairly easy to profile performance bottlenecks. Answering these questions becomes much harder when there are multiple systems involved.

#47: Terraform: managing infrastructure as code

Terraform is fairly low-level software for managing your infrastructure. For instance, it's used to create and provision cloud instances, networks and software. Unlike traditional tools in this area, Terraform is _declarative_. It means you don't define step-by-step, imperative guides. Essentially, scripting your infrastructure with Bash or Python. Instead, you define desired, final infrastructure state. For example, how many hosts, how they should be connected, what kind of software and packages they should contain. Once you apply this configuration, Terraform takes all the necessary steps to fulfill your needs. Here's how it works in more detail.

#46: Kubernetes: Orchestrating large-scale deployments

Kubernetes is a platform for managing various workloads inside containers. Before I jump into a definition, let's describe the problems it tries to solve. Imagine your application consists of several components. It can be microservices, multi-layer application, etc. Each type of component needs to be deployed on multiple servers. First of all, to support fault tolerance, but also to achieve horizontal scaling. Doing this by hand is quite problematic. Manually tracking which servers should host which components is tedious and error-prone.

#45: Node.js: running JavaScript on the server (!)

JavaScript language is primarily used inside your web browser. Your computer downloads a JavaScript file and executes it on your machine. But if you want to build a dynamic website, you need a server-side language. Like PHP, Java, Python, etc. Programs written in these languages handle incoming requests and produce dynamic HTML. HTML that varies, depending on the request, who is asking and what data is available in the underlying database. But for more than a decade we can also use JavaScript on the server. The same language can be used for a very different purpose. Namely, listening and handling web requests. But also implementing command-line utilities and one-off scripts. This became possible after extracting the JavaScript engine from Chrome browser.

#44: RESTful APIs: much more than JSON over HTTP

REST is an architectural style of communication, based on HTTP. It was proposed in the year 2000 by Roy Fielding. In his dissertation he describes the way systems should communicate, embracing fundamental features of HTTP. He puts emphasis on: statelessness, support for caching, uniform representation and self-discoverability. APIs that adhere to these priniciples are called RESTful. This academic paper is quite abstract so I'll focus on what it means in the enterprise. Also, it's much easier to understand what RESTful API is when contrasted to SOAP. And GraphQL released recently.

#43: Public-key cryptography: math invention that revolutionized the Internet

Disclaimer: this podcast is not about cryptocurrencies. I despise them. Instead, we'll talk about asymmetric encryption. One of the most wonderful math discoveries of the 20th century. Before 1970s all cryptographic algorithms were symmetric. This means that the same key must be used to encrypt and decrypt data. That sounds rather obvious. If you encrypt a file with a password, you must use the same password to decrypt it. But there's one problem. Imagine Bob wants to e-mail an encrypted file to Alice. Sadly, Eve can read all communication between Alice and Bob. File was encrypted, so no worries? Well, it's not only encrypted, but also worthless. Alice doesn't have a password. And how is Bob suppose to provide that password if Eve can spy all communication channels?

#42: Flow control and backpressure: slowing down to remain stable

Imagine two independent systems communicating with each other. One producing data and the other consuming it. There must be some place where data is buffered. Just in case the producer generated some data but the consumer is currently busy. For example, incoming requests, messages, packets - must wait. Sooner or later, this buffer overflows and either starts dropping data or crashes altogether. Moreover, large buffers imply growing latency between production and consumption. The consumer is perceived less responsive because data waited for a long time in queue. Especially when nothing is prioritized, so first come, first served. Also known as FIFO, first in, first out.

#41: Unicode: can you see these: Æ, 爱 and 🚀?

Computers speak bits and bytes. Numbers in general. They don't understand images, poems and JSON. When we say "_hello_", it needs to be encoded to numbers. Conveniently, each character becomes one number. A number can then be stored, transfered and rendered on another computer. Therefore, everyone needs to agree which numbers represent which characters. The first commonly used attempt was called ASCII. American Standard Code for Information Interchange. In short, it's a table of 127 symbols and their respective numbers. For example, lower-case _h_ is 104, whereas exclamation mark is 33. There's one problem here. 127 symbols. 7 bits. Of course, it's an American Standard. So it ignores the existence of any other country and alphabet.

#40: Docker: more than a process, less than a VM

When two processes run on the same machine, they are somewhat isolated. For example, they cannot read each other's memory. However, they still share the same file system, libraries, network ports. And hardware: CPU and memory. Docker allows running processes with greater isolation on a Linux machine. Processes like: web servers, databases or web applications. Traditionally, to achieve better isolation, virtual machines were used. Virtual machine is essentially an operating system started inside of another operating system. For example, Windows running inside Linux. Typically you run a few VMs on a single host. Unfortunately, a virtual machine has an overhead. It takes several seconds to start and uses a significant amount of memory. Docker is somewhere in between. Better isolation than plain processes, but it's not quite yet a VM.

#39: DNS: one of the fundamental protocols of the Internet

Domain name system (DNS for short) is one of the fundamental protocols of the Internet. In the Internet all communication is routed through IP addresses. Traditionally, these addresses consist of four numbers, like `91.198.174.192`. Each and every server, as well as your computer, is identified using such an address. But we no longer remember phone numbers, let alone IP addresses! Remembering that the aforementioned IP belongs to [wikipedia.org](https://www.wikipedia.org/) is tedious. DNS is often compared to a global phone book. A phone book that maps easy to remember domains like `wikipedia.org` or `gmail.com` to IP addresses - usable by machines. Without DNS the Internet could technically work. Just like you could use your phone without contacts, memorizing all phone numbers. DNS servers not only free us from remembering IP addresses. They know **all** of them.

#38: HTTP cookies: from saving shopping cart to online tracking

Before we fully appreciate how important HTTP cookies are, let's imagine the web without them. HTTP is inherently stateless. This means that the HTTP server is not allowed and not capable of storing any context between requests. It has no memory of prior questions from the same client. Contrary to stateful protocols like FTP or SSH. They have a concept of long-running session. If you change the working directory during a session, subsequent commands take that into account. This is not the case for HTTP. For example, imagine you just logged in to GMail to see the list of unread e-mails. Now you click the most important one, from the [Nigerian prince](https://www.cnbc.com/2019/04/18/nigerian-prince-scams-still-rake-in-over-700000-dollars-a-year.html). Sadly, the server has no idea you are the person who just logged in. You must log in again. And again. This is where cookies help tremendously.

#37: Fallacies of distributed computing: overlooked challenges

Fallacies of distributed computing are a set of myths we believe, when designing complex systems. And what is a distributed system? Well, if your application is split into hundreds of microservices, it's distributed. Or if you have a single application, scaled horizontally to hundreds of instances. Or... If you have a monolith connecting to a database on the other node. This is a distributed system as well! OK, we have 200 seconds left and 8 fallacies to cover. Let's go!

#36: Microservices architecture: principles and how to break them

Microservices are contrasted to a monolith. Single, large application that implement the whole system. Typically hard to understand, develop, test and deploy. Monoliths tend to become a big ball of mud with each component referencing every other. The idea behind microservices is to split your complex system into multiple independent applications. Small and agile. They communicate with each other via APIs but are otherwise highly decoupled. The independence and decoupling has many aspects: deployment, languages and frameworks, storage, organization. Most importantly, each microservice should be self-sufficient to a reasonable degree. Let's discuss what it means and how often these aspects are violated.

#35: Reactive programming: from spreadsheets to modern web frameworks

To understand what reactive programming is, let's contrast it to _imperative_ programming. Imperative programs can be read top-to-bottom, with occasional jumps. Jumps are `if` statements, loops and procedure calls. Program is executed line by line. If you see `x = y + z`, the expression on the right is evaluated once. Then the symbol on the left is modified. If you change the value of `y` or `z` in the next line, obviously, it won't affect `x`. Compare it to a spreadsheet. Yes, an Excel file. It's obvious that changing any cell immediately propagates to all cells that depend on it, right? The process continues until all affected cells are updated. Essentially, every spreadsheet is internally represented by a dependency graph. We declare which pieces of data depend on which. The rest happens automatically. This approach to developing software is called... _reactive programming_.

#34: SQL joins: unleash the true power of Structured Query Language

In relational databases, data is kept in relations, commonly known as tables. Simplifying, when data is normalized, it's not duplicated. For example, when storing books and authors, you don't keep an author's name next to a book record. Instead, you use a so-called foreign key that references the author in another table. Thanks to this level of indirection, books by the same author do not store repeated information. This has many benefits and one, huge drawback. In order to look up a book together with a corresponding author you must somehow correlate these two tables. This is called joining.

#33: OAuth 2.0: safe, password-free authorization

OAuth 2.0 is a standardized authorization protocol. In this episode, I'll explain just one use case of it: the `authorization code` flow. It allows server-side application to act on behalf of a user of another service. For example, a 3rd party application can post on Twitter on your account. Historically, to do this, this application must have had your Twitter credentials stored. Not only you had to reveal your Twitter password, but also that application must store it in plain text. Such an approach has multiple flaws. First of all, if the application is not entirely honest, it can now do anything on your behalf. Including changing your password and stealing your online account. But even if you trust the 3rd party application, it can still be hacked. Your password, together with thousands or millions of others, is compromised.

#32: Cryptographic hash function: much more than a blockchain

Sometimes you need to split arbitrary objects into a fixed number of groups. For example, storing a record into one out of many database nodes. Or saving a cookie in a hash table. Or distributing jobs among multiple workers. In all of these cases you later want to know, bucket or worker was chosen. Also, data should be split evenly. You don't want one node or worker to be overloaded. The above properties are implemented by a _so-called_ hash function. It's an algorithm that takes arbitrary input and produces fixed-length output. A number. For the same input, often called a _message_, it always produces the same output, known as a hash. Ideally, different messages should produce a different hash. Even better, two _slightly_ different messages should produce _wildly_ different hash. In practice, hash collisions must happen. After all, we are mapping arbitrarily large messages into a fixed-length hash. Often 32- or 64-bit.

#31: Redis: an in-memory database, cache, broker and much more

Redis is quite a versatile NoSQL, key-value database. Or in-memory cache. Or pub/sub broker. With transactions, stored procedures and fast replication. It's quite universal. Anyway, the main use-case for Redis is caching. Internally the whole dataset must fit in memory. Redis can optionally persist data on disk, but all online operations happen entirely in memory. This makes Redis extremely fast. It's often used as an alternative to the widespread Memcached server.

#30: Linear Regression: simple, yet powerful machine learning

Linear regression is one of the simplest machine learning algorithms. But also quite useful. It takes a bunch of existing, known observations and tries to predict how new observations will look like. Think about forecasting or finding trends. It says "_linear_" because the algorithm essentially finds a straight line that most closely follows the observations. OK, let's take a concrete example. Imagine you are selling your apartment. What is the right price for it? Well, you compare it to similar apartments in your neighborhood. If someone sells the exact same flat across the street, your price should be very similar. If another flat is sold, but 10% larger, expect its price to be 10% higher as well. Yet another flat is half the size of yours. So expect its price to be just 50% of your estimated asking price. Sound reasonable?

#29: Time synchronization: how Network Time Protocol does it's magic

Clocks are important to computers. Computers need to order events in a way understandable to humans. Every computer has a bunch of internal counters, like CPU ticks. But they only work within one machine. We need a way to have a reliable, global clock, that is synchronized between many computers. Why, exactly? Well, imagine you are selling tickets to The Rolling Stones concert. They sometimes sell within a few seconds. First come, first served. But who was first, if selling happens asynchronously in multiple data centers? Fans shouldn't be penalized for being routed to a server with higher latency. So, instead, we use timestamps. Late messages may still be treated as earlier ones if a transaction timestamp says so. Obviously we can't rely on the client's clock. It's too easy to change your laptop's time and see Mick Jagger from the front row. But how do we make sure servers aren't lying the same way? Even unintentionally? This is where NTP, network time protocol, comes into play.

#28: Event sourcing: your data as a stream of changes

Event sourcing is an alternative technique of storing business data. Rather than updating a single database record, every change is captured in an immutable, append-only log. We never overwrite existing data. Instead, we create and store an event that represents what exactly has changed. From the business perspective. In order to recreate the current state of an entity we must go through all the events and reconstruct it from history. Event sourcing brings better auditing and debugging. Also, storing changes can be faster because it requires inserting a new record rather than updating an existing one.

#27: Proof-of-work in blockchain: achieve consensus without trusted third party

Let's try to cheat the blockchain. If my wallet has exactly one bitcoin, I can't spend it twice. Once it's written into an immutable blockchain, **everyone** knows my wallet is empty. However, what if I purposefully create and announce two blocks at the same time. With the same parent block. For example, in one of the blocks there's a 1 bitcoin from my wallet spent on drugs. In the other block I spent that same bitcoin on unlicensed firearms. You know, things you do with cryptocurrencies. There are two competing blocks, each having a different version of the history. There is no central database so the blockchain network has no way of figuring out which block is valid and which is not. Well, they both technically are.

#26: Blockchain: distributed, append only database

Blockchain is a technology used for storing data without a central database. Data is organized in an ever-growing list of blocks with each block referencing the previous one. Like a linked list. Once a block is added to this list, it can't be modified. The integrity is guaranteed by including a cryptographic hash of the previous block. If the previous block changes, all subsequent blocks need to change as well. You can't simply modify history. This is similar to the operations on your bank account. However, the idea behind the blockchain is to maintain integrity without a central authority, like a bank. Data is distributed among peers. No node is distinguished and some number of nodes can even be hostile. Blockchain tolerates up to 50% of nodes purposefully trying to cheat the system. Everything happens using peer-to-peer network with no central backbone whatsoever. At what cost all of this can be achieved?

#25: High-frequency trading: why computers are better than human at trading?

According to some estimates, even half of the trading volume in the American stock exchange is generated by computers. Specifically, computer programs that make trading decisions in a split of a second. They may buy stock to sell it a few milliseconds later. With very minimal profit, this process repeated thousands of times per day can make a solid return. How do such systems work? There are multiple strategies, but most of them require extremely fast algorithms running close to the physical stock exchange. The speed is crucial and that's what makes HFT so interesting. A trading bot can easily read social media and within microseconds decide whether particular news is good or bad. That can lead to a stock going up or down. For example, a president tweets about a new special tax relief for the pharmaceutical industry. A computer program almost instantaneously buys some stocks from the pharma companies and sells them seconds later. Before other computers do the same. Human traders stand no chance.

#24: Service discovery: never again hard-code IP addresses in your configuration

In the old days an application consisted of a monolithic backend and a database. Once they were deployed their location never changed. So the only piece of configuration was the address of the database almost hardcoded into the monolith. These days an application is split into hundreds of microservices talking to each other. Probably too many services, probably talking too much. But that's a different story. Anyway, the environment became much more dynamic. Services come and go, orchestration frameworks are deploying them on different machines all the time. TCP/IP ports are random, instances are scaled up and down frequently. Sometimes automatically. New hosts are provisioned, old ones are shut down. Whole data centers are added. Under such circumstances we can no longer hard-code anything. When one service wants to talk to the other, it must somehow figure out where that service currently lives. It needs a mechanism to dynamically discover that service in an ever-changing environment.

#23: Garbage collection: how automatic memory management makes writing software much easier

Creating new objects, arrays or strings is so straightforward that we often forget what happens underneath. And I don't mean trying to figure out what `this` refers to in JavaScript objects. I mean: memory management. On each request we create a ton of objects. A server can easily allocate hundreds of megabytes of memory. Per second. Memory is cheap and there's a lot of it. But it's not infinite. How come we can simply call `new Object()` over and over again, taking more and more memory from our computer? Many objects are no longer needed a few milliseconds after they're created. What happens to the memory they occupy? We take for granted what was thought to be almost impossible: automatic memory management.

#22: Moore's law: still alive and true after decades

It's a common misconception that Moore's law is dead. That's because many believe it's about the speed of a CPU. But in reality Gordon Moore meant the number of transistors, not the clock frequency. And also, it's now even a law. Just an observation that holds true after half a century. OK, so what does this "law" state? Gordon Moore, before co-founding Intel, noticed that the number of transistors in a CPU doubles every two years. This means exponential growth. Which is a lot. So why are these transistors important?

#21: SSE and WebSockets: servers can talk to browsers, not only the other way around

HTTP is historically request-response-driven. This means a server is idle as long as no-one asks it to do something. Typically fetching data or accepting some form. In reality, we'd often like to receive data from the server without any request. Typically to subscribe for some server-side updates. For example displaying a current price on the stock exchange that changes many times per second. Or when waiting for some asynchronous process to complete. Traditionally this could be achieved with a few hacks. The most obvious and the worst one is busy-waiting. You simply keep asking the server over and over again periodically. More frequent requests result in a lot of excessive network traffic. Less frequent requests increase latency, so it's no longer real-time communication.

#20: Chaos engineering: breaking your system intentionally when you are prepared

We tend to focus on testing happy paths and expected edge cases. But how do you make sure that your system can survive minor infrastructure and network failures, as well as application bugs? Especially in microservice or serverless environment, where there are tons of moving parts. I've seen too many times systems that fail miserably because some minor dependency was malfunctioning. For example you have a tiny service that displays a small social widget on your website. When that service is down, the rest of the website should work. But without proper care and testing you may end up with global HTTP 503 failure. Code reviews and unit tests are fine, but the ultimate test is... turning off that service on production. And making sure the rest actually works. This is called _chaos engineering_.

#18: JIT: bytecode, interpreters and compilers

Source code can then be executed in two ways. Language implementations in general either interpret or compile it. In order to run an interpreted program you need one extra binary: an interpreter. Interpretation is simple: you read source code line by line and execute it. The compilation is much harder. A special program called a _compiler_ reads your source code ahead of time (AOT) and translates it into machine code. After this translation your program is standalone. You don't need a compiler to run it. Only you and your CPU.

#16: Akka: distributed actor-based toolkit for the JVM

Akka is a toolkit for building highly scalable, concurrent applications. It's written in Scala and based on the ideas from Erlang. Its approach to achieve concurrency is quite radical. Rather than mutexes, semaphores and shared memory, Akka uses so-called _actor model_. An actor is a small, stateful object that doesn't expose traditional methods. Instead, actors send and receive asynchronous messages with each other. There is no other way to interact with an actor. If you want an actor to do something or give you some information, message passing is the only way. Send a message, actor will receive it at some point in time, consume it and optionally send a response back.

#15: Mutation testing: who tests your tests?

Imagine I wrote a script that takes your codebase and removes a random line. Fairly simple. Or maybe some more subtle change, like replacing plus with minus operator? Or switching `x` and `y` parameters with each other? OK, so now my script builds your project. Most of the time it will fail the compilation or test phase. But what if the build succeeds? Well, apparently your test suite is not covering some lines? OK, but what if my script only removes or alters lines covered by tests? How is it possible that the build still succeeds? Turns out your tests aren't as good as you think. And I just described mutation testing that discovers that.