Skip to content
View dudo's full-sized avatar




  • Pro


@cqrs @cardbinder @dudo-website @orbservability
Block or Report

Block or report dudo

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Please don't include any personal information such as legal names or email addresses. Maximum 100 characters, markdown supported. This note will be visible to only you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse

Engineering Philosophy


The battle against complexity in web development is a constant tug of war. We give a little to get something new, we take it back to make it simpler. Progress is good. Complexity is a bridge. Simplicity is the destination.

I love this quote from DHH. For those unfamiliar, DHH is the founder of Ruby's Rails framework, and is a huge proponent of the "mighty monolith." While I admire DHH's stance on simplicity, we diverge on architectural ideals. Modern tooling streamlines microservices management:

  • Container Orchestration in the cloud automates deployment and scaling of 12-factor apps.
  • Service meshes externalize common code for inter-service communication. This enhances traffic management and security.
  • Schemas predefine APIs, often automating client and server code generation.
  • Federated GraphQL consolidates GraphQL schemas, optimizing API organization and microservice communication.
  • Events foster service independence, boosting scalability and resiliency via asynchronous communication.

Tangentially, an essential part of our job is knowing when to buy versus build. When services are small and have a singular purpose, there's often a SaaS solution. There's no sense in reinventing the wheel, after all.

Development Environment

Containerization changed everything. Long ago are the days of needing a version manager for every language you’re working with. asdf solves part of the problem, but docker renders most version tooling obsolete. Docker compose makes stitching apps, data stores, and tooling together painless. In other words, setting up our local environment is as easy as setting up docker...

Configure docker compose files with tooling to run any language or framework commands. I prefer them to Makefiles.

# pro-tip
alias dr='docker compose run --rm '

dr npm install left-pad
dr npm update

dr go get -d
dr go mod tidy

dr bundle install
dr bundle exec rails db:setup

Spinning up a local environment simply consists of:

docker compose up -d


Let’s keep code styling consistent with linters. There is community tooling for all languages, so be sure to configure your editor.

Continuous Integration

Let's protect ourselves from... ourselves. CI enables us to do things like:

  • verify our tests are passing
  • check our code against linters
  • static code analysis
  • build various artifacts
  • keep our dependencies current

...all without having to know much about any given repo. Configure integration failures to be verbose, with clear steps to rectify any errors.

GitHub Actions is a wonderful solution. Use reusable workflows and templates to add Actions to a repo.

Continuous Deployment

Embracing GitOps, tools like Flux and ArgoCD enable pull-based deployments straight to Kubernetes. This keeps git as our single source of truth! Operators within the Kubernetes cluster align their state with the source code, minimizing the system's attack surface and guaranteeing the capture of all changes.

Resource Provisioning

GitOps also centralizes infrastructure declarations. While Terraform is a go-to, cloud providers offer their alternatives.


Security is like an onion...

  • Starting with code, employ static analysis tools to catch vulnerabilities before they reach production. CI should be running a suite of security checks with every commit.
  • Prefer hardened, minimal base images and employ network policies to create a fortress around services. Terraform isn’t just for provisioning; it’s for crafting a secure foundation.
  • At runtime, utilize a defense-in-depth strategy. Monitoring, logging, and alerting systems keep us informed, while an incident response plan ensures we're ready to act when necessary.
  • Ensure we're always a step ahead. Embrace continuous education and adherence to best practices like regular patching and updates.


So... your PR was merged. Congratulations! An image was built, tagged, and pushed up to the container registry. An operator within Kubernetes has presumably detected the new tag, pulled the image, and started a canary rollout. Incoming requests are gradually diverted to new pods. Your changes are taking traffic. Now what?

If you can afford Datadog, go with them as they're best-in-class. Grafana's LGTM stack is excellent for self-managed setups. Regardless of the tool, microservices necessitate advanced observability, and distributed tracing is critical. Logs and metrics still have their utility, but some companies have transitioned to event-based systems.

Last, but not least, always remember to go SLO to go fast!


Development Environment





This README has been optimized for accessibility based on GitHub's blogpost "Tips for Making your GitHub Profile Page Accessible".


    ## Jeep
    * 2006 Wrangler Unlimited (LJ)
  2. turing-pi turing-pi Public

    Continuous Deployment for local ARM64 based Kubernetes cluster

    Dockerfile 9

  3. Tooling for Interacting with Kubernetes Tooling for Interacting with Kubernetes
    # Kubernetes local development
    ## kubectl
    - Install Docker for Mac
  4. tag_check tag_check Public

    Checks the code for a version. Compares that version with GitHub.

    Shell 4 2

  5. create_kustomized_namespace create_kustomized_namespace Public

    Ruby 5

  6. ruby_twirp_skeleton ruby_twirp_skeleton Public

    Ruby Twirp template

    Ruby 1