Compare commits

...

17 Commits

Author SHA1 Message Date
Jay
ea3e782d28 fix spacing 2026-03-24 20:13:03 +00:00
Jay
e9cdb6e25f pull from main 2026-03-24 20:10:21 +00:00
Jay
0eb8915b21 Add dms lecture notes 2026-03-24 20:06:20 +00:00
Jay
ac5e4639d8 Add dms lecture notes 2026-03-24 20:05:33 +00:00
John Gatward
934df269dd added chapter4
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 13s
2026-03-13 12:28:35 +00:00
John Gatward
c1a1f4f11f finished chapter3
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 16s
2026-03-12 13:01:29 +00:00
John Gatward
3a49c14cfa Added part2 & chapter3
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 11s
2026-03-10 12:22:47 +00:00
John Gatward
b2a1f705a9 Added chapter 2
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 11s
2026-03-06 12:10:18 +00:00
John Gatward
c86b40baf6 Add api design chapter 1
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 10s
2026-03-04 12:16:25 +00:00
Jay
3b64218fe5 add workflow
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 6s
2026-03-03 16:04:48 +00:00
Jay
2c56fad751 add workflow
Some checks failed
Build and Deploy MkDocs / deploy (push) Failing after 5s
2026-03-03 16:02:46 +00:00
Jay
914403247f add workflow
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 5s
2026-03-03 15:59:10 +00:00
Jay
e9d34ec449 add workflow
Some checks failed
Build and Deploy MkDocs / deploy (push) Failing after 33s
2026-03-03 15:56:57 +00:00
Jay
0376e86fd0 add workflow
Some checks failed
Build and Deploy MkDocs / deploy (push) Failing after 9s
2026-03-03 15:55:16 +00:00
Jay
cb920fe70f add workflow
All checks were successful
Build and Deploy MkDocs / deploy (push) Successful in 25s
2026-03-03 14:59:32 +00:00
Jay
83e759895e add workflow
Some checks failed
Build and Push Static files / deploy (push) Failing after 32s
2026-03-03 14:57:22 +00:00
Jay
1209e30858 add workflow
Some checks failed
Build and Push Static files / deploy (push) Failing after 59s
2026-03-03 14:52:27 +00:00
19 changed files with 583 additions and 59 deletions

View File

@@ -1,61 +1,44 @@
name: Build Notes Site
name: Build and Deploy MkDocs
on:
push:
branches: [ main ]
branches:
- main
jobs:
build:
deploy:
runs-on: ubuntu-latest
container:
image: node:20-bookworm # Node for checkout
steps:
# 1⃣ Checkout repository
- uses: actions/checkout@v4
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Important for switching branches
# 2⃣ Install Python for MkDocs build
- name: Install Python
- name: Build and Extract Site
run: |
apt-get update
apt-get install -y python3 python3-venv python3-pip
docker build -t mkdocs-temp -f ci/mkdocs/Dockerfile .
docker create --name temp-container mkdocs-temp
# Copying content to a folder named 'output_content' to avoid naming collisions
docker cp temp-container:/build/site ./output_content
docker rm temp-container
# 3⃣ List repo files (debug)
- name: List repo files
run: ls -R "${{ github.workspace }}"
# 4⃣ Build MkDocs site locally
- name: Build MkDocs site
- name: Deploy to docs-static Branch
run: |
python3 -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -r ci/mkdocs/requirements.txt
.venv/bin/mkdocs build --clean --site-dir site_output
git config user.name "gitea-actions[bot]"
git config user.email "actions@noreply.gitea.io"
# Increase buffer to handle larger media files
git config http.postBuffer 524288000
# 5⃣ Install Docker CLI so we can copy to volume
- name: Install Docker CLI
run: |
apt-get update
apt-get install -y ca-certificates curl gnupg lsb-release
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/debian $(lsb_release -cs) stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce-cli
mv output_content /tmp/site_final
git checkout --orphan docs-static
git rm -rf .
cp -r /tmp/site_final/. .
# 6⃣ Copy the site output into notes_public Docker volume
- name: Copy site to notes_public volume
run: |
docker run --rm \
-v notes_public:/public \
-v "${{ github.workspace }}/site_output:/tmp/site" \
alpine sh -c "cp -r /tmp/site/* /public/"
# Optional: Remove source maps to save space
find . -name "*.map" -type f -delete
# 7⃣ Optional: Verify files in volume
- name: List notes_public volume
run: |
docker run --rm -v notes_public:/data alpine ls -la /data
git add .
git commit -m "Automated MkDocs build"
git push origin docs-static --force

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
site/
venv
.venv

View File

@@ -1,7 +1,9 @@
FROM python:3.13-slim
FROM ghcr.io/squidfunk/mkdocs-material:latest
WORKDIR /work
WORKDIR /build
COPY requirements.txt /tmp/requirements.txt
COPY . .
RUN pip install --no-cache-dir -r /tmp/requirements.txt
RUN pip install --no-cache-dir mkdocs-minify-plugin
RUN mkdocs build

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,100 @@
# Introduction to APIs
**API**: Application Programming Interface
## What are web APIs?
- An API defines the way in which computer systems interact.
- We can find APIs in the standard libraries
- But a special type of API that is built to be exposed over a network and used remotely, "web APIs".
- Those building the API have so much control where as the users have relatively little.
- Web APIs allow you to expose *functionality* without exposing the *implementation*.
- Sometimes they allow users to take advantage of massive compute.
## What are resource-oriented APIs?
- Many web APIs act like servants.
- You ask them to do something, and they go off and do it.
- This is called *remote procedure call* (**RPC**)
### So why aren't all APIs RPC-orinented?
One of the main reasons is the idea of *statefulness*.
> - **Stateless**: When an API call can be made independently from all other API requests, with no additional context.
> - **Statefulness**: A web API that stores context on a user from previous API requests.
> For example a web API that stores a user's favourite cities and provides weather forecasts for just those has no runtime inputs but requires a state to be set by the user.
Consider the following API method names:
1. `ScheduleFlight()`
2. `GetFlightDetails()`
3. `ShowAllFlights()`
4. `CancelReservation()`
5. `RescheduleFlight()`
6. `UpgradeTrip()`
Each one of these RPCs is pretty descriptive, but we have to memorize these methods, each of which is subtly different.
- e.g. sometimes we talk about flight, other times we talk about a trip or a reservation.
- We also need to memorise which action is used in the method.
- Was it `ShowFlights()`, `ShowAllFlights()`, `ListFlights()` etc
We need to standardise, by providing a standard set of building blocks - method-resource
1. `CreateFlightReservation()`
2. `GetFlightReservation()`
3. `ListFlightReservation()`
4. `DeleteFlightReservation()`
5. `UpdateFlightReservation()`
Resource-oriented APIs will be much easier for users to learn, understand and remember.
- Standardisation makes it easy to combine what you already know (set of standard actions) which the resource which is easy to learn.
## What makes an API "good"?
What is the purpose of building an API in the first place?
1. We have some functionality that some users want.
2. Those users want to use this functionality programmatically
### Operational
- The system as a whole must be operational.
- It must do the thing users actually want.
- **Non-operational** requirements: It must perform how the user expects.
- e.g. latency
### Expressive
- The system needs to allow users to express the thing they want to do *clearly* and *simply*.
- The API should be designed such that there is a clear and simple way to do so.
- Avoid workarounds - if there is some functionality a user wants but there is not an easy way to do this, this is called a *workaround*.
- e.g. If you have a translation API, users can create a detect language feature by constantly pinging translate endpoint.
### Simple
- We could think of simplicity as the number of endpoints.
- However an API that relies on a single `ExecuteAction()` method just shifts complexity from one place to another.
- APIs should aim to expose the functionality users want in the most straightforward way possible, making the API as simple as possible, but no simpler.
- **Make the common case fast**
- Whenever you add something that might complicate the API for the benefit of an advanced user, it is best to keep this complexity hidden from a basic user.
- This keeps the more frequent scenarios simple and easy whilst enabling advanced features for those who want them.
- e.g. Image a translation API. `GET /translate?lang=en`, allowing the user to add a specific language model as a mandatory field is complex for the average user and will slow down basic scenarios.
### Predictable
APIs that rely on repeated patterns applied to both the API surface definition and the behaviour.
Users very rarely learn an entire API, they learn the parts they need to and make assumptions when they need to make additions. e.g. if a query parameter is called text in one endpoint, it should not be called string or query in another.
APIs that rely on **repeated**, **predictable** patterns are easier and faster to learn; and therefore better.
### Summary
- Interfaces are contracts that define how two systems should interact with one another.
- APIs are a special type of interface
- Web APIs are again a special type of API that is exposed over a network.
- **Resource-oriented** APIs are a way of designing APIs to reduce complexity by relying on a standard set of actions, called *methods*, across a limited set of resources.
- Good APIs are generally: *operational*, *expressive*, *simple* and *predictable*.

View File

@@ -0,0 +1,31 @@
# Introduction to API Design Patterns
## What are API Design Patterns?
A **software design *pattern*** is a particular design that can be applied over and over to lots of similar software problems, with only minor adjustments. It is not a pre-built library but more of a *blueprint* for solving similarly structured problems.
- Most often, design patterns focus on specific components rather than entire systems.
- e.g. If you want to add a logging system, you can use the **singleton design pattern**.
- This pattern is not complete
- However, it's well-defined and well-tested pattern to follow when you need to solve this small compartmentalised problem of always having a single instance of a class.
## Why are API Design Patterns Important?
- While having programmatic access to a system is very valuable, it's also much more fragile and brittle.
- Changes to the interface can easily cause failures for those using the interface.
- We refer to this aspect as *flexibility*
- Interfaces where users can easily accommodate changes are *flexible*
- GUIs are flexible - moving a button
- Interfaces where even small changes cause complete failures are *rigid*.
- Backend APIs: changing a query parameter breaks old client code.
- Rigid interfaces make it much more difficult to iterate toward a great design.
- We are often stuck with all design decisions, both good and bad.
**Pagination Pattern**: The pagination pattern is a way of retrieving a long list of items in smaller, more manageable chunks. The pattern relies on extra fields on both the request and response.
Moving from a non-paginated to paginated response pattern:
Q. What happens if we don't start with the pattern?
1. All previously written clients are expected all the data in one list - it has no way of getting subsequent pages.
2. Clients are left to think they have all the data - which can lead to incorrect conclusions.

View File

@@ -0,0 +1,88 @@
# Naming
In every software system we build, and every API we design or use - there are names that will live far longer than we ever intend them to. It is **important to choose great names**.
## Why do names matter?
When designing and building an API, the names we use will be seen by & interacted with all users of the API.
## What makes a name "good"?
### Expressive
It is critical that a name clearly convey the thing is it naming.
- e.g. The term topic is used in both messaging and machine learning.
- If your project includes both using the name *topic* will be confusing.
- A more **expressive** name is required:
- `topic_model`
- `topic_message`
### Simple
- While an expressive name is important, it can also become burdensome if the name is excessively long without adding additional clarity.
- Names should be expressive but only to the extent that each additional part of a name adds value to justify its presence.
- On the other hand, names shouldn't be oversimplified
| Name | Note |
|------|------|
| `UserSpecifiedPreferences` | Expressive, but not simple enough |
| `UserPreferences` | Both simple & expressive |
| `Preferences` | Too simple |
### Predictable
- In general, we should use the same name to represent the same thing, and different names to represent different things.
- The basic goal is to allow users of an API to learn one name and continue building on that knowledge to be able to predict what future names would look like.
## Language, Grammar & Syntax
Language being inherently flexible and ambiguous can be a good thing and a bad thing.
- On the one hand, ambiguity allows us to name things to be general enough to support future work.
- Naming `image_url` rather than `jpeg_url` presents us from limiting ourselves to a single image format.
- One the other hand, when there are multiple ways to express the same thing, we often tend to use them interchangeably, which ultimately makes our naming choices unpredictable.
### Language
Use American English.
### Grammar
#### Imperative Actions
REST standard verbs should use the imperative mood. They are all commands or orders.
- `isValid()`: Should it return simple boolean field? Should it return a list of errors?
- `GetValidationErrors()`: Clear that it will return list of errors, empty list if is valid.
#### Prepositions
- If a Library API wants to list `Book` resources with the `Author`, it's tempting to name `BooksWithAuthor`.
- This falls apart when we add in all our additional resources
- We will end up with many function names to call.
- The preposition `with` is indicative of a more fundamental problem.
- Prepositions act like *code smell*, hinting at something not being quite right.
#### Pluralisation
- Most often, we should use the singular.
- However collection names might be pluralised.
- Use American English to pluralise.
## Context
- When we use `book` in the library API, we are referring to the resource, however in a flight booking API - we are referring to an action.
This means we need to keep the context of our API in mind.
- Context can impart additional value to a name that might otherwise lack a specific meaning.
- It can also lead us astray when we use words with a specific meaning but don't make sense without the context.
- *record* is very generic, until you consider the context of an audio recording API.
## Data types and units
A name can become more clear when using a richer data type.
- `dimensions: String;` - this is ambiguous
- `dimensions: Dimensions;` (where `Dimensions` is an object)

View File

@@ -0,0 +1,82 @@
# Resource Scope and Hierarchy
## What is a resource layout?
The arrangement of resources in our API, the fields that define those resources, and how those resources relate to one another through those fields.
In other words, resource layout is the entity (resource) relationship model for a particular design of an API.
### Types of Relationships
#### Reference Relationships
The simplest way or two resources to relate to one another is by a simple reference.
<figure>
<img src="/books/api_design_patterns/media/chapter4_01.png">
<figcaption>A message resource contains a reference to a specific user who authored the message.</figcaption>
</figure>
- This reference relationship is sometimes referred to as a *foreign key* relationship.
- As a result, this can also be considered a *many-to-one* relationship.
- A user might write many messages, but a message always has one user as the author.
#### Self-Reference Relationships
<figure>
<img src="/books/api_design_patterns/media/chapter4_02.png">
<figcaption>An employee resource points at other employee resources as managers and assistants.</figcaption>
</figure>
#### Hierarchical Relationships
- Hierarchical relationships are sort of like one resource having a pointer to another
- But that pointer aims upward and implies more than just one resource pointing at another.
- Hierarchies also tend to reflect *containment* or *ownership* between resources.
<figure>
<img src="/books/api_design_patterns/media/chapter4_03.png">
<figcaption>ChatRoom resources act as the owner of Message resources through a hierarchical relationship.</figcaption>
</figure>
In this case, there is an implied hierarchy of `ChatRooms` *containing* or *owning* `Messages`.
## Choosing the Right Relationship
### Do you need a relationship at all?
When building an API, after we've chosen the list of things or resources that matter to us, the next step is to decide how these resources relate to one another.
- Consider a self-reference relationship between `Users`. A single change to one resource can affect millions of other related resources.
- e.g. if someone famous deletes their Instagram account, millions of records might be to be removed/updated.
Reference relationships should be **purposeful** and **fundamental** to the desired behaviour. Any reference relationship should be something important for the API to accomplish its primary goal.
### References or in-line data
- Where data is in-lined, we only need a single API call to retrieve all the relevant information.
- But what if we aren't interested in that information very often?
- Then our response is bloated.
Optimise for the common case - without compromising the feasibility of the advanced case.
### Hierarchy
The biggest differences with this type of relationship are the **cascading** effect of actions and the inheritance of behaviours and properties from parent to child.
- Deleting a parent resource typically implies deleting a child resource.
- Access to a parent generically implies the same level of access to the children resources.
## Anti-patterns
### Resources for Everything
It can often be tempting to create resources for even the tiniest concept you might want to model.
**Rule of thumb**: If you don't need to interact with one of your resources independent of a resource it's associated with, then it can probably be a data type.
### Deep Hierarchies
Overly deep hierarchies can be confusing and difficult to manage.
Page 63 4.3.3 in-line everything

View File

@@ -1,3 +0,0 @@
# Structure and Interpretation of Computer Programs
We are about to study the idea of a *computational process*. Computational processes are abstract beings that inhabit computers. As they evolve, processes manipulate other abstract things called data. The evolution of a process is directed by a pattern of rules called a *program*. People create programs to direct processes. In effect, we conjure the spirits of the computer with our spells.

View File

@@ -0,0 +1,135 @@
# Java Collections
Week 3 (Oct 5th)
**Part 1**
In java a *collection* is an object that represents a group of objects.
The collections API is a unified framework for representing and manipulating collections independently of their implementation.
An *API* (application programming interface) is an interface protocol between a client and a server, intended to simplify the client side software.
A *library* contains re-usable chunks of code.
**Java Collections framework**
- We have container objects that contain objects
- All containers are either "collections" or "maps"
- All containers provide a common set of method signatures, in addition of their unique set of method signatures
*Collection* - Something that holds a dynamic collection of objects
*Map* - Defines mapping between keys and objects (two collections)
*Iterable* - Collections are able to return an iterator objects that can scan over the contents of a collection one object at a time
NOTE: Vector is a legacy structure in Java replaced with *ArrayList*
Stack is now *ArrayDeque*
`LinkedList(Collection<? extends E> c)` - means some type that either is E or a subtype of E. The `?` is a wildcard.
```java
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("string");
String s = (String)list.getFirst();
System.out.println(s);
}
```
This is bad coding practice, the collection constructor are not able to specify the type of objects the collection is intended to contain. A `ClassCastException` will be thrown if we attempt to cast the wrong type.
```java
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("string");
String s = list.getFirst();
System.out.println(s);
}
```
This is a type safe collection using generics.
- Classes support generics by allowing a type variable to be included in their declaration.
- The `<>` show the same type as stated (in this case string)
- You cannot type a collection with a primitive data type eg int
**HashMap Class**
- A HashMap is a hash table based implementation of the map interface. This implementation provides all if the optional map operations, and permits null values and the null key.
```java
public static void main(String[] args) {
HashMap<String, Integer> userData = new HashMap<>();
userData.put("Emma", 30);
userData.put("John", null);
userData.put("Millie", 17);
Set<String> keys = userData.keySet();
for (String key:keys){
System.out.println(key + "=" userData.get(key));
}
}
```
```
Emma = 30
John = null
Millie = 17
```
**Part 2**
__Relationships between objects__
*Aggregation* - The object exists outside the other. It is created outside so it is passed as an argument.
An animal object *is part of* a compound object (semantically) but the animal object can be shared and if the compound object is deleted, the animal object isn't deleted.
```java
public class Compound {
private Animal dog;
public void setAnimal(Animal dog){
this.dog = dog;
}
}
```
![Image](assets/1.png)
*Composition* - The object only exists if the parent object exists, if the parent object is deleted then so is the child object.
The zoo object owns the compound object. If the zoo object is deleted then the compound object is also deleted.
```java
public class Zoo {
private Compound dogArea = new Compound();
}
```
![Image](assets/2.png)
**Inheritance**
A way of forming new classes based on existing classes. Has a "is-a" relationship.
*Polymorphism* - A concept in object oriented programming. Method overloading and method overriding are two types of polymorphism.
- *Method Overloading* - Methods with the same name co-exist in the same class but they must have different method signatures. Resolved during compile time (static binding).
- *Method Overriding* - Methods with the same name is declared in parent and child class. Resolved during runtime (dynamic binding).
```java
public class Child extends Parent {
public Child(String name){
super(name);
}
@Override
Public void eat() {
chew();
}
}
```
The super keyword called the parent class' constructor.
![Image](assets/3.png)
**What is the difference between an abstract class and an interface**
- Java abstract class can have instance methods that implement a default behaviour. May contain non-final variables.
- Java interfaces have methods that are implicitly abstract and cannot have implementations. Variables are declared final by default.
Interfaces are less restrictive when it comes to inheritance, interfaces can have many levels of inheritance where as a class can only have one level.

View File

@@ -0,0 +1,92 @@
# Unified Modelling Language
12/10/20
**UML**: A specification defining a graphical language for visualising, specifying, constructing and documenting the artefacts of distributed object systems.
Latest version: **2.6**
**Benefits of UML**
- Enhances communication and ensures the right communication
- Captures the logical software architecture independent of the implementation language.
- Helps to manage the complexity
- Enables reuse of design
<img src="assets/4.png" alt="img" style="zoom:80%;" />
## Object Orientated Analysis
**Use case diagrams**
- Describe a set of actions that some system should or can perform in collaboration with one or more external users of the system.
- No attempt to represent an order or a number of executions.
**Use case diagram components**
`Actors` - Entities that interface with the system. Can be people or other systems.
`Use case` - Based on user stories and represent what the actor wants your system to do for them. In the use case diagram only the use case name is represented.
`Subject` - Classifier representing a business, software system, physical system or device under analysis design, or consideration.
`Relationships`
> Relationships between use case and actor
>
> 1. Association indicates which actor indicates which use case
>
> Relationship between two use cases
>
> 1. Specifying common functionality and simplifying use case flows
> 2. Using <<include>> or <<extend>>
**`<<include>>`**- multiple use cases share a piece of same functionality which is placed in a separate use case.
**`<<extend>>`** - Used when activities might be performed as part of another activity but are not mandatory for a use case to run successfully.
**Use case diagram of a fleet logistics management company**
![image](assets/5.png)
**Base Path** - The optimistic path (best case scenario)
**Alternative Path** - Every other possible way the system can be used/abused. Includes perfectly normal alternate use, but also errors and failures.
Use Case: `Borrow copy of book`
> **Purpose**: The book borrower (BB) borrows a book from the library using the Library Booking System (LBS)
>
> **Pre-conditions**:
>
> 1. The book must exist
> 2. The book must be available
>
> **Base Path**:
>
> 1. LBS requests membership card
> 2. BB provides membership card
> 3. BB is logged in by LBS
> 4. LBS checks permissions / debts
> 5. LBS asks for presenting a book
> 6. BB presents a book
> 7. LBS scans RFID tag inside book
> 8. LBS updates records accordingly
> 9. LBS disables anti-theft device
> 10. BB is logged out by LBS
> 11. LBS confirms that process has been completed successfully
>
> **Alternative Path**
>
> 1. BB's card has expired: Step 3a: LBS must provide a message that card has expired; LBS must exit the use case
>
> **Post conditions for base path**
>
> **Base path** - BB has successfully borrowed the book & system is up to date.
>
> **Alternate Path 1** - BB was NOT able to borrow the book & system is up to date.

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

View File

@@ -25,6 +25,8 @@ theme:
- search.suggest
- search.highlight
- search.share
- content.action.edit
- content.action.view
markdown_extensions:
- admonition
@@ -60,9 +62,18 @@ nav:
- Home: index.md
- Books:
- Designing Data-Intensive Applications:
- Preface: books/designing_data_intensive_applications/preface/index.md
- Part 1. Foundations of Data Systems:
- Chapter 1. Reliable, Scalable and Maintainable Applications: books/designing_data_intensive_applications/part1/chapter1.md
- Chapter 2. Data Models and Query Languages: books/designing_data_intensive_applications/part1/chapter2.md
- Structure and Interpretation of Computer Programs: books/structure_and_interpretation_of_computer_programs/index.md
- Preface: books/designing_data_intensive_applications/preface/index.md
- Part 1. Foundations of Data Systems:
- Chapter 1. Reliable, Scalable and Maintainable Applications: books/designing_data_intensive_applications/part1/chapter1.md
- Chapter 2. Data Models and Query Languages: books/designing_data_intensive_applications/part1/chapter2.md
- API Design Patterns:
- Part 1. Introduction:
- Chapter 1. Introduction to APIs: books/api_design_patterns/part1/chapter1.md
- Chapter 2. Introduction to API Design Patterns: books/api_design_patterns/part1/chapter2.md
- Part 2. Design Principles:
- Chapter 3. Naming: books/api_design_patterns/part2/chapter3.md
- Chapter 4. Resource Scope and Hierarchy: books/api_design_patterns/part2/chapter4.md
- Lecture Notes:
- Developing Maintainable Software:
- Java Collections: lectures/dms/01_java_collections.md
- UML Diagrams: lectures/dms/02_uml.md