Follow this blog

Software engineering, design, and psychology

Later Ctrl + ↑

Principles Behind Good Microservice Boundaries | Microservice Architecture — Ep. 12

  1. Single Responsibility. Consumers of a service need to clearly understand its purpose.
  2. High Cohesion and Exhaustiveness. All related functionality has to end up in the same service.
  3. Low Coupling. Services should minimize dependencies on others — even if that means duplicating supporting code. Big codebases for microservices are OK as long as the services are cohesive and centered around a single business capability.

Imaging we have a patient data management system for hospital intensive care units (ICUs), built as a monolith. It manages patient information, prescriptions, treatment history, vital parameters, and provides a dashboard with current state and therapy.

❌ Wrong decomposition:

  • dashboard
  • care plan
  • monitoring

Why? Consider we add a new drug into the system. All services must change:

  • care plan — to prescribe it
  • monitoring — to display past treatments with the new drug
  • dashboard — to show current therapy

✅ Better approach:

  • drugs
  • vital parameters
  • timeline (treatment plans, current state, history)

Why? Available drugs and vital parameters change in one place, while evolution of timeline does not affect other services. Each service owns a stable business concept, not a UI page.

Good microservice boundaries reduce change coordination, not just code size.

Benefits and Challenges of Microservice Architecture | Microservice Architecture — Ep. 11

The core of microservice approach contains two ideas:

  • narrow business domains
  • small and independent teams (2-pizza team size)

So, splitting monoliths into microservices immediately brings benefits:

  • smaller codebases — easier to comprehend, faster to change
  • higher cohesion — easier to comprehend, more reasonable to scale when needed
  • smaller build sizes — cheaper infrastructure and better horizontal scaling

These benefits are balanced by fundamental trade-offs:

  • the system becomes distributed — network delays and partitions become ordinary and must be designed for
  • the system becomes asynchronous — integration and end-to-end testing becomes significantly harder
  • events are now processed by service chains — bugs become harder to trace, reproduce, and reason about
  • wrong service boundaries are expensive — errors here lead to numerous inter-service dependencies, spawning a “distributed monolith”, combining cons of both approaches while bringing few benefits

Microservices shift complexity from code size to communication structure, forcing boundaries between business logic and supporting infrastructure.

Problems of Monoliths in Growing Projects | Microservice Architecture — Ep. 10

When a project grows successfully, with time amount of code grows, and more devs are hired. This often leads to:

  • a bloated codebase — harder for new engineers to understand, slower to change
  • tight coupling between many modules — releases require more coordination and happen less frequently
  • growing coordination overhead — N team members can form up to N² communication paths
  • legacy accumulation — dependencies receive updates, but codebase upgrades are postponed due to fear of breaking changes
  • longer build times
  • increasing hardware requirements for all environments

This is a time when teams start thinking about splitting the system into smaller, independently evolving parts.

Would you name the approach? :)

It is Right to Start with a Monolith | Microservice Architecture — Ep. 9

Microservices have many benefits — but they are not a default choice for greenfield projects.

Monoliths have strong advantages that service-oriented approaches cannot offer:

  • the whole app is deployed as a single unit: if it compiles, cross-module integration is likely correct
  • development and refactoring are simpler: the compiler helps to track if changes are complete
  • cross-module calls are synchronous or close to synchronous, taking less than 1-10 milliseconds
  • testing is easier, with clear targets of integration and e2e tests
  • debugging is simpler: spin up the app locally, set breakpoints, attach a profiler — and you have the whole system for inspection

When monoliths are OK:

  • small projects
  • small teams
  • unclear domain
  • unclear scaling requirements

...basically, in most new projects.

Decomposition of ESBs into Cloud Services | Microservice Architecture — Ep. 8

Let’s revise what were the responsibilities of Enterprise Service Buses:

  • service discovery and communication
  • request routing
  • protocol mediation
  • authN and authZ
  • rate limiting
  • logging and monitoring
  • workflow orchestration

These capabilities are generic. Any sufficiently complex system needs them — but they don’t need to live inside a single, centralized component.

In cloud-native systems, ESBs were effectively decomposed into specialized services:

  • service discovery -> service mesh tools (AppMesh, Linkerd)
  • service communication -> messaging and event streaming platforms (Kafka, SQS)
  • request routing, rate limiting, auth -> API gateways
  • logging and monitoring -> observability tools (CloudWatch, CloudTrail)
  • orchestration -> workflow engines (Step Functions)

What remained were microservices themselves:

  • independently developed
  • independently deployed
  • independently scaled
    ...units of a system, focused on isolated business capabilities.

Tech Background of the Early 2010s | Microservice Architecture — Ep. 7

The late 2000s to early 2010s marked the emergence of cloud computing. AWS and Google Cloud made on-demand compute available at scale.

The hardware and infrastructure assumptions shifted:

  • ephemeral instances became the norm
  • horizontal scaling became cheaper
  • infrastructure-as-code tools appeared and matured
  • instance and network failures now considered expected, not exceptional

At the same time, communication protocols and platforms stabilized around clear leaders:

  • HTTP as the universal transport
  • JSON as the universal data language
  • REST / gRPC as dominant API styles
  • Linux as the default server OS

This convergence reduced the need for protocol mediation and heavy integration layers — some of the reasons ESBs were invented. The switch from SOA was not driven only by its limitations, but also by changes in technology.

Drawbacks of Enterprise Service Buses | Microservice Architecture — Ep. 6

ESBs gathered all control over the system in a single place: communication, schemas, orchestration, infrastructure. Over time, this revealed systemic issues:

  • The ESB became a single point of failure: a bug could bring down entire system.
  • ESB changes were risky and slow: engineers had to deeply understand schemas, adapters, business rules, and their interdependencies.
  • Updates to services became problematic: even a small change in API required coordination with the ESB integration layer and orchestration logic.
  • The ESB team turned into a bottleneck, struggling to catch up with changes in different services.
  • Horizontal scaling was limited: ESBs commonly relied on vertical scaling and expensive hardware.

These issues slowed innovation and adaptability, turning large systems rigid, slow, and outdated. Another kind of architectural approach had to appear — one favoring independent ownership, decentralized control, and horizontal scaling of any service.

Peak of SOA — Enterprise Service Bus | Microservice Architecture — Ep. 5

The core of service-oriented architecture is centralized governance over how diverse services provide their capabilities and communicate.

This idea lead to the Enterprise Service Bus (ESB) — a central integration layer connecting all services, handling:

  • protocol conversion
  • message translation into enterprise-wide data models
  • request routing
  • security rules for all services (auth, rate limiting, access control)
  • centralized logging and auditing
  • workflow orchestration, including cross-service transactions and compensations

ESB made sense in heterogeneous enterprise environments — but it also concentrated complexity and control in one place. Many of today’s architectural advancements are reactions to this tradeoff.

Service-Oriented Architecture (SOA) | Microservice Architecture — Ep. 4

SOA is a predecessor to microservices. It is an architectural style that treats services as independent, heterogeneous providers of business capabilities.

“Heterogeneity” here acknowledges that services may:

  • belong to different vendors
  • run on different platforms
  • be written in different languages
  • communicate over different protocols
  • be developed by different teams

SOA emphasizes:

  • well-defined, explicit service interfaces
  • stability and genericity of contracts to serve multiple consumers over long periods of time
  • service discovery via service registries
  • centralized service administration with approval of contracts, schemas, and compatibility guarantees

The focus on central governance and long-lived, broadly reusable contracts is the key distinction between SOA and modern microservices. It is also its key limitation factor: services cannot evolve quickly because of dependence on central governance and strictness of agreed-upon interfaces.

Microservices vs. Traditional Services | Microservice Architecture — Ep. 3

A microservice is not a “small service” — it is a service with stricter constraints.

A microservice:

  • owns a single business capability (“bounded context‘ in DDD terms)
  • has limited to no dependencies on other microservices
  • is deployed and versioned independently, without coordination with its consumers
  • evolves its API in a backward-compatible way, giving consumers time to upgrade
  • is owned by a team small enough to understand and operate it end-to-end (the ‘two-pizza team‘)

What the ‘micro-’ prefix does not mean:

  • trivial logic
  • a small codebase
  • few endpoints

A microservice can be large and complex, as long as it remains cohesive and operable by a small team. And it can be small and simple too — if that’s what its business capability or scaling needs require.

Services vs. Components | Microservice Architecture — Ep. 2

What is the difference between a service and a component? Both should be cohesive and loosely coupled to the rest of application, both should solve a single problem, both have no hard limits on size. The key difference is the boundary.

Comparing to a component, a service:

  • does not share memory with other processes
  • is not accessed directly — only via a network
  • fails independently, without crashing the entire application
  • scales independently from the main process or other services

Components are in-process abstractions.
Services are distributed system units.

What is a Service? | Microservice Architecture — Ep. 1

This is the beginning of series on Microservices & Event-Driven Architecture (MEDA). The series explores the theme from its historical context to practical topics like testing, deployment, and observability.

All research and writing are done by me. The ideas are drawn from respected books and lectures, as well as my own professional experience. No AI is used to generate the content itself; I use ChatGPT only for editing, as English is not my native language, and I believe the texts benefit from AI corrections of my grammar and fluency.

I hope you find this series helpful and interesting. If you notice any errors or have suggestions, feel free to contact me at george@mishurovsky.com or leave a comment — I read them all.

Now, let’s proceed to the topic.

It helps to settle with fundamentals before diving into modern software architecture buzzwords like ‘microservices’ and ‘event-driven systems’.

A service is:

  • a self-contained unit of functionality
  • serving a specific business purpose
  • owning both its logic and data
  • deployed independently
  • providing capabilities through a standardized interface
  • accessed through a network boundary (real or assumed)

Note the emphases on autonomy and boundaries (functional and communicational). Without those, we’re talking about components, but not services.

Understanding this distinction makes architectural discussions clearer and prevents “microservices” from becoming just a fancy label for a distributed monolith.

📚 Bookshelf

Below is a list of books I’ve finished — and those I plan to read. I will update it from time to time. Welcome!

Feel free to join comments for this post and in linked book reviews. What do you think? Which books transformed your knowledge and approaches in software development?

Titles within categories follow in alphabetical order. Updated Sep 2026.

Finished

Software Architecture

  • Designing Data-Intensive Applications — M. Kleppmann ⭐️
  • Fundamentals of Software Architecture — N. Ford ⭐️

Management & Communication

  • Fundamentals of Project Management — J. Heagney
  • Getting Real — D. H. Hansson
  • Nonviolent Communication — M. Rosenberg ⭐️
  • On Writing Well — W. Zinsser
  • Start with No — J. Camp ⭐️
  • The Elements of Style — E. B. White

Object-Oriented Programming

  • ASP.NET Core in Action — A. Lock
  • C# in a Nutshell — J. Albahari ⭐️
  • Design Patterns — E. Gamma
  • Effective TypeScript — D. Vanderkam
  • Node.js Design Patterns — M. Casciaro
  • Patterns of Enterprise Application Architecture — M. Fowler ⭐️
  • Refactoring — M. Fowler
  • The Object Oriented Way — C. Okhravi (Review)
  • Unit Testing Principles, Practices, and Patterns — V. Khorikov ⭐️

Functional Programming

  • Domain Modeling Made Functional — S. Wlaschin
  • Professor Fisby’s Mostly Adequate Guide to Functional Programming — B. Lonsdorf
  • Purely Functional Data Structures — C. Okasaki

DevOps & Cloud

  • Accelerate — N. Forsgren
  • AI Engineering — C. Huyen
  • Continuous Delivery — D. Farley
  • Continuous Integration — P. M. Duvall

Data Science

  • Data Pipelines Pocket Reference — J. Densmore (Review)
  • Learning SQL — A. Beaulieu ⭐️
  • Web Scraping with Python — Ryan Mitchell (Review)

Graphic Design

  • Grid Systems in Graphic Design — J. Müller-Brockmann
  • Practical UI — A. Dannaway
  • Refactoring UI — A. Wathan
  • The Elements of Color — J. Itten ⭐️

Basics

  • Clean Architecture — R. C. Martin
  • Clean Code — R. C. Martin
  • Code Complete — S. McConnell
  • Domain-Driven Design — E. Evans ⭐️
  • Introduction to Algorithms — T. Cormen

In-Progress

  • Continuous Deployment — V. Servile
  • Systems Engineering Principles and Practice — A. Kossiakoff

Waiting In the Shelf

  • Building Microservices — S. Newman
  • Dependency Injection Principles, Practices, and Patterns — S. Van Deursen
  • Grokking Simplicity — E. Normand
  • Philosophy of Software Design — J. Ousterhout
  • Software Architecture: the Hard Parts — N. Ford
  • Structure and Interpretation of Computer Programs — H. Abelson
  • Stylish F# — K. Eason
  • Team Topologies — M. Skelton
  • The Anatomy of Story — J. Truby
  • The Art of PostgreSQL — D. Fontaine
  • The Linux Command Line — W. Shotts
  • Thinking with Type — E. Lupton

Dijkstra’s Algorithm is Basically a BFS Algorithm

A small note on a commonly mentioned algorithm — trying not to sound too pretentious 😅

If you, like me, get startled every time you see Dijkstra’s algorithm, forgetting how it works exactly — it is essentially a breadth-first search (BFS), but with two twists:

  • The graph is weighted
  • The queue is min-priority, not FIFO

So instead of blindly processing nodes in a queue one by one, we always pick the node with the lowest cumulative distance.

Once you realize this, the algorigthm becomes quite simple to implement, and the most of the complexity moves into building an efficient min-priority queue based on a Fibonacci or pairing heap.

Strictly speaking, it is BFS that is a special case of Dijkstra’s algorithm for unweighted graphs, not the other way around.

Renaming Entities Project-Wide with find, grep, sed, and rename

There are times in software projects when a big shift happens in domain representation. This results in changes of project structure, class responsibilities, and occasionally, requires bulk renames of entities across the whole codebase.

Imagine we need to rename every Employee to Worker. This change should affect both file paths and textual occurrences throughout the project.

Renaming may sound like a simple problem: assuming there are no external dependencies using the target name, we just need to rename all occurrences of it inside a repository. But there multiple caveats:

  1. We must rename both file names and folder names.
  2. We must rename all code and text occurrences.
  3. Casing must be preserved: Employee → Worker, and employee → worker.
  4. Both plain and compound usages must be properly renamed: createEmployee → createWorker.
  5. Non-code, non-document files must not be affected (consider binary files which by coincidence might have an ...employee... fragment inside).
  6. There are folders or files which we would want to omit from renaming (e. g., .git).
  7. No IDE provides such functionality, so we cannot rely on existing solutions.

I will address all these challenges in a solution below, but there is an important complexity that cannot be tackled with automation. If by any chance your code depends on a library with the target name (e. g., employee.js) or uses exports from a library containing the target name (import type { valuableEmployeee } from ‘employee-js’), you’ll have to resolve issues manually after renaming.

Reviewing Expected Changes

First, remove any folders and files that are recreated during project builds or setup: build/, dist/, node_modules/, .storybook-static/, etc. This step isn’t strictly necessary, but it can help iterate faster if commands encounter errors.

Now, let’s start with renaming text occurrences by listing all files that might get affected with find command. Here I am using -iname for case-insensitive search and `-not -path ‘’` syntax to exclude folders we need to protect from changes.

Shell
find . -not -path '*/.*' -not -path 'src/protected' -iname '*employee*'

Revise the output: make sure it does not contain folders or files you do not want to be changed.

Then, let’s see which text occurrences inside our files will be affected. Same approach: case-insensitive search in all files, excluding protected directories or files.

Shell
grep -RIn -i --exclude-dir='*/.*' --exclude-dir='src/protected' 'employee' .

In the output you’ll see all lines containing the target name. Revise all them carefully: if you want to protect some names from changes, you might want to add file names to exclusion, or rename such occurrences manually to some special value (e. g. em#plo#yee), so you can revert it later.

Renaming Text Occurences

Now we can rename all text occurrences, handling separately each casing. It will require some sed magic:

Shell
LC_CTYPE=UTF-8 find . -type f \
  -not -path '*/.*' \
  \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.json' \) \
  -exec sed -i 's/Employee/Worker/g; s/employee/worker/g' {} +

There are two important points here. First, LC_CTYPE=UTF-8 allows us to treat all file characters as UTF-8, even if the situation is different. Without it, sed stops when encounters non-UTF-8 characters. Second, we use -o -name ‘*.ext’ syntax to list file extensions to be affected. This prevents accidental changes of binary or image file contents.

Renaming Paths

Hopefully, file content renaming finished successfully. From here we will proceed with renaming of file and folder names. For this we will use rename command ingesting find output:

Shell
find . -not -path '*/.*' -depth -name '*Employee*' \
  -exec rename 's/Employee/Worker/g' {} +
find . -not -path '*/.*' -depth -name '*employee*' \
  -exec rename 's/employee/worker/g' {} +

These commands might produce warnings. If you have file paths that include multiple occurrences of the target name, the renames will be performed only for the first one, so you will have to run the commands multiple times until the paths are fully renamed.

And that’s it! ✨
If you created any specially-renamed entities, rename them back manually. Then run git add and git commit — git should detect all path renames automatically.

The Day of My First Open-Source Contribution

This Friday called for a small celebration! For the first time in my professional career, I opened a PR in a major open-source repository – and it was approved and merged! 🎉

Now, let’s be honest: it was the tiniest contribution possible. I fixed a single missing character in the docs for the List.sort function. You really can’t go smaller than that — unless someone figures out how to commit whitespace.

But it is still a moment to be proud of. It was my genuine finding when I was learning how to use F#, and creating a proper PR for such a big repository is a good exercise by its own!

Now I can officially call myself as .NET / F# contributor 😏

Book review: “The Object Oriented Way”, Christopher Okhravi

Last week I finished reading “The Object Oriented Way” by Christopher Okhravi. I was attracted to this book with occasional posts by the author on Youtube where he was discussing complex and interesting topics of OOP. His dives into use cases for composition vs. inheritance, composition patterns, and dependency inversion finally convinced me to buy a full copy. I was not disappointed!

This book is like a Bible of OOP. It starts from the very foundational topics like syntax, declaration vs. assignment vs. initialization, number types, variable mutability and so on – written in a concise yet exhaustive manner.

The story develops with detailed discussion of all the tools used in C# OOP, each chapter more advanced than the previous one. It culminates with very interesting discourse of Liskov Substitution Principle: covariance, contravariance, invariance, and the limitations C# has regarding pure logical object-oriented compatibility.

The ending was somewhat unexpected. For me it turned a textbook into a wonderfully written story, with a narration gradually building cognitive tension towards beautiful complexity and then resolution with a new state, a level above the starting point. I will not spoil any details, though :)

Whom this book is going to be useful:

  • anybody who wants to learn C#
  • junior devs to build a solid understanding of OOP toolchain
  • middle-to-senior devs to fill in the gaps in OOP theory
  • staff devs and above to master arguments for or against object-oriented approach in a particular module

Verdict: 4.5 / 5 – essential.
Consider buying the full book. It is a worthy investment for most of OOP practitioners.

I personally would love to see more detailed UML diagram section. They can be quite complex, and it would be cool to have a complete material on how to write expressive diagrams when planning OOP architecture.

A Security Checklist for Senior Engineers and Tech Leads

Couple of years ago, I told an interviewer I didn’t want to work on security problems because I found them boring. My mind has changed since then.

Security requirements are genuine engineering constraints. They drive development of sophisticated solutions, and it is interesting to work with them. The hard part, though, is knowing an exact list of critical security issues and approaches to them.

That’s why I asked ChatGPT for such list – on a level a solid principal engineer should know. The response was quite reasonable, so I spent some time refining the list, and here is the result! I keep it as a reference for myself, and I hope you’ll find it useful, too.

Core Web App Security

  • API Security: REST/GraphQL hardening, input validation, over/under-fetching prevention, API keys, HMAC, request signing, certificate pinning, replay prevention.
  • Authentication & Identity: password storage (bcrypt/argon2), MFA, OAuth2/OIDC, SAML, JWT best practices.
  • Authorization: RBAC, ABAC, least privilege, privilege escalation prevention.
  • CSRF Protection: tokens, SameSite cookies, double-submit cookie pattern.
  • Data Protection: encryption at rest (AES-256+), in transit (TLS 1.2+), key management.
  • Error Handling & Logging: no sensitive data leaks, structured logging, correlation IDs.
  • File Uploads: validation, MIME checks, virus scanning, sandboxing.
  • Injection Attacks: SQLi, NoSQLi, LDAP, OS command injection, template injection.
  • Input Validation: sanitization, strict schema validation, whitelisting.
  • Output Encoding: escaping for HTML, JS, CSS, URLs to prevent XSS.
  • Rate Limiting & DoS Protection: throttling, circuit breakers, caching.
  • Secrets Management: key rotation policies, vaults (e. g., HashiCorp Vault, AWS Secrets Manager).
  • Session Management: secure cookies, SameSite, HttpOnly, session fixation, token expiry/rotation.

Browser & Front-End Security

  • Clickjacking Protection: X-Frame-Options, frame-ancestors.
  • CSP (Content Security Policy): nonces, strict-dynamic, avoiding unsafe-inline.
  • HTTP caching headers: Cache-Control, Vary, Pragma for sensitive data.
  • Subresource Integrity (SRI) for 3rd-party scripts.
  • Trusted Types to mitigate DOM-based XSS.
  • Web Storage Security: storing sensitive data outside of localStorage or sessionStorage.

Infrastructure & Deployment

  • CI/CD Security: supply chain attacks, dependency scanning (SCA), signed builds.
  • Container Security: minimal images, runtime restrictions, scanning (Trivy, Clair).
  • DNS Security: DNSSEC, avoiding cache poisoning.
  • HTTPS Everywhere: HSTS, secure TLS configs, certificate rotation.
  • IaC Security: secure Terraform and CloudFormation, policy-as-code (OPA).
  • Reverse Proxies & WAFs: e. g., Cloudflare, AWS WAF.
  • Secret and Key Management: choosing correct algorithms (AES-GCM, RSA vs ECC, SHA-2/3), key rotation policies, HSMs/KMS use.
  • Secrets in CI/CD: no hardcoded creds, encrypted variables.

Operational & Organizational

  • Compliance & Privacy: GDPR, HIPAA, SOC2, PCI-DSS basics.
  • Dependency Management: SCA, patching, SBOMs.
  • External Attack Surface Discovery: domains, APIs, old endpoints.
  • Insider Threats: principle of least privilege, auditing.
  • Monitoring & Incident Response: SIEM, anomaly detection, alerting.
  • Secure SDLC: threat modeling, STRIDE, abuse cases, security reviews.
  • Security Testing: static analysis (SAST), dynamic analysis (DAST), penetration testing.
  • Zero Trust Principles: network segmentation, identity-aware access.

Advanced / Modern Web Concerns

  • AI/ML API Security: prompt injection, model data leaks.
  • GraphQL-specific Risks: introspection, batching attacks.
  • Multi-Tenancy & Data Isolation: proper tenant isolation in SaaS apps, preventing IDORs (Insecure Direct Object Reference)
  • Serverless Security: least privilege IAM, cold-start secrets, event injection.
  • SSRF & Cloud Metadata Protection.
  • Supply Chain Security: typosquatting, malicious packages.
  • WebSockets Security: auth, rate limiting, input validation.

How to Delete All Local Git Branches in One Command

First, checkout to main (or any other branch you want to clear from upstream branches).

Now, let’s build the command, step by step.

  1. Check which branches were merged to the current branch:
Shell
git branch --merged
  1. Filter out current branch from the output – it is marked by an asterisk (*):
Shell
git branch --merged | grep -v \*
  1. Turn the columnar output into a space-separated string:
Shell
git branch --merged | grep -v \* | xargs
  1. Feed these arguments to the deletion command (passed in the second argument of xargs):
Shell
git branch --merged | grep -v \* | xargs git branch -D

How to Recall Your Google Meets Fast

I have to confess. I am a sinner — I constantly forget to log my time spent on tasks! I postpone this demanding chore for a week, until our PM comes bashing my door (and I work remotely!): “Please log your time, we need to create reports!” And here lies the problem: usually, I can hardly remember even what happened yesterday, let alone the whole week. I believe I am not alone here.

Alright, so now I need to log my work time for the week. I can track code contributions by commit dates, but how do I log meeting times? A common way to do this is to sweep through emails, Slack messages and meeting notes, but it is chaotic and time-consuming. If you use Google Meet, there is a much more straightforward way — Google Takeout!

Google Takeout is a service that allows you to download all data Google keeps about your account. This is a very interesting yet terrifying resource: you’ll find data from over 60 different services, some of which may keep gigabytes of your data! But for our current goal, we only need Google Meet data.

What to do

First, visit https://takeout.google.com/ from a work account. Deselect all checkboxes, then find and mark Google Meet. Scroll to the bottom of the page, and click primary-colored buttons a couple of times. Google will prepare data export and will send a link to your email. Use it to download a zip archive with data and unpack it.

When you get to Google Takeout page, deselect all checkboxes and then find and mark Google Meet.
Click “Next step”, then “Create export” — Google will send a report to your account email in a minute.

The downloaded folder has a nested structure of ./Takeout/Google Meet/ConferenceHistory with two .csv files inside. We will need only conference_history_records.csv. It is a large csv file with about 20 columns, holding information about all meets for your account. Let’s tidy it up with some command line magic to get a convenient output:

Shell
awk -F ',' '{print $5 "\t" $10 "\t" $12}' "~/Downloads/Takeout/Google Meet/ConferenceHistory/conference_history_records.csv" | head -n 20 | column -ts $'\t'

This command parses the csv and outputs only important data in a columnar view: meeting code (the same one used in Google Meet Links), date and time of the meet and its duration.

Meeting Code  Start Time               Duration
rst-uvwx-yza  2025-08-17 14:14:14 UTC  1:07:18
fgh-ijkl-mno  2025-08-16 06:36:12 UTC  0:23:57
vwx-yzab-cde  2025-08-15 17:20:33 UTC  0:41:03
klm-nopq-rst  2025-08-14 09:09:09 UTC  1:15:42
yza-bcde-fgh  2025-08-13 20:48:06 UTC  0:55:56
hij-klmn-opq  2025-08-12 07:02:08 UTC  0:17:15
opq-rstu-vwx  2025-08-11 15:33:54 UTC  0:34:29
tuv-wxyz-abc  2025-08-10 05:44:21 UTC  1:49:37
def-ghij-klm  2025-08-09 19:59:59 UTC  0:26:04
uvw-xyza-bcd  2025-08-08 11:11:11 UTC  0:09:48

Now it is much easier to recall which meetings they were and how long they lasted. Unfortunately, this file does not provide meeting names — but now retrieving them is easy: just copy-paste meeting code into your gmail search box, and you will find your invitation email with all the details.

This way I manage to save myself some 15 to 20 minutes each week. I hope this trick helps you, too.

Earlier Ctrl + ↓