Как контролировать код ИИ-агентов: Quality Gates, архитектура и инструменты разработчика — Transcript
Full transcript
- 0:00Hello, friends. This is the Organized
- 0:02Programming podcast. I’m your host,
- 0:04Kirill Makevnin. I’ll be on my own today
- 0:07. And today's topic is Quality Gates and
- 0:11developer tools.
- 0:14If you follow my Telegram channel, you
- 0:17know I recently wrote a few posts on
- 0:20this topic, explaining how we are
- 0:23expanding our use of various linters—
- 0:25tools that not only check code against
- 0:28pre-set rules, but go a bit further,
- 0:31because we want agents to check more
- 0:34than just basic things in standard code
- 0:36, but also architectural rules and
- 0:39deeper concepts in general.
- 0:43And since I am currently working on
- 0:45another project alongside Hexlet—an
- 0:48entirely separate direction and business
- 0:50—we are launching an international
- 0:53marketing platform.
- 0:54It’s an open-source thing, a so-called
- 0:57OpenCore product. I’ve started showing
- 0:59it off quite a bit. Some people have
- 1:01already subscribed and are keeping an
- 1:03eye on it.
- 1:04I highly recommend doing that because
- 1:05it’s a product being built according to
- 1:07all the approaches and rules of modern
- 1:08AI-assisted development.
- 1:11It is literally one step away from
- 1:13release, from starting to sell it, and
- 1:15from actual implementation. So, this is
- 1:17a separate business of mine that you’ll
- 1:19be able to follow. You know how people
- 1:21say, "Go start a business and get rich.
- 1:23" Well, this is exactly that. It's a B2B
- 1:26SaaS that I’m building for specific
- 1:28reasons. This is a long-standing story;
- 1:30I’ve wanted to do it for a long time,
- 1:31but I didn't have the opportunity, time
- 1:33, or team. Now, AI really makes it
- 1:35possible. But it’s not a story—for those
- 1:37who watched previous episodes—about just
- 1:39slapping some code together and having
- 1:41it work. It’s clear that the main part
- 1:43is actually something else entirely. The
- 1:45product itself is straightforward, and
- 1:46it’s not that hard to build these days,
- 1:48especially if you know what to build.
- 1:50But implementation, sales, and
- 1:51understanding the market—that’s a
- 1:52completely different story. Far fewer
- 1:53people understand how that works and
- 1:55what needs to be done for it. But we
- 1:57happen to know a little bit about that.
- 1:59So you will be able to see firsthand how
- 2:01a product emerges from nothing and what
- 2:04its future fate will be. Accordingly, I
- 2:06will be reporting on it periodically.
- 2:08At least until we...you know how it
- 2:10often happens: people start a new
- 2:11project, they share and tell stories,
- 2:13but then, when it turns into a regular
- 2:15business and there’s a team and everyone
- 2:17is working, the founders just have a ton
- 2:18of other problems, and they aren't as
- 2:20interested in sharing anymore.
- 2:22And if at some point I stop talking
- 2:24about it, there will be two
- 2:25possibilities. Either nothing worked out
- 2:27, which I really wouldn't want, or quite
- 2:28the opposite, everything is good and
- 2:30we’ve simply entered normal business
- 2:31mode. I’ll probably just be approaching
- 2:33it from a different angle, I promise.
- 2:35But in any case, I will tell you about
- 2:36it, and you’ll be able to follow
- 2:38everything more or less in real-time.
- 2:40Why is it specifically related to that?
- 2:42Because, firstly, it's built using
- 2:44different technologies. It mainly uses
- 2:46Go.
- 2:48And since we were building this project
- 2:50according to certain principles from the
- 2:52start, plus Go is missing some things I
- 2:54need, I had to dig into this issue quite
- 2:56deeply to upgrade some technical aspects
- 2:58, which I’ll talk about today.
- 3:01So, that’s why today we’re talking a bit
- 3:04about developer tools, necessary for any
- 3:06base, related to things like hooks,
- 3:08setup, task execution, and so on, up to
- 3:11architecture checks.
- 3:13Basically, that’s our topic for today.
- 3:15So, let’s get started.
- 3:23I think the first thing I want to start
- 3:25with is auto-generation. There’s this
- 3:27belief with AIs that we can now generate
- 3:30anything we want.
- 3:31We don't need any libraries, we don't
- 3:33need frameworks, we can do everything
- 3:35from scratch, no problem at all.
- 3:37In reality, if you do that, there won’t
- 3:39just be a lot of code.
- 3:42First of all, it’s much harder to track
- 3:43boundaries, because, look, if you take a
- 3:45library, there’s a clear interface, it’s
- 3:47decoupled from you.
- 3:49If it’s done on the fly, and you don’t
- 3:52really check the code or watch what’s
- 3:54happening, it’s very easy for things
- 3:56that are usually separated, made
- 3:58independent, and isolated as modules to
- 4:00start blurring and mixing with the main
- 4:02logic.
- 4:03And there will be a lot, a lot, a lot of
- 4:04that.
- 4:05If you generate fast enough and add many
- 4:07features, reaching a point where you
- 4:09have a couple hundred thousand lines of
- 4:11code is absolutely trivial.
- 4:13It’s clear that with such a product, you
- 4:16won’t just deploy and release it easily
- 4:18. So it’s obvious that all of this still
- 4:21needs to be checked and you have to use
- 4:23your head, but there are still some
- 4:24basic principles that allow you to
- 4:26minimize the headache that will
- 4:28eventually arise from this generation.
- 4:30The first is understanding, in principle
- 4:32, what the system is built from, what it
- 4:33consists of, what elements there are,
- 4:35which elements can be extracted
- 4:36immediately, and which elements to use.
- 4:38For example, the first thing I used
- 4:40there and often talk about concerns
- 4:42generation.
- 4:43Instead of just taking raw Go, as people
- 4:45usually like to talk about—which, by the
- 4:48way, doesn't match what's happening on
- 4:50GitHub.
- 4:51There are tons of libraries on GitHub,
- 4:52and frameworks, and everything else. So
- 4:54, like, let's take raw Go and build
- 4:56everything from scratch.
- 4:58That’s certainly very fun and cool, but
- 5:00the thing is, a typical web project,
- 5:01well, a typical one—where there are lots
- 5:03of classic handlers, HTTP handlers, and
- 5:05so on.
- 5:06It could be an API, it could be a
- 5:08service. The thing I'm working on right
- 5:10now is a rather complex technical piece
- 5:11inside, with a bunch of different
- 5:13elements, like sending emails, and so on
- 5:14. And the concepts remain more or less
- 5:16the same. That is, you have handlers,
- 5:18there’s some business logic you need to
- 5:20call, there’s database interaction,
- 5:22there’s an API, you need to transform
- 5:24data, use some DTOs, and so on. Writing
- 5:27tests. In general, it’s an absolute
- 5:28classic for any web project, no matter
- 5:30what it’s doing. And in this whole mix
- 5:32of all these layers and all these
- 5:34stories that concern any web project,
- 5:36there are very clear parts, very clear
- 5:38approaches that should be used rather
- 5:40than neglected.
- 5:42So, the first is design-first; what are
- 5:44we talking about here?
- 5:45Design in this case refers to
- 5:47architectural design, not drawing
- 5:48pictures, because there is code-first
- 5:50and there is design-first. Code-first
- 5:52usually means we've knocked together
- 5:54some API, wrote documentation for it,
- 5:57threw it out to the frontend dev or
- 5:59whoever needed it at the time.
- 6:02It's clear that I'm doing all of this
- 6:03entirely by myself, from infrastructure
- 6:05to release, backend, frontend, and
- 6:06testing.
- 6:08There is no one else there. But even in
- 6:10this case, it’s important to think about
- 6:12how it will evolve from that perspective
- 6:13. And that's why I switched to a
- 6:15design-first approach, because it used
- 6:16to be difficult. You have to sit down,
- 6:18plan, design, you know, like the
- 6:19documentation, and then build something
- 6:21from that.
- 6:22And it was always very difficult,
- 6:24especially if you have a team, to get
- 6:26everyone to first change the API, the
- 6:28OpenAPI design, for example, and only
- 6:30then generate the corresponding elements
- 6:32that exist in the system.
- 6:34With CI, it became very simple, that is
- 6:37, practically effortless. Instead of
- 6:39building something right away, here is
- 6:40what I do first, there is a specific
- 6:42order to it. First, it’s not even the
- 6:44Open API that’s generated, but TypeSpec
- 6:46, which I also regularly talk about.
- 6:48It’s a language built on top of Open API
- 6:51that provides much better control
- 6:52guarantees. It’s more compact, more
- 6:54readable, and so on.
- 6:56It’s a really cool thing made by
- 6:58Microsoft, from which Open API is
- 6:59generated, and then, using ready-made
- 7:01tools—of which there are millions for
- 7:03frontend, backend, whatever you want—a
- 7:05literal ton of code is generated.
- 7:08I mean, not just a lot, but a whole lot
- 7:10of code. What does that include? Well,
- 7:12first of all, this thing immediately
- 7:14gives you an SDK for, say, Node. Well,
- 7:16basically, all SDKs in general.
- 7:18I mean, for example, clients for my
- 7:19platform here, they actually appear
- 7:20right out of the box simply because the
- 7:22generators exist.
- 7:23Furthermore, this thing fully generates
- 7:25frontend APIs for requests to the
- 7:27backend.
- 7:28Because when we talk about design-first
- 7:30, it’s not just about the external API.
- 7:33There are many different types of APIs.
- 7:34There’s an API for the site, an API for
- 7:36external users, and there could be other
- 7:38APIs too; in short, there are many kinds
- 7:39, and it generates all of them. So, some
- 7:41of these libraries are generated for
- 7:43external clients. And that means you
- 7:44don't have to write SDKs by hand at all
- 7:46. Everything is generated entirely from
- 7:48scratch. Whether you want it for Ruby,
- 7:50Go, Haskell, or any language like Rust—
- 7:52there you go, generated with zero human
- 7:55intervention. The second part is the
- 7:56generation, as I already mentioned, for
- 7:58frontend developers—or for the frontend
- 8:00in my case, because I’m building that
- 8:01too.
- 8:03In my setup, I use React Query, which
- 8:06effectively provides these abstractions
- 8:09related to my site.
- 8:11And then the UI uses that to perform the
- 8:14actual calls. This also saves a huge
- 8:16amount of code, resources, and attention
- 8:18when it’s all done, first of all,
- 8:20uniformly, and second, directly tied to
- 8:22this design.
- 8:24So the question of divergence doesn't
- 8:26even exist, because if the spec changes
- 8:28and then generation occurs, if something
- 8:29doesn't match in the types, it
- 8:31immediately makes itself known.
- 8:33It’s a very, very reliable thing. And
- 8:35one more important element.
- 8:38When I was choosing the Go approach, and
- 8:40specifically which coding style to pick
- 8:42, I was primarily looking not just at
- 8:44how popular an approach was, or how many
- 8:46pre-built middlewares there were, or
- 8:48even built-in test support—which is also
- 8:50quite important, because if the entire
- 8:52HTTP stack is loaded without options,
- 8:54like it was in Express, it's expensive,
- 8:56inconvenient, and creates a lot of
- 8:58various problems.
- 8:59I was also considering which of these
- 9:01approaches was most tailored for "
- 9:03design-first," meaning where the
- 9:05generators were.
- 9:06I think there were about four or five
- 9:08different frameworks I looked at.
- 9:10In the end, I found a library—well,
- 9:12there are two main ones that do the
- 9:14generation. One is more advanced, the
- 9:16other less so. I ended up choosing the
- 9:18one that is less popular, though it is
- 9:19still quite widely used. Ogen or
- 9:20something like that; I don't recall the
- 9:22exact name right now, but I'll provide
- 9:23it later. But the most important thing
- 9:24is that its level of generation is
- 9:25immense. It generates the incoming
- 9:27validation layer, the converters, and
- 9:29very importantly, all the handlers. It’s
- 9:32not just something that creates
- 9:34interfaces; it generates actual,
- 9:36specific handlers.
- 9:38All in all, it’s slightly worse than in
- 9:40Java, because in Spring Boot, for
- 9:42instance, you can generate a lot more,
- 9:44but it’s close to the ceiling of what is
- 9:46possible in Go regarding how much can be
- 9:49generated from that base design.
- 9:52In this podcast, I talk a lot about
- 9:53agentic development, Spec-Driven
- 9:55Development, and how the programmer's
- 9:57job is changing.
- 9:58But I don't just talk about it. Together
- 10:00with Prxsor, we are implementing these
- 10:02approaches in real engineering teams. We
- 10:04help transition from a situation where
- 10:06each developer uses Cursor or Cloud Code
- 10:07individually to a process where agents
- 10:09are integrated into the entire
- 10:11development cycle, from task definition
- 10:12to reviews, testing, and production. If
- 10:15you want to make this transition in your
- 10:16company, details are at prxsor.ru, link
- 10:18in the description. Just yesterday, as
- 10:21I'm currently running a program for
- 10:23programmers, I was giving a presentation
- 10:25to the guys, and I was showing what's
- 10:27happening using this project as an
- 10:29example. So, when I looked, it turned
- 10:31out that the project's codebase already
- 10:33has about 700,000 to 800,000 lines of
- 10:35code, of which, just so you understand,
- 10:37only 180,000 were written by hand. Well
- 10:40, he says "written by hand," but he
- 10:42means that's what the IDE wrote itself,
- 10:44rather than being generated by any other
- 10:46tools. Just think about that—more than
- 10:48500,000 lines of code were generated.
- 10:51It’s not just some trashy code, it’s
- 10:53that boilerplate code required for those
- 10:55hundreds of handlers, API endpoints,
- 10:57DTOs, converting data from the database
- 10:59into resources exposed externally, and
- 11:01so on and so forth.
- 11:02All of this is open; you can easily go
- 11:04in and take a look, and I believe that
- 11:06this approach is the future. Moreover, I
- 11:08am focusing on increasing the number of
- 11:10generators.
- 11:12That is, if I have some routine task
- 11:14where I need to generate something else
- 11:16, I don't ask the AI to write it for me
- 11:18in the first place.
- 11:20I first ask it, "Can this task be solved
- 11:22with an additional extension, for
- 11:24example, an emitter for TypeSpec?"
- 11:27Because you can write emitters for
- 11:28TypeSpec that can generate anything you
- 11:30need based on what is described in the
- 11:32TypeSpec.
- 11:33The same applies to OpenAPI, because
- 11:35there are also these generators for
- 11:37OpenAPI that are usually extensible,
- 11:38allowing you to write something to
- 11:40achieve the desired result.
- 11:42In other words, I ultimately try to
- 11:44reduce everything that is routine and
- 11:45boilerplate so that it isn't done by
- 11:47hand, but generated instead.
- 11:49And the main focus of writing code is on
- 11:52the logic. That is, where the business
- 11:54logic, entities, some wrapper around
- 11:56them, and so on, reside. By the way,
- 11:58that’s also interesting. I actually had
- 12:00to force it, because it doesn't do this
- 12:02by default, to force the AI to move this
- 12:04into a separate layer. I mean, it can be
- 12:06called different things. Let’s just call
- 12:08it a service layer for simplicity. It
- 12:10doesn't necessarily mean there are
- 12:11specific classes, services, etc., but
- 12:13rather a separate layer where the actual
- 12:15business logic lives.
- 12:17It was quite funny that while I was
- 12:18generating this project, I had a certain
- 12:21picture in my head of how to do it right
- 12:23, how to build layer interactions, who
- 12:24is responsible for what, where
- 12:26everything goes, and how to write tests
- 12:28.
- 12:29What did I do?
- 12:30I launched an agent and asked it to do
- 12:32some research, that is, to open all
- 12:33similar projects on GitHub—well, not all
- 12:35of them, but the top ten most popular
- 12:37ones written in Go—and analyze their
- 12:39architecture, comparing it specifically
- 12:41with what I have done.
- 12:43It turned out to be quite funny that in
- 12:46terms of isolating logic into separate,
- 12:48independently testable services that
- 12:50generalize business operations—all
- 12:53business operations—there seem to be
- 12:55almost no such projects.
- 12:57So, he gave me a report; I have the
- 12:59research, and by the way, it’s publicly
- 13:00available. You can open the Docs
- 13:02research folder and find the document
- 13:05where he shows that many of them don't
- 13:07even have this layer defined. There’s a
- 13:10lot of duplication, and he specifically
- 13:12noted that this project, called
- 13:13Sphericon, is done better in this regard
- 13:15.
- 13:16I still had a few shortcomings that I’m
- 13:18fixing right now, but overall he noted
- 13:20that from an architectural layering
- 13:21perspective, it’s more structured than
- 13:24all the other projects he looked at.
- 13:26That’s how the story goes.
- 13:28I’m not drawing any conclusions from
- 13:30this; it’s just that perhaps I have this
- 13:33thought because in Go, it’s somewhat
- 13:35denied or there aren't—not that there
- 13:37aren't established practices, but it's
- 13:39discussed less, and maybe given less
- 13:41attention because there’s an element of
- 13:44"we’re not like everyone else," right.
- 13:47But in practice, you get what you get,
- 13:49because this leads to duplication and
- 13:51smears the logic. In short, there are
- 13:53all sorts of different problems, but
- 13:54these are purely architectural things.
- 13:56So, even though, as you can see, the
- 13:58code isn’t written by hand, I never
- 14:00allow it to just generate whatever
- 14:02nonsense it wants. No, there are clear
- 14:04layers—in fact, there are many of them—
- 14:06and their areas of responsibility must
- 14:08be followed. If there’s a bug inside,
- 14:10well, that’s not a disaster; it will be
- 14:12covered by tests and will eventually be
- 14:13fixed one way or another, because it is
- 14:15being checked.
- 14:16Plus, there will be all sorts of error
- 14:18collectors, logs, tracing, everything
- 14:20under the sun, and metrics.
- 14:22I will never neglect that.
- 14:26It doesn’t depend on the level of the AI
- 14:28, because, well, the AI isn't capable—
- 14:30it's not magic that just takes
- 14:31everything in and solves all your
- 14:33problems for you.
- 14:35No, but of course, looking specifically
- 14:37into a concrete piece of code to see
- 14:39what’s happening there is not always
- 14:40necessary at all. That is true. By the
- 14:42way, regarding that, you know, I’m
- 14:44deliberately putting that point off. I
- 14:45have material in preparation on this
- 14:47topic about what code quality actually
- 14:48is, why you need to look at it, why you
- 14:50don't, where I will explain this
- 14:51position in more detail. I just don’t
- 14:53want to focus on it right now because
- 14:55it’s a bit of a separate issue, and it
- 14:57was quite funny. Let me just give you an
- 14:59example. Since I talk about this a lot,
- 15:01obviously, I get all kinds of different
- 15:02comments.
- 15:03In one place, a guy wrote a comment that
- 15:05he either disagrees or something, but
- 15:07the main thing is he gave an example:
- 15:08what if it uses concatenation instead of
- 15:10interpolation? Like, I don't trust it.
- 15:13And I realized how different our
- 15:15understanding of code quality and code
- 15:16architecture is, right?
- 15:18Because for me, what he’s describing is
- 15:20not at all what one should be focusing
- 15:22on. Firstly, a linter should be tracking
- 15:24that. Secondly, it has absolutely
- 15:25nothing to do with the actual quality we
- 15:27are talking about.
- 15:29But again, I won't go into detail on
- 15:31this thought right now, because it's
- 15:34such an important, separate topic that I
- 15:36want to cover it in a dedicated webinar
- 15:39—well, a podcast—and write several
- 15:41pieces on it.
- 15:43Yeah. That’s roughly the kind of circus
- 15:45that goes on. By the way, I just
- 15:47realized that, in principle, I can even
- 15:50show it, since I’ll be demonstrating
- 15:52various things today.
- 15:54Let me show you TypeSpec separately so
- 15:56you can see roughly what it looks like.
- 16:00So, this is the API design.
- 16:02On the left, we have the descriptions of
- 16:04the models, resources, and the API in
- 16:07general. And on the right, accordingly,
- 16:09is the Open API thing that gets
- 16:11generated.
- 16:12The spec, firstly, as you can see, turns
- 16:14out much longer, it's much harder to
- 16:16analyze and look at because it’s more
- 16:17machine-oriented, let’s say.
- 16:20TypeSpec, thanks to good tooling around
- 16:23it—like LSP support and checkers—is
- 16:26actually compiled, so it’s also
- 16:28well-verified.
- 16:30It can, in short, verify a lot more
- 16:31different things. That is, you need to
- 16:33write more boilerplate code around Open
- 16:35API to do the things you need.
- 16:37TypeSpec allows you to remove all that,
- 16:39to express it in more classic and
- 16:41familiar terms like models,
- 16:42relationships, interfaces, and so on.
- 16:44And thanks to this, not only is a lot of
- 16:46code reduced, but the level of
- 16:48understanding and control increases
- 16:50significantly. So, it's a cool thing. I
- 16:52recommend it to everyone who hasn't used
- 16:54it yet and is thinking about it. And
- 16:56I’ll just show you that here, when I
- 16:58talk about emitters, it's an important
- 17:00thing. You don't necessarily have to
- 17:02turn it into Open API right away. You
- 17:04can, in principle, create any emitters
- 17:06directly from TypeSpec. Moreover, it is
- 17:08extensible. So, roughly speaking, if you
- 17:11find OpenAPI to be limited in some way,
- 17:13TypeSpec is less restricted, it has many
- 17:15more possibilities, and therefore you
- 17:18can incorporate features into it that
- 17:20aren't in OpenAPI and write emitters
- 17:22directly. And ultimately, if they, say,
- 17:24really get serious about this,
- 17:26converting to OpenAPI, in principle,
- 17:27won't be necessary. You will be able to
- 17:29emit exactly what you need right away.
- 17:31Well, notice here that, sure, there's
- 17:33JSON schemas, just OpenAPI, they can
- 17:36emit Protobuf, GraphQL, and right now
- 17:38they are making clients for four
- 17:40languages: Java, Python, JavaScript, C#
- 17:42, and JavaScript servers; well, it's
- 17:44clear that there's still a lot to be
- 17:46added here.
- 17:47I hope they are working on it.
- 17:50It seems like, if you go to GitHub,
- 17:51let's see when their last commit was
- 17:53from Microsoft.
- 17:546 hours ago. So, in short, they are
- 17:56actively working on it. Anyway, that's
- 17:58good. I believe in this thing and will
- 18:01be a bit of an ambassador for it.
- 18:03So I've sort of become a little bit of a
- 18:05Microsoft ambassador in this area.
- 18:07So, um, I recently wrote a post, and
- 18:10it's not just a post.
- 18:12It turned out that when I started
- 18:15building this thing in Go, I saw a large
- 18:17number of, firstly, certain changes in
- 18:20my process, and secondly, a lack of some
- 18:22tools that I needed to add. And now I'm
- 18:25going to tell you about all of them. Why
- 18:27, by the way, someone might say, "
- 18:29Kirill, why are you using these new
- 18:30trendy buzzwords like 'Quality Gates'?"
- 18:32What kind of crap is that? Why don't you
- 18:34just say 'linters'? Yeah, well, I would
- 18:35think the same thing. Well, on one hand
- 18:37, you could say that, but on the other,
- 18:39I want to emphasize that all this is
- 18:41moving towards automation, and secondly
- 18:43, the range of capabilities is
- 18:45broadening slightly, things that, well,
- 18:47were never done with linters before and
- 18:49weren't thought of that way. For example
- 18:51, modern tools, they already look at the
- 18:53architecture in a sense, right? Formally
- 18:55, you could call them linters too, but
- 18:57the effect is different. I mean, you
- 18:59want to understand that our task is not
- 19:01to do this for ourselves, but we are
- 19:03doing it for the AI, so it can
- 19:05automatically verify what it's doing,
- 19:07specifically in a loop, right? So it
- 19:09made something, ran it, saw the errors,
- 19:11fixed them, and in this way, accordingly
- 19:13, it moves forward. So, in this
- 19:15terminology, it's called quality gates.
- 19:17And in this direction, the development
- 19:19of all further thought will proceed. So
- 19:22, what did I do? Let me demonstrate it
- 19:24to you.
- 19:25I created a repo called Death Quality
- 19:28Gates.
- 19:29Note that I've already received pull
- 19:30requests and it has reached 145 stars.
- 19:33That's pretty good. How, again, does
- 19:35this differ from, say, a regular list of
- 19:37linters for different languages?
- 19:40It differs because, in reality, if you
- 19:42dig deep, it turns out there are many
- 19:45tools that go well beyond the things
- 19:47we're used to.
- 19:49When we think about linters—let me give
- 19:51you some examples—first of all, sure,
- 19:53there’s security-related stuff, but
- 19:54there are also cool things, for example
- 19:56, related to Markdown. I mean, what are
- 19:58we usually used to? Well, in Markdown,
- 20:00they look at headers and things like
- 20:01that, but there's a tool, for instance,
- 20:03that looks for links and checks if
- 20:05they’re broken or not. Especially
- 20:06cross-links between Markdown documents.
- 20:08A really cool thing. Next is a
- 20:10spellchecker that checks for various
- 20:12errors. Well, that's a pretty obvious
- 20:13thing, right? Then there is an awesome
- 20:15linter. For us, as people who create
- 20:18courses and have many thousands of
- 20:19Markdown files with code examples that
- 20:22need constant maintenance, this is a
- 20:24lifesaver, because it’s not just a
- 20:26Markdown linter and formatter. It’s a
- 20:28cool extensible system that connects
- 20:31specific linters and formatters directly
- 20:33for code snippets. And, accordingly, all
- 20:36the code we have—we have a huge
- 20:39meta-repo that contains a ton of other
- 20:41repositories with courses and practices
- 20:44—it just en masse runs them through this
- 20:47, uh, Markdown—again, I guess you could
- 20:50call it that, but it includes everything
- 20:53—in short, through this tool, which not
- 20:56only checks Markdown, but also checks
- 20:58the code inside it using its linters and
- 21:01formatters. And this is, of course,
- 21:03fantastic, because before, with such
- 21:04volumes, you’d simply get exhausted from
- 21:06constantly fixing and cleaning things up
- 21:07. Especially when standards change in
- 21:09some languages, like: "Oh, now everyone
- 21:11move here." Like, we used to put a
- 21:12semicolon, but now we don’t. And you
- 21:14have to change that in thousands of
- 21:16files. Well, there’s always something to
- 21:17do, right? On the other hand, people
- 21:19also want to see that everything is
- 21:20implemented correctly, so this helps us
- 21:22with that. But it’s useful in more cases
- 21:23than just this one. So if you're writing
- 21:25any kind of documentation that includes
- 21:26code examples, honestly, it's just
- 21:28beautiful. Basically, there's an epic
- 21:30amount of stuff gathered here.
- 21:32It covers Git hooks, Git conventions—
- 21:35basically checking how we commit our
- 21:37code. A new tool has appeared that
- 21:40checks agent configurations, configs,
- 21:43MCPs, skills, and so on. You have to set
- 21:46up custom rules there. What else do we
- 21:48have? There's the obvious Dockerfiles
- 21:50and all the infrastructure stuff.
- 21:53There's a bot like Dependabot—for those
- 21:56who don't know, it's a free automated
- 21:58GitHub bot you connect to GitHub Actions
- 22:01, and it constantly sends you pull
- 22:03requests with updates and security
- 22:05patches.
- 22:08If you're on GitLab, you don't have that
- 22:09, but there's a bot called Renovate, and
- 22:11it does exactly the same thing.
- 22:14So, if you haven't connected it yet, now
- 22:16is the time to do it. There are error
- 22:18scanners, and there's this cool thing
- 22:21called Gitleaks that finds secrets if
- 22:23something has leaked. Again, just in
- 22:25case an agent did it by accident, even
- 22:27though they usually watch that closely,
- 22:29you never know, right? You don't want
- 22:30things leaking. And so on. There are
- 22:32things for specific languages, and there
- 22:34are some separate items I’ll explain now
- 22:36. By the way, there's this cool tool
- 22:37called Limit that checks your bundle
- 22:39size, for example, and tells you if
- 22:40you’ve done something wrong in your
- 22:42frontend. Do you know what the coolest
- 22:43part of this whole situation is? With
- 22:45all these lists in the past, what was
- 22:46always the problem? Everyone would put
- 22:48them together and say, "Oh, cool." You’d
- 22:50bookmark them, share them, but what
- 22:51comes next? Actually implementing and
- 22:53applying all of that is a huge problem.
- 22:55So, here’s how the modern approach works
- 22:58: having looked at the best cutting-edge
- 23:00techniques, I created a section called "
- 23:02It in your project," where you are
- 23:04simply given—my god!
- 23:06—a prompt snippet that you copy, and it
- 23:08just goes through this list, compares it
- 23:10to what you have, and tells you what you
- 23:12can change. And it actually works really
- 23:15well. I mean, I haven't seen anything
- 23:16like this before. Now people are writing
- 23:18in the comments: "Hey, I ran it, and it
- 23:20found four tools for me," they even send
- 23:21me screenshots, and people are just
- 23:23happy that they got something working.
- 23:25And I'm just like, "Damn, that's cool."
- 23:26There was no such range before. And now
- 23:27you can generally think about the things
- 23:30you do in this way. So, I highly
- 23:32recommend looking at what's happening
- 23:34from this perspective. By the way, you
- 23:35can perform updates in this manner.
- 23:37Meaning, when you have a guide, a
- 23:39migration guide from one thing to
- 23:40another, it can be more in the form of a
- 23:42prompt so that it can be fed into a
- 23:43machine and it does everything itself.
- 23:45But when I was doing all this, my goal
- 23:47wasn't just, you know, like an "awesome
- 23:49list" where they collect absolutely
- 23:50everything that exists.
- 23:53My goal was to curate a list of what I
- 23:55consider to be genuinely cool, because
- 23:57there are many similar tools, yes, but I
- 24:00have my own specific criteria for what
- 24:02is good and what is bad, what is
- 24:04promising and what is not.
- 24:07That's why, first of all, I named it a
- 24:09bit differently and explained right at
- 24:11the beginning that these are my personal
- 24:13preferences: one tool per task, if
- 24:15possible. They just overlap sometimes,
- 24:17so it's not always perfect. And it
- 24:19turned out that a lot of things people
- 24:21recommended to me later, or just wrote,
- 24:23"Kirill, check this out, do you have
- 24:25this?" No. How else did I do it?
- 24:28I don't just add them there; there is a
- 24:30folder inside the repository called "
- 24:32research," where I force the AI first—
- 24:34and naturally, everyone who sends pull
- 24:36requests—to conduct deep research on
- 24:38what is better and how it's used.
- 24:40Well, in general, a bunch of different
- 24:42aspects are checked there. And all the
- 24:44tools that were sent to me, sometimes
- 24:46I'd think, "Oh, maybe I really need this
- 24:48one?" I run it through there, and it
- 24:50tells me, "Listen, I’ve already done
- 24:51that research because I asked the agent
- 24:52to study everything that exists."
- 24:54"This tool is worse than ours for such
- 24:56and such reasons." In the end, I think
- 24:58only a couple were added, and even then
- 24:59, only in languages I hadn't covered
- 25:01initially. Something was added to Elixir
- 25:03and, maybe in Rust, I think something
- 25:04was add—wait, no, there were three or
- 25:06four, but those were brand new topics.
- 25:08But whenever I was shown an existing one
- 25:11that was already on the list, the one I
- 25:14already had always won. So all the
- 25:16others turned out not to be the right
- 25:18ones. Well, usually, you know, firstly,
- 25:19these are modern Rust-based tools.
- 25:21Secondly, there’s still a certain level
- 25:22of popularity, integration, and so on.
- 25:24Now, there are some things I really want
- 25:26to talk about separately. So, in essence
- 25:28, today will be a sort of review.
- 25:31I’ve partially mentioned this in my
- 25:33channel, but I want to voice it out,
- 25:35talking about the tools I’ve made or use
- 25:37and highly recommend to you.
- 25:40So, today is kind of an open-source
- 25:42advertisement in a sense. And I won’t be
- 25:44focusing on "look at this tool I made,"
- 25:46but rather on the problem itself,
- 25:48because it's very likely you haven't
- 25:50looked at it this way or thought about
- 25:52such an approach.
- 25:54And this might somehow help or give you
- 25:55a hint. I’ve been creating Hexlet
- 25:58courses since 2013. Right now, we are
- 26:00actively moving toward artificial
- 26:01intelligence. Agentic programming,
- 26:03automation, low-coding, and LLM
- 26:05programming. All of this is becoming a
- 26:07key direction in the near future. If you
- 26:09want to increase your productivity,
- 26:11implement AI-based solutions in your
- 26:13work, or start your own projects, you’ve
- 26:16come to the right place. You can look at
- 26:18specific training programs via the link
- 26:20in the description.
- 26:21Let me start with something I talk about
- 26:24regularly, but there's a nuance, and it
- 26:26needs to be said again.
- 26:28So, there’s this concept that you
- 26:31generally need to set up specific
- 26:33versions of languages and SDKs for each
- 26:36project, and you can’t really do that
- 26:39manually by default.
- 26:43That is, as a rule, if you have a Mac or
- 26:45, say, Ubuntu, your installers do
- 26:47everything globally, so you can't easily
- 26:49separate language versions.
- 26:52There are many different version
- 26:54managers. They are called version
- 26:56managers. It's very important not to
- 26:57confuse them with package managers,
- 26:58because a package manager handles
- 26:59packages for a specific language. Here,
- 27:00we mean the language itself: its
- 27:02interpreter, compiler, or whatever it is
- 27:04that makes it run.
- 27:05Accordingly, there is essentially such a
- 27:08tool for every language.
- 27:09But when you write in different
- 27:11languages, it becomes a problem, because
- 27:13, well, you'll get exhausted having to
- 27:15install these tools, update them, and
- 27:17manage things through them. And it's
- 27:19different everywhere. That’s why, at
- 27:21some point, the asdf tool became popular
- 27:23. It appeared many, many years ago, it
- 27:25was recommended to me, and I switched to
- 27:27it. But asdf was from before the Rust
- 27:29era, and it sort of got stuck there. And
- 27:31besides that, it honestly didn't have
- 27:33the simplest user interface. I forgot
- 27:35how to use it every single time, to be
- 27:36honest. But it did solve the problem
- 27:38well enough. And at some point, a guy
- 27:41showed up, some crazy open-sourcer who
- 27:44created mise.
- 27:46First off, it's written in Rust.
- 27:47Secondly, it's a super-fast tool.
- 27:50Thirdly, it's much simpler from an
- 27:51interface perspective. And that's
- 27:53exactly how it started. Moreover, I
- 27:55really want to mention this, because I
- 27:56explained it to some people in messages
- 27:58and they were shocked.
- 28:00Since it's been around for a while and
- 28:02many aren't following the updates, many
- 28:04still think it's just a thing that
- 28:06installs languages.
- 28:08I want to dedicate about 10 or 15
- 28:10minutes to it, to tell you what it has
- 28:12actually turned into, so you understand
- 28:15that right now it can replace a ton of
- 28:17various tools, custom scripts, and hacks
- 28:19, and work as a unified system to manage
- 28:22your entire development process. It’s
- 28:24just fantastic, guys. Honestly, I can't
- 28:26help but promote it, simply because it’s
- 28:28an insanely cool tool.
- 28:29By the way, I call it "mise," but it’s
- 28:31written there that it’s pronounced "
- 28:33meez." So, in reality, it should be
- 28:34called "meez." It's strange because I've
- 28:36never actually heard how it's pronounced
- 28:38. And you see, it turns out I’ve been
- 28:39pronouncing it wrong the whole time. Let
- 28:40me call it "mise" as it's written, and
- 28:42explain how it works. So, let's start
- 28:44like this. By default, you can clearly
- 28:46see it as a tool. It determines which
- 28:49Node, Python version, and so on, to
- 28:53install. Indeed, it all started with
- 28:55that, but that was just the beginning.
- 28:58After that, one of the next steps was
- 29:00expanding to the point of "let's just
- 29:02install anything."
- 29:04What's the difference if it's a language
- 29:06or something else? If you can install
- 29:08something via apt or brew, well, we can
- 29:10install any damn thing. That's why mise
- 29:12currently installs basically anything
- 29:14you want. And it does this from almost
- 29:16anywhere. What's very nice is that you
- 29:19don't need to worry; if you run this
- 29:22project with this config on different
- 29:24operating systems, it will simply ignore
- 29:27what isn't there. So you don't even have
- 29:29to keep track of that.
- 29:30This is also great, as it allows you to
- 29:33create cross-platform deployment
- 29:34environments based on it.
- 29:37So, for example, I have any tools there
- 29:39that are additionally needed for the
- 29:42project to work. And it doesn't matter
- 29:44if they might also be specified in a
- 29:45neighboring folder.
- 29:47It doesn't matter at all, because it
- 29:49will install and handle everything
- 29:50correctly and efficiently. Ah, so what’s
- 29:52included there?
- 29:53Let me just show you as an example what
- 29:55kind of tools I install in this project
- 29:57of mine, besides the languages.
- 30:01We’ll go into the source code now; it
- 30:02might lag a little because I have about
- 30:04five agents running in the background.
- 30:06So, here’s the config. Just look at the
- 30:08list of tools, right? There are
- 30:11basically two screens of them. What can
- 30:14I say? Uh, there are utilities here,
- 30:16languages, all sorts of linters, and
- 30:20checkers. And notice, they’re installed
- 30:23from GitHub, from Homebrew, and from NPM
- 30:26. In short, from everywhere. I think
- 30:28even C ++ is built directly here. It
- 30:30seemingly just compiles it itself. In
- 30:32short, it’s really cool. You can define
- 30:35anything you want this way. Note that
- 30:37some versions are pinned, while others
- 30:38are set to "latest," and it just
- 30:40installs them. Well, because for those,
- 30:41it’s not critical. That’s kind of a
- 30:42separate thing. I just want the latest
- 30:44one. A web server is installed, some
- 30:46kind of Caddy or CoreDNS, since we use
- 30:48DNS there for specific tasks. There’s a
- 30:50lot of stuff. That was the first thing
- 30:53that appeared. Here’s its extension.
- 30:54Second, that means managing environment
- 30:57variables. It sets them, it, uh, loads
- 31:00them.
- 31:02And most importantly—and you’ll see why
- 31:04this becomes significant—because Mise
- 31:06eventually expanded to cover almost all
- 31:08standard development tasks, this
- 31:10management of environment variables
- 31:12helps it automatically propagate
- 31:14everything everywhere: whether it’s
- 31:16tasks, running programs, hooks, and so
- 31:18on and so forth.
- 31:21Usually, this is a bit of a headache
- 31:23when you have to use all kinds of tricky
- 31:25mechanics, with various tools stored
- 31:27here, and separate tasks kept over there
- 31:29.
- 31:30All that kind of stuff. Let’s move on.
- 31:33So, the next thing it started doing: it
- 31:36suddenly took over the task-running
- 31:38history, meaning what Make or other
- 31:40runners usually do.
- 31:43If you remember, I always advocated for
- 31:45Make. And despite the existence of many
- 31:48different runners, mostly written in Go
- 31:50, by the way, and quite popular ones too
- 31:53, I somehow avoided them. I thought it
- 31:55was just another tool. There generally
- 31:57wasn't any point to it, as a rule. Make
- 31:59covered almost everything. Sometimes
- 32:01bash scripts, but then again, the IDE
- 32:02writes those. So, it feels like there
- 32:03are no problems at all. Yeah, Make
- 32:05doesn't show you the commands, but it
- 32:06feels like you're running them manually
- 32:08much less often now anyway.
- 32:10But on the other hand, why did I
- 32:11ultimately switch—if you look at the
- 32:13source code now, I’ve moved from
- 32:15Makefiles to mise everywhere, which is
- 32:17fantastic for me, because I’ve been
- 32:19advocating for Make since, like, 2011,
- 32:21and I used it in all my projects for 15
- 32:23years and was absolutely happy.
- 32:25And for only one reason: because mise,
- 32:28its system, is integrated with
- 32:30everything going on inside it.
- 32:33And since I’m not the one writing or
- 32:35monitoring it anyway, it’s much more
- 32:36convenient for me to have one tool that
- 32:38manages absolutely everything. Well,
- 32:40obviously. And plus, actually, there are
- 32:41, of course, some convenient features
- 32:42there. Like, you type "run," and you get
- 32:45a fuzzy search for the tasks that are
- 32:47available. I mean, there are really a
- 32:50lot of cool little features that truly
- 32:52improve the developer experience
- 32:53significantly. That’s why, in the end,
- 32:56it grew on me, and we’ve switched to it
- 32:58everywhere. And it has plenty of other
- 33:00features too. I’ll be honest with you,
- 33:02the guy is crazy; he releases it every
- 33:04single day, and every day there are just
- 33:06tons of changes. I am absolutely amazed
- 33:08by how much he gets done and how
- 33:09powerful this tool is. Look at what he
- 33:11does next. He implemented hooks into it
- 33:13. So, this thing also replaces all your
- 33:16git-hook, git-simple-hook, and so on and
- 33:18so forth. And at the same time, it can
- 33:20run its own commands internally using
- 33:22its own environment variables. Super,
- 33:24everything is integrated once again. And
- 33:26look, this isn’t the end.
- 33:28It has a bootstrap function, so it can
- 33:31be used as a system deployment tool,
- 33:33roughly speaking. So you're setting up
- 33:36your computer from scratch, and
- 33:38obviously, you still need to configure
- 33:39things, no matter what, regardless of
- 33:41the IDE you’re using. And I’ll show you
- 33:43what I did now. I had my dotfiles, which
- 33:46, by the way, are quite popular. A lot
- 33:48of people keep an eye on them. And
- 33:50before, there was a lot of manual work
- 33:51involved there. It used things like
- 33:53Docker, and I had to set up symlinks and
- 33:56so on.
- 33:57If you look, notice the activity—for a
- 33:59long time I was doing minor things here
- 34:01and there, and then there’s this spike.
- 34:03That spike happened recently for the
- 34:06sole reason that mise forced me to
- 34:08completely rethink my entire approach.
- 34:11Accordingly, first of all, it's clear
- 34:13that various agent skills and so on have
- 34:14appeared here, but most importantly,
- 34:16note that everything has simply come
- 34:18down to Miz. In essence, there is
- 34:19nothing else here. First, he didn't
- 34:21restructure it as is customary; he
- 34:22created the home directory specifically
- 34:24using the folders that are laid out so
- 34:26they match exactly for symlinking. So,
- 34:28what else does Miz do besides that?
- 34:30First, there is the Bootstrap, as I
- 34:32already said, which actually sets up the
- 34:33application from scratch.
- 34:35And what is also very important, it has
- 34:37dotfile management, meaning setting up
- 34:39symlinks, what to delete, update, and
- 34:41all that kind of thing. Now I'll open
- 34:43its config, yes, it's quite...so here's
- 34:46my config, you see, it's almost 400
- 34:48lines of code.
- 34:49What’s in it. So, first, so you
- 34:52understand, it directly handles command
- 34:55line settings and things like that, like
- 34:58Bash or Zsh. It even configures my macOS
- 34:59settings directly.
- 35:01I mean, there are some things when I'm
- 35:02setting up that I need to tweak, for
- 35:04example, which gestures I want to enable
- 35:05.
- 35:06It configures all that history. Next, it
- 35:08knows where, you see, the home is for
- 35:10dotfiles and their default mode is
- 35:12symlinks. It symlinks them. Here are the
- 35:14tools it installs. At the same time,
- 35:16these tools work globally. However, each
- 35:17project can also have its own, right?
- 35:19And accordingly, it installs, for
- 35:20example, bat, if anyone knows it. It’s a
- 35:22tool where you use bat instead of cat,
- 35:25and it outputs the file contents to the
- 35:27screen, but with syntax highlighting. So
- 35:29, it’s a very cool thing. It installs my
- 35:32VS Code dev containers, Docker, Docker
- 35:34Compose, and fzf. Well, in short, if you
- 35:37look, there’s just a ton of various
- 35:38utilities that are used globally. And
- 35:40ripgrep, some pandoc, yes, what else do
- 35:43we have? Terraform, treesitter is needed
- 35:45for something. And so on, in short. And
- 35:49various AWS command-line utilities. In
- 35:51general, everything that is needed
- 35:53overall. And notice, not even just for
- 35:55the command line; for example, my Chrome
- 35:57is updated through this thing. So I made
- 35:59it so that all the software I need is,
- 36:01in principle, installed through this
- 36:03stuff. I believe tools like guests are
- 36:05also installed here. So it turns out
- 36:07that it sets up not just purely
- 36:09developer things, it basically sets up
- 36:11my entire system. There. And,
- 36:14accordingly, the Bootstrap even sets up
- 36:15Brew, since it's not there by default.
- 36:17Just look at how many packages are
- 36:19installed via Brew. Telegram, Slack,
- 36:21WhatsApp, ChatGPT, CLI, OBS, Audacity—
- 36:23that's all for recording. Zoom, NordVPN
- 36:26, I use GCloud, and MK installs and even
- 36:30updates itself. In short, it's just
- 36:32beautiful. There's even an Oh My Zsh
- 36:34configuration here.
- 36:36And various features with dotfiles. Just
- 36:39wow.
- 36:41And the last major thing it does, as I
- 36:43already mentioned, you should explore it
- 36:45yourself because it has a ton of
- 36:47features.
- 36:49You might be surprised, but not everyone
- 36:51likes or wants to work with Docker
- 36:53Compose. To give you some context, I was
- 36:55one of those people who, back when it
- 36:57first appeared, acted as a kind of
- 36:59advocate for it. I moved all my projects
- 37:01over to Docker Compose. I recommended it
- 37:04to everyone and trained people on it. So
- 37:05, in a way, I contributed to Docker
- 37:07Compose being actively used everywhere.
- 37:10But, honestly, as time went on, there
- 37:13were more and more issues related to
- 37:16performance.
- 37:18On Macs, it's still honestly a problem
- 37:21with resources—the overall management,
- 37:23having some things inside and others
- 37:25outside, caches, the need for quick
- 37:27dependency updates, and so on.
- 37:30In short, a whole bunch of other
- 37:32problems started popping up. I mean, it
- 37:34seems like there’s isolation and all
- 37:35that. In production, it’s clearly very
- 37:37necessary and cool, but in development,
- 37:39in reality—especially considering the
- 37:41emergence of tools that set everything
- 37:44up automatically (since the problem used
- 37:46to be just setting it up)—the
- 37:48performance issues have become
- 37:49full-blown, absolutely massive. And for
- 37:52me, this shows up a lot because I often
- 37:54have many Docker containers running in
- 37:57parallel specifically for practice tasks
- 37:59. It turns out that when a project is
- 38:01running in Docker at the same time, my
- 38:03Docker literally freezes. Something
- 38:04happens regularly because there's so
- 38:06much—to give you an idea, I have about
- 38:09150 GB actively used by Docker images.
- 38:11That’s how much I have to build and run
- 38:13there. Well, that's just a
- 38:15Hexlet-specific thing.
- 38:17I just realized that I don't want my
- 38:18main project to depend on Docker,
- 38:19because I’d rather turn it off so it
- 38:20doesn't get in my way.
- 38:22And in the end, we did it semi-manually
- 38:24.
- 38:26You know, if anyone still remembers
- 38:27Procfiles or Foreman—that thing that
- 38:30could manage and launch processes—it was
- 38:32always a bit of a manual chore because
- 38:34you had to set everything up and
- 38:36configure it yourself.
- 38:38Well, now Mise has implemented that
- 38:40functionality internally. It has a
- 38:43mechanism like that. I'll try to check
- 38:45now if it's here in the docs or not. Ah
- 38:47, well, just look at how many things it
- 38:49does. It's called "daemons."
- 38:52Essentially, it's a separate utility,
- 38:55and Mise has become sort of an umbrella
- 38:57tool that connects many of its other
- 39:00tools.
- 39:02So, it's a separate thing integrated
- 39:04into it, which is managed via Mise,
- 39:06effectively replacing—let's call it—
- 39:08Docker Compose, but for regular
- 39:09processes.
- 39:11And that doesn't mean, by the way, that
- 39:13you can't even spin up containers there
- 39:14too. In fact, you describe the daemons
- 39:16you have in the very same config file.
- 39:19It can, for example, share ports or
- 39:21distribute them, so there are many
- 39:22features like that. It can start them,
- 39:25restart them, or start a whole set if
- 39:27needed. It shows their logs. Just the
- 39:29same. In short, it's an absolutely
- 39:31identical thing, but without using
- 39:32Docker Compose. Here is an example of
- 39:34how it's structured. See, there are
- 39:35tools, daemon descriptions, and tasks.
- 39:38So, you see, it's really cool that this
- 39:39is all done in one place. I didn't fully
- 39:41realize before how great it is when it's
- 39:43a single tool. Now you can see it, and
- 39:45it works amazingly well.
- 39:48Anyway, you can look at this yourself in
- 39:50the projects I'm talking about here.
- 39:53Yes, it's all public, everything is open
- 39:54.
- 39:55For instance, here are my daemon
- 39:57descriptions: a database, Mailpit—a
- 40:00separate utility where the mail we send
- 40:02goes.
- 40:04DNS runs separately, then the backend,
- 40:05frontend, and Dite—something else
- 40:07interesting. Actually, I don't even know
- 40:09what that thing is. Some contract, some
- 40:11server. Well, anyway, Caddy, and by the
- 40:14way, Mise can also sync skills.
- 40:17I wouldn't be surprised—in fact, I'm
- 40:18confident—that it's heading toward fully
- 40:21managing the setup of things like MSC,
- 40:22MCP servers, skills, and so on.
- 40:25So it will also become a system for all
- 40:27that stuff. Anyway, let me stop talking
- 40:29about it now.
- 40:31I hope, I really want to believe that
- 40:33I've convinced someone to take a look
- 40:35and try it out, because to me, it’s a
- 40:38truly brilliant solution that covers all
- 40:40the basic needs—it’s like a Swiss Army
- 40:42knife, but a proper one.
- 40:44It’s not an attempt to do everything,
- 40:46but an attempt to unite those things
- 40:48that should, in fact, be united. I have
- 40:50a bit of a prediction, if you will. I'll
- 40:52play the part of a psychic for a moment
- 40:54. While the approach used to be—well, it
- 40:56changed sometimes, but in general—let’s
- 40:58build independent utilities, even if
- 40:59they’re cool.
- 41:01Because we can now generate so much, and
- 41:03at a fairly high quality, and
- 41:05furthermore, many things need to be
- 41:07rethought with a modern approach, I’ve
- 41:09started to believe that some super-apps
- 41:11will emerge, similar to how it happened
- 41:13on mobile.
- 41:15I mean, MCP is a great example of why it
- 41:17doesn't make sense anymore to make any
- 41:19of these tasks a separate product that
- 41:21we invest in fully. Indeed, it can all
- 41:23be implemented by a single tool that
- 41:25divides everything between itself,
- 41:27shares resources, and allows us to
- 41:29properly describe and build
- 41:30relationships between them, because it’s
- 41:32ultimately one unified developer toolset
- 41:34that we need when we are actually
- 41:36working. So, I don't know if there are
- 41:38other similar tools on the horizon right
- 41:40now, but I'm certain that, in principle
- 41:42, they should be like this. Therefore,
- 41:43for all those making just a separate
- 41:46tool, say, for managing GitHub, well, to
- 41:48me, the value of such things is dropping
- 41:51sharply. If you recall, there were
- 41:52already many of them, and more have
- 41:54appeared, but what’s the point if they
- 41:56only cover that one part? You still need
- 41:58five or six other tools to cover the
- 41:59whole pipeline. Anyway, MCP has done it
- 42:01. For me, this is the point where you
- 42:04know you can relax; the issue is
- 42:07resolved, and they'll handle any further
- 42:09refinements as needed.
- 42:12I think the only thing left regarding
- 42:13global stuff is that there isn't a
- 42:15universal way to install MCP servers yet
- 42:16. I mean, there’s an approach for Claude
- 42:18, there’s an approach for others, but
- 42:20there’s no universal one yet. I’m sure
- 42:22they will take that on.
- 42:23By the way, I know there are attempts to
- 42:26create utilities that manage everything
- 42:29needed for agents.
- 42:30There are skills for installing skills,
- 42:32but only for skills. Microsoft is trying
- 42:34, for some reason in Python, I don't
- 42:36know why, to build some modern tool that
- 42:38allows you to define a general config,
- 42:40install MCP skills, or maybe something
- 42:41else, like plugins from marketplaces if
- 42:43needed.
- 42:44And now I see and realize that all of
- 42:46this is actually useless. Yes, someone
- 42:48else might try to do something like this
- 42:50or they might succeed, but eventually,
- 42:52once Mistral adds MCP support on top of
- 42:54its skills, that's it—box checked,
- 42:56nothing else is needed; it does
- 42:58everything in one single stroke, so to
- 43:00speak. We're done with that. Maybe I
- 43:02talked about it for a bit too long, but
- 43:04I really wanted to describe it in detail
- 43:06so you could understand the power of
- 43:07this whole system. And by the way, the
- 43:09Evil Martians didn't finish Left. I
- 43:12actually managed to switch to it in a
- 43:14couple of projects. We ran it for a
- 43:15couple of months and that was it, it
- 43:18became obsolete because Mistral appeared
- 43:20with all these features. Let's move on
- 43:22and talk about the rest. So, what did I
- 43:24have to write? I wrote about three or
- 43:27four tools, some partially in Go, some
- 43:29for everything else. I will just go
- 43:32through them now and tell you a little
- 43:34bit about them, because these tools are
- 43:37quite cool in themselves.
- 43:39And, perhaps, they will give you some
- 43:41ideas for your own projects. Let's get
- 43:44started. I'll open them up now and tell
- 43:46you about them. So, let's start with the
- 43:49"heavy" utility.
- 43:51When we work with a large number of
- 43:54agents now, how did we actually work
- 43:56before?
- 43:57Let's say I'm in "main" right now in my
- 43:59project, and I need to get something
- 44:01done. I create a branch, switch to it,
- 44:03and work in it. It's clear that nobody
- 44:04works in several branches in parallel.
- 44:06Meaning you work in one branch, if
- 44:08needed, switch to another or back to
- 44:10main, and somehow juggle all of that.
- 44:12With a multi-agent approach, that's no
- 44:14longer the case. Everything started
- 44:15working in parallel. On the other hand,
- 44:17by the way, people sometimes ask: "How
- 44:19do you manage five sessions in parallel
- 44:20?" There's a trick to it, guys. It's not
- 44:22about us working the old way in five
- 44:24different sessions. It's clear that
- 44:26while task planning is sequential, the
- 44:29execution is parallel. Because this
- 44:30constant micromanagement, where you
- 44:32intervene and say: "Oh, you're doing it
- 44:34wrong, do it this way." That's the old
- 44:35approach. Nobody does it that way
- 44:36anymore. Therefore, as a rule, there is
- 44:38a fairly long sequential design of tasks
- 44:41, but execution happens in parallel. And
- 44:43in general, you don't even have to do
- 44:45this on a computer anymore. You can do
- 44:46it remotely, because in the end, you
- 44:48only look at the final result. But for
- 44:50this to work, obviously, you need
- 44:51something like Spec-Driven Development
- 44:53and all other similar approaches. But
- 44:54that is just to illustrate how people
- 44:56run agents in parallel. Like that. They
- 44:58don't do it as if we just opened five
- 45:00branches at once, yeah, and are just
- 45:02hacking away. So, actually, when we move
- 45:04to such an approach, using pure branches
- 45:07. You just can't use "git switch". Why?
- 45:09Because if one of your agents switches,
- 45:11all the others are like: "Hey, what did
- 45:13you do? I want to do mine too." Yeah.
- 45:16And despite the fact that absolutely all
- 45:18agents work with worktrees, git worktree
- 45:21, without problems, they still often
- 45:23don't do it by default.
- 45:25That is, if you don't have it saved in
- 45:27memory anywhere or haven't explicitly
- 45:29told it to, I often notice this because
- 45:30, for example, I launched these four new
- 45:32big projects, including this "vivi" one
- 45:34that I'll describe to you now.
- 45:36When I tried to build some features that
- 45:37way, it immediately started creating
- 45:39branches.
- 45:40So it's still clear that if you start
- 45:41completely from scratch and it isn't
- 45:43trained, you have to teach it to use
- 45:44worktrees. Well, worktrees allow you to
- 45:46not overlap by using separate folders.
- 45:47Each works in its own environment. But
- 45:49there are, again, tools that allow you
- 45:51to manage these worktrees. People
- 45:53started recommending things to me like,
- 45:55check this out, check that out. In the
- 45:56end, I sat down with an IDE and realized
- 45:58that none of these things suited me or
- 45:59were even necessary in general. And
- 46:01there is a problem there. What kind?
- 46:03Even if you have a tool that knows how
- 46:04to create these worktrees, that's not
- 46:06the point. The point is what gets
- 46:07launched inside, and that is your logic
- 46:09. No tool is going to solve that for you
- 46:11. If we take typical web projects again
- 46:13, what appears there immediately? You
- 46:15need to start the project, right,
- 46:16there's the database, and then you have
- 46:18ports. Accordingly, if you don't do
- 46:20anything special, the ports will be the
- 46:23same. Meaning, if something started in
- 46:25one worktree, it will crash in another,
- 46:27well, because it can't spin up. Take
- 46:29running tests, for example, because if
- 46:31you have, say, five agents in a PT Work
- 46:333 running tests simultaneously, that's
- 46:35it—you're done for, everything will
- 46:37grind to a halt. Then, as a rule, even
- 46:39if you have a fairly advanced system,
- 46:41not only does it run in Work 3, but it
- 46:44can also launch several agents in
- 46:46parallel that diverge in various ways,
- 46:48which in turn leads to even more
- 46:50increasing load. Then, even if you've
- 46:52set up Work 3, you still need to install
- 46:54dependencies there, for example.
- 46:55And if you have, say, some kind of
- 46:57module, it might happen that each Work 3
- 46:59starts gobbling up 5-10 GB of space.
- 47:02So, despite the fact that we have
- 47:04mega-powerful machines now—the latest
- 47:06Macs are just out of this world—you
- 47:08suddenly find yourself in a situation
- 47:10where everything starts to lag, you run
- 47:12out of memory, the disk fills up, and
- 47:14everything locks up.
- 47:16And, having long forgotten about such
- 47:18problems when I was writing code myself
- 47:20before reaching high levels of
- 47:21parallelization, I ended up in a
- 47:23situation where I have to clear my disk
- 47:25every day. I have 500 GB, but those 200
- 47:27that fluctuate, they just get eaten up
- 47:29in 3 days, especially with some boom,
- 47:32you free it up, and you're already down
- 47:34a gigabyte.
- 47:35Yeah.
- 47:37And so, in addition to starting to use
- 47:39Work 3, the task emerged to use a large
- 47:41number of mechanics that allow for
- 47:43working effectively with these Work 3s
- 47:46and projects.
- 47:48And when I wrote a post about this
- 47:49recently, it turned out that a lot of
- 47:51people are currently facing the exact
- 47:52same pitfalls and are trying to solve
- 47:53them.
- 47:54And as practice shows, they are solving
- 47:56them in exactly the same way I described
- 47:57.
- 47:57Well, because overall this isn't some
- 47:59new story, but it is very actively
- 48:01occupying the minds of most developers.
- 48:04For those who have a job right now, a
- 48:06little disclaimer. So, what does that
- 48:09include? Let's go in order. First, for
- 48:11example, is assigning random ports,
- 48:14because it needs to run in parallel. And
- 48:17I just assigned this to an agent; it
- 48:18wrote the necessary scripts for me and
- 48:20used the right utilities. It’s basically
- 48:22the simplest part of the whole story,
- 48:23right, assigning random ports.
- 48:25Especially if you use something like
- 48:27Mesos, which handles the substitution,
- 48:29it also intelligently distributes it
- 48:31across all the components.
- 48:32Second is the database. So, first of all
- 48:36, if I were using Docker Compose, I’d be
- 48:39overwhelmed by having a separate compose
- 48:42instance starting up for every single
- 48:45project. It’s a pretty heavy thing, no
- 48:47matter how you look at it. Especially on
- 48:48a Mac. That’s why I just run a plain
- 48:50Postgres instance instead. It starts up
- 48:53once, and each project creates its own
- 48:55database inside. It just so happens that
- 48:57I’m using the latest Postgres everywhere
- 48:59, but even if there were different
- 49:00versions, well, okay, maybe a couple
- 49:01would run.
- 49:02So, I manage things by simply creating
- 49:04databases. But the DBMS instance itself
- 49:07is singular.
- 49:08This also applies if any other heavy
- 49:10components show up; they can be unified
- 49:12in this way so they’re reused.
- 49:14At the same time, nothing will conflict
- 49:16because, well, the databases inside are
- 49:18separate.
- 49:19Now, the next thing is the actual
- 49:21execution of heavy processes. And this
- 49:23is interesting. It became obvious that
- 49:25they needed to be ordered somehow. I
- 49:26started looking for utilities that could
- 49:28apply a lock.
- 49:29Instead of just running "make test" or,
- 49:32in this case, "ztest"—yes, that’s what I
- 49:34run—I wanted something that locks the
- 49:37execution, checks the logs to see what
- 49:39else is running, and waits its turn.
- 49:42There are several different utilities.
- 49:44One of them is "flock," for example, but
- 49:46it turned out it doesn't work that well
- 49:47on Mac or everywhere else. At first, he
- 49:49just threw together a bunch of scripts
- 49:51for me. And when I realized I needed
- 49:52this in three or four different projects
- 49:53, I thought, "This is kind of ridiculous
- 49:55." Why hasn't anyone written this yet?
- 49:57What did I do? I basically said, "
- 49:59Alright, enough, let's just write it."
- 50:01He actually came up with the name
- 50:02himself. I really liked this "heavy"
- 50:04idea. I said, "Let's do it, I don't have
- 50:05anything in Rust anyway." So, we banged
- 50:07out this thing in Rust. I included a
- 50:10link to it, by the way, in that post.
- 50:12Take note, it already has 35 stars. A
- 50:13whole bunch of people used it and said
- 50:15they were really happy with it.
- 50:17Basically, the utility is as simple as a
- 50:19brick to use. We place it before any
- 50:21execution.
- 50:22After that, it runs the command you need
- 50:24; it’s very cool and highly configurable
- 50:27.
- 50:27So, it doesn't just lock; it has slots.
- 50:30Meaning you can specify that, for
- 50:31example, three are allowed in parallel.
- 50:33And the slots aren't global, but rather
- 50:34for specific types of tasks. Meaning you
- 50:36can also create different pools. In
- 50:38general, there are quite a lot of such
- 50:40settings there. Plus, by the way, for
- 50:42example, something important and cool
- 50:43that turned out to be missing everywhere
- 50:45else is that it can handle nesting.
- 50:47That is, if you have things running at
- 50:49different stages and this appear at
- 50:52different levels—which can easily happen
- 50:54when there are many tasks combined into
- 50:57higher-level tasks—it knows how to
- 50:59aggregate them so it works with nested
- 51:01processes.
- 51:03And so on. In short, it's a very cool
- 51:06tool. You can, of course, write your own
- 51:08, or you can use this one. And right
- 51:10here, he specifically wrote why use his
- 51:12instead of other existing utilities. I
- 51:15highly recommend it. You have the source
- 51:18code, so you can take a look.
- 51:20The utility is as fast and compact as
- 51:21possible, tested, and can be used as a
- 51:23library or installed however you want.
- 51:25I've made all possible options available
- 51:28, whether through Cargo, Homebrew, or
- 51:30even just via binary—any way you like.
- 51:32This is the first thing I made.
- 51:34Again, I repeat, it's not about using
- 51:36this specific library, but about
- 51:38understanding the concept itself. I even
- 51:40had an exchange with one person who said
- 51:42, "I won't use it, I have my own project
- 51:44, but I stole a couple of good ideas
- 51:46from yours."
- 51:48So we ended up exchanging a few ideas on
- 51:50how such utilities are built.
- 51:53Alright, let's move on. That covers
- 51:55parallel execution. So, what else? Let
- 51:59me talk about something called DB
- 52:00Cleaner. It’s a bit of a surprise to me
- 52:03that this doesn't exist in Go. I'll
- 52:05explain the idea and concept now.
- 52:09So, if we take so-called "Rich
- 52:10Frameworks"—classic heavy frameworks
- 52:13that grew out of an earlier era, like
- 52:15Laravel, Rails, Spring Boot, or Django.
- 52:19And the list goes on. In short, there
- 52:21are these frameworks that are "
- 52:22all-inclusive," doing everything from
- 52:24start to finish.
- 52:26And at some point—quite early, to be
- 52:28fair, back in 2007 or even earlier—they
- 52:31came up with the concept that it's great
- 52:33to run tests within transactions.
- 52:36Firstly, you don't need to wipe the
- 52:38database, or you'd just get sick of
- 52:39testing. Secondly, there’s no point in
- 52:41doing that. Let's just start a
- 52:42transaction at the beginning of the test
- 52:44and roll it back at the end.
- 52:45Consequently, you don't need to monitor
- 52:47the data. It's incredibly fast. And it's
- 52:49just generally great. I’ve been using
- 52:51this approach my whole life.
- 52:53Of course, you might also have something
- 52:54like Redis, things that need to be
- 52:56closed, and external requests—
- 52:57everything is a bit more complex in real
- 52:59life.
- 52:59But at least for most projects, the key
- 53:01story of how to interact with the
- 53:03database is indeed solved in this exact
- 53:05way.
- 53:05You could, of course, ask about the
- 53:07logic that needs to run after a commit.
- 53:10You can work with that in reality.
- 53:12There are complex transactions, and ways
- 53:14to build such logic, and other
- 53:16approaches, and so on.
- 53:18But that remains outside the scope for
- 53:19now. Right now, we are only talking
- 53:21about the most core idea. In short,
- 53:22despite the fact that the approach is
- 53:24super popular and everyone who has
- 53:26written in such frameworks knows about
- 53:28it, in Go there are simply no solutions
- 53:30—none at all—that do this. And when I
- 53:32started this project, I immediately
- 53:34asked it to generate this kind of thing
- 53:35for me. It generated something, and the
- 53:37tests were executed accordingly.
- 53:39But again, I have three such projects in
- 53:41Go, some private and two or three public
- 53:44ones.
- 53:45By the way, the Basic code has also been
- 53:46rewritten in Go, and it has this too.
- 53:48And I thought, "Alright, it's time to
- 53:51extract it separately." At the same time
- 53:53, when I first started extracting it, I
- 53:54thought, "Okay, what do people talk
- 53:56about most often here?""First of all,
- 53:57let's try testcontainers." I thought, "
- 53:59Well, let's try it and see if
- 54:01testcontainers can solve anything, where
- 54:03a container is spun up for each test and
- 54:05then destroyed.""In general, it seems
- 54:07like a beauty." And let's also try
- 54:09another approach with templates. This
- 54:11has become really popular now too. It
- 54:13uses a copy-on-write technique, and you
- 54:14create a kind of template inside the
- 54:15database. Accordingly, it’s as if the
- 54:17database is copied, though not entirely
- 54:19. And then you can work with it. So it's
- 54:21kind of like another approach. I asked
- 54:23this thing to conduct some research. And
- 54:26guess what it did for me? Well, the AI
- 54:28showed me this kind of thing. It
- 54:31analyzed, in short, how much time it
- 54:34takes. I’ll fast forward here and show
- 54:36you.
- 54:38It turned out that the approach with
- 54:39deletions and transactions is, well,
- 54:41incredibly faster.
- 54:43That is, compared to working with
- 54:44templates. For some reason,
- 54:45testcontainers aren't shown here, by the
- 54:46way. Back then it showed me a similar
- 54:48story there.
- 54:49But templates and testcontainers,
- 54:51despite seeming fast—I mean, what’s 50
- 54:54milliseconds or 80 milliseconds, right?
- 54:58Or with testcontainers, there was a
- 55:00similar example, but compared to a
- 55:01transaction that takes 3 milliseconds,
- 55:03that is, excuse me, a lot.
- 55:06Especially when we're talking about a
- 55:08very, very large number of tests,
- 55:09parallel runs, and everything else,
- 55:11because you need to look a bit deeper
- 55:13there; one thing is transactions,
- 55:14another thing is all those templates and
- 55:16testcontainers, which also involve
- 55:18spinning up actual processes and so on.
- 55:20Accordingly, the load increases not only
- 55:22on the CPU, but on the overall context.
- 55:24And what happens because of this? It's
- 55:26that at high volumes, this becomes very
- 55:29noticeable. In the end, even though I
- 55:31initially thought: "Okay, fine, guys,
- 55:33let's do it the way you're used to,
- 55:34let's not use transactions, let's do it
- 55:36differently." Even the AI itself—again,
- 55:37it's not that it convinced me, it's just
- 55:39that I discussed it with it for a long
- 55:40time in detail. Besides, I do understand
- 55:42a little bit about what I'm doing. I
- 55:44came to the conclusion that if I take
- 55:45any other path, I'll be digging my own
- 55:47grave, especially as the number of tests
- 55:49keeps growing. So, in the end, I built
- 55:51this utility that works with SQL DB,
- 55:53meaning it's universal and can connect
- 55:56to anything. And it works on the
- 55:58principle: start the test, roll it back
- 55:59. This, by the way, is a port,
- 56:01essentially, of database cleaner. There
- 56:03is this thing in Ruby. It supports
- 56:04various strategies there, including a
- 56:06truncate strategy, which is also here.
- 56:08You can, like, truncate instead of using
- 56:10transactions, if anyone needs that. At
- 56:12first, I named it PG Cleaner and built
- 56:14it, but then I thought, why am I being
- 56:16so dense? And so, I redesigned it. And
- 56:18now this thing works, basically, as an
- 56:20almost universal tool. Although, it
- 56:22doesn't have all the databases yet.
- 56:24SQLite, MySQL, MariaDB, Postgres. Well,
- 56:26you can add more if needed. In short,
- 56:28this thing can easily connect to your
- 56:30project and allow you to do this. Again
- 56:32, even if you—well, it's shown here,
- 56:35everything works quite simply and easily
- 56:37. You can take a look at the source code
- 56:39, it's a small project, but the concept
- 56:41itself is very important.
- 56:43So, if you have a situation where it's
- 56:45important to run tests quickly, I
- 56:47generally recommend experimenting and
- 56:49looking into testcontainers, templates,
- 56:51and transaction commit-rollback cycles.
- 56:54If you operate under the assumption that
- 56:57you don't need any of this because you
- 56:58just mock everything, then we’re just
- 57:01not on the same page.
- 57:02I’m of the opinion that you shouldn't
- 57:04mock the database. Moving on. So, I made
- 57:06another library, but it’s more of a
- 57:08linter. A very interesting and unusual
- 57:10linter that I essentially swiped from
- 57:12Ruby. What's more, some of you have seen
- 57:15my podcast with the creator of the
- 57:17library I took this from. There's a
- 57:19library there called
- 57:21database_consistency.
- 57:23It does a very interesting thing. It
- 57:25looks at your database schema. That is,
- 57:28you need to give it direct access to the
- 57:29database, so it’s a bit trickier than a
- 57:31regular linter. And then it compares
- 57:33that against how your entities are
- 57:34described in the code. And this can be—
- 57:36well, in Ruby, everything is simple.
- 57:38There’s like a single ORM in Rails,
- 57:40which is Active Record. In Go, of course
- 57:42, it's a bit more complex because there
- 57:44are many tools you can use to work with
- 57:46the database. In any case, there is some
- 57:47sort of abstraction. It's not like
- 57:48you’re just sending raw queries and
- 57:50getting something back. Typically,
- 57:51there’s some compilation, there are
- 57:53structs, so all of that exists. And
- 57:55that’s why it was a bit harder for me to
- 57:57do this, but also a bit easier, because
- 57:58again, an agent is doing it. And what
- 58:00did I ask it to do? I said, "Let's do
- 58:02this."
- 58:03We need something that, following the
- 58:06rules from database_consistency, takes
- 58:08all the most modern approaches to
- 58:10database interaction and can work
- 58:12universally through adapters to compare
- 58:15constraints in the database with
- 58:17constraints in the code.
- 58:19You might ask, "What kind of constraints
- 58:20are these?""What could be the problem?"
- 58:22"Well, there can be many problems." Here
- 58:24, I’m showing a list of what’s included
- 58:25. For example, when you have redundant
- 58:28indexes, duplicate indexes, missing
- 58:30uniqueness—for instance, it's present in
- 58:33one place but not another.
- 58:35Nullability, booleans, the use of
- 58:38certain prefixes, mandatory vs. optional
- 58:41fields, missed or unadded foreign keys,
- 58:43and so on and so forth.
- 58:46In short, a whole host of things that,
- 58:47technically, could probably be expanded
- 58:49further, but I’ve got about twenty rules
- 58:51here that are being checked.
- 58:53And despite the fact that, it would seem
- 58:54, the ORMs there aren't that rich and
- 58:56it's supposedly a bit easier to control
- 58:58everything there, when I made this thing
- 58:59and ran it, it immediately found flaws
- 59:01in my new project.
- 59:03So, accordingly, it fixed them, and now
- 59:04, after that, it's controlled and it
- 59:06doesn't happen anymore.
- 59:07Accordingly, I'm happy, everyone's happy
- 59:10, and I believe this project deserves to
- 59:13be noticed and used more often.
- 59:15But for now, since this is, so to speak
- 59:17, my release and I'm talking about it
- 59:19for the first time, I might see how it's
- 59:21received and how often it gets used. So
- 59:23it's quite possible that there will be
- 59:25more expansion here if someone comes
- 59:26along with their own stuff.
- 59:28By the way, when I was building it, I
- 59:30specifically asked for it to be written
- 59:32in such a way that plugins for other
- 59:33systems—since it doesn't cover
- 59:35everything, right?
- 59:37Maybe you've built something yourself in
- 59:39your project for working with the
- 59:40database—could be added, so it's easily
- 59:42extensible.
- 59:43Meaning you don't necessarily have to
- 59:44submit a pull request here, although
- 59:46that would be nice.
- 59:47Instead, you can just create an
- 59:49additional adapter for the specific
- 59:51system you're using, and it will
- 59:53accordingly check all this stuff.
- 59:55Out of the box, it works with ent, bun,
- 59:58and gorm. There’s serif here too, I
- 1:00:00think, by the way. You can open the
- 1:00:02adapter folder and see how many there
- 1:00:03are. Bun next. Bun and G. Gorm next
- 1:00:07static model.
- 1:00:09In short, five or six adapters.
- 1:00:12So that's the kind of thing it is. By
- 1:00:13the way, there's already a pull request
- 1:00:14here. Let's take a look at this pull
- 1:00:15request from, probably, dependabot. Ah,
- 1:00:17yes, it's a release. There were just
- 1:00:19some changes there. It's suggesting I
- 1:00:20release it. And the last thing I want to
- 1:00:23talk about right now is, so to speak,
- 1:00:25the pinnacle of these "dev quality gates
- 1:00:27," which is called "pass"; when we were
- 1:00:29choosing the word, my IDE even told me
- 1:00:32that it's a word that even natives don't
- 1:00:34really know.
- 1:00:35It's like a pass for access to some
- 1:00:38territory.
- 1:00:39And it's really cool because it's easy
- 1:00:41to read, easy to write, easy to
- 1:00:43understand, and at the same time, it
- 1:00:45describes well what it is.
- 1:00:47So, look, an approach has become popular
- 1:00:49now where we decide to write a linter
- 1:00:51that specifically checks architectural
- 1:00:54rules. Architectural rules—well, what
- 1:00:55can be included in those? For example,
- 1:00:57primarily the dependencies between
- 1:00:59modules and components. Who can go where
- 1:01:01, who can look at what, who can use what
- 1:01:03and where.
- 1:01:04The complexity of this thing lies in the
- 1:01:06fact that it needs to have access to the
- 1:01:08runtime. I mean, it's not enough for it
- 1:01:10to just, well, basically access types.
- 1:01:12It's not, it's not enough. Wait, I'm
- 1:01:14slightly wrong here. Ideally, it needs
- 1:01:16runtime, but at the very least, it needs
- 1:01:19type information that an AST simply
- 1:01:22cannot provide.
- 1:01:24Meaning, if you use the same ast-grep I
- 1:01:26mentioned earlier, where it can break
- 1:01:28down any language into a tree for you,
- 1:01:30and then you add your own rules.
- 1:01:33First of all, those rules still can't be
- 1:01:35very deeply nested. For example, this
- 1:01:37thing can be used here, but this thing
- 1:01:39can't. Secondly, it lacks type
- 1:01:40information because, for example,
- 1:01:42there's basic type inference, and it
- 1:01:44doesn't always understand everything, so
- 1:01:46we needed a tool that can handle that.
- 1:01:47And someone might say, "Kirill, such
- 1:01:49tools already exist." And it's true,
- 1:01:50they do exist for some languages. There
- 1:01:52are actually very few of them, but they
- 1:01:53exist. I mean, for example, for Go
- 1:01:54there's this, for Ruby there's that, and
- 1:01:56so on.
- 1:01:58And they try to describe things like: I
- 1:02:00have these specific layers, they are in
- 1:02:02these folders, with certain naming
- 1:02:03conventions, who can depend on whom and
- 1:02:05who can't, often with very tricky
- 1:02:07configurations—for instance, something
- 1:02:09might be allowed directly in tests, but
- 1:02:11not here.
- 1:02:12For example, SQL queries aren't allowed
- 1:02:14directly here, but there's an exception
- 1:02:15, so it's allowed there. So, there are
- 1:02:17quite complex dependencies and intricate
- 1:02:19rules for how this all works. And as you
- 1:02:21can imagine, riding the wave of starting
- 1:02:23all this, I thought, well, there isn't
- 1:02:25really one great universal tool yet.
- 1:02:27Is it even possible to create one?
- 1:02:29At first, I built it based on ast-grep,
- 1:02:31but it immediately showed me—well, it
- 1:02:33was obvious—that you can't verify truly
- 1:02:35proper, robust rules through it. I
- 1:02:37thought, well then, this tool is useless
- 1:02:40, because in that case, one could just
- 1:02:42use ast-grep directly.
- 1:02:45So I started looking for options,
- 1:02:46wondering if it's possible to make it a
- 1:02:48universal utility that can still get the
- 1:02:50necessary info.
- 1:02:51And you know what I found? I'll show you
- 1:02:53right now.
- 1:02:54It turns out there’s this thing called
- 1:02:57the Code Intelligence Protocol.
- 1:02:59I had no idea about it at all. It's a
- 1:03:01fairly new thing. It's pronounced "skip
- 1:03:03," and it describes itself as a Language
- 1:03:05Agnostic Protocol for indexing source
- 1:03:07code. It's used for things like go to
- 1:03:09definition, find reference, and so on.
- 1:03:11It's a standardized, unified format. It
- 1:03:13turned out that many tools are already
- 1:03:15using this gizmo. So, I must have really
- 1:03:18missed out on this. And, as you can see
- 1:03:20, it essentially solves the problem I
- 1:03:22need addressed.
- 1:03:24I mean, it does require various
- 1:03:25compilers and such, but at least it can
- 1:03:27be run in a somewhat universal way.
- 1:03:30Anyway, I connected this thing and
- 1:03:31rewrote it; the first version was based
- 1:03:33on grep, and I rewrote it using this,
- 1:03:35then added quite a few languages that I
- 1:03:37didn't have initially.
- 1:03:39I'll list the languages connected here.
- 1:03:41Take a look. Go, TypeScript, Python,
- 1:03:43Java, R, C#, Ruby, Kotlin, PHP, Swift.
- 1:03:45There. And it states what is available
- 1:03:47for each language. Notice the absolutely
- 1:03:49giant README that describes all its
- 1:03:51capabilities. I mean, I 100%tried to
- 1:03:54make it that way. I did a deep research
- 1:03:56session where I took all similar tools,
- 1:03:58all similar feature requests, all
- 1:04:00articles on the topic, and shoved in
- 1:04:02every possible thing that could go in
- 1:04:04there. And just so you understand, it
- 1:04:06wasn't just a "let's throw it in" idea.
- 1:04:08Roughly speaking, I was working on this
- 1:04:10project in parallel with several others
- 1:04:12, including Sflcon and Hexlet.
- 1:04:15I'd send it over and say, "Look, your
- 1:04:16rules state how things should be,
- 1:04:18because I've accumulated a lot of rules
- 1:04:20on how to code over this time."
- 1:04:23I'd say, "Look at which problems this
- 1:04:24can convert into automated checks for
- 1:04:26you."
- 1:04:27And they'd be like, "Oh, for instance, I
- 1:04:28can enforce these five rules using this
- 1:04:30thing." I do the same in another project
- 1:04:32. "Oh, I can use these rules." But they
- 1:04:34would reply: "First off, look, this part
- 1:04:36is inconvenient because there are
- 1:04:38exceptions, then I can't port this rule
- 1:04:39, and so on." And I had a session with
- 1:04:41probably five or six back-and-forth
- 1:04:43exchanges. Until I reached a point where
- 1:04:45the majority of their rules and how they
- 1:04:47wanted to express them could indeed be
- 1:04:49expressed. And, in principle, it no
- 1:04:50longer made sense to be involved in it
- 1:04:52manually.
- 1:04:53Basically, I just started connecting it
- 1:04:55to the projects I'm involved in and
- 1:04:57stating that any rules that can be
- 1:04:59expressed through this thing should be.
- 1:05:01It looks, as you can see, like this.
- 1:05:03So, it describes the layers, the rules,
- 1:05:06who can depend on whom, and who cannot.
- 1:05:09Uh, well, obviously there are excludes
- 1:05:11and so on, the rules.
- 1:05:13In short, a billion different kinds of
- 1:05:15dependencies.
- 1:05:17And the number of rules here is probably
- 1:05:19about 15, if I'm not mistaken, checking
- 1:05:21what is happening.
- 1:05:23Yeah.
- 1:05:24Yes, for instance, who can import a
- 1:05:26component, defining layers and forbidden
- 1:05:28dependencies. Overall, I'll be honest, I
- 1:05:31liked it so much. I hope that this thing
- 1:05:34becomes super popular. I will develop it
- 1:05:36and use it to the max, because out of
- 1:05:38everything I have, this is probably the
- 1:05:40highest level of abstraction I’ve
- 1:05:42managed to achieve, which enforces very
- 1:05:44high-level rules. After I connected a
- 1:05:46certain amount, despite the fact that I
- 1:05:48was monitoring it overall, one still
- 1:05:49needs to understand the difference
- 1:05:51between automatic checks and the
- 1:05:52recommendations or descriptions found in
- 1:05:54your agency, MD, and other configs. So,
- 1:05:56even though I monitor this very closely
- 1:05:58and there were many rules, once I
- 1:05:59connected this thing, it immediately
- 1:06:01found hundreds of errors in different
- 1:06:03places. Well, simply because when the
- 1:06:05code exceeds a hundred thousand lines,
- 1:06:06it's hard to keep track of everything,
- 1:06:08and after that, it became easier to
- 1:06:09rework.
- 1:06:11Another issue is that when I switched to
- 1:06:13this skip mechanism, this parsing
- 1:06:15protocol, and expanded it to everything
- 1:06:17possible, even though it's written
- 1:06:19efficiently—I believe it's all written
- 1:06:21in Rust—it still started working slowly
- 1:06:23, just purely because all of this takes
- 1:06:26time.
- 1:06:27That is why, at some point, I simply
- 1:06:29moved this check out of, you know where
- 1:06:31?
- 1:06:32So, it’s not in my regular make check,
- 1:06:34which runs with every change, but I
- 1:06:35moved it to a nightly check instead.
- 1:06:38Meaning the rules themselves still exist
- 1:06:40, and it keeps track of them in terms of
- 1:06:41meaning, like an IDE. But the formal
- 1:06:43check itself, to see that there's
- 1:06:45nothing in the code, I run it at night,
- 1:06:47and accordingly, all the changes that
- 1:06:49came in are fixed after that. Anyway,
- 1:06:51that’s the kind of gadget I ended up
- 1:06:52with. And it, like my other tools and
- 1:06:55like this printer, has a concept of a
- 1:06:57baseline. I’ll explain for those who
- 1:06:59don’t know how this is structured in
- 1:07:00modern linters, again. So, when you
- 1:07:02install this thing on a new project, it
- 1:07:03will most likely show you billions of
- 1:07:05errors if you describe everything you
- 1:07:07want, right?
- 1:07:08And there is a concept called a baseline
- 1:07:10, where you run it and say, "this is the
- 1:07:12baseline," so it decides that we won't
- 1:07:14show these errors because we need to
- 1:07:15start from scratch; otherwise, it’s very
- 1:07:17hard to set up and follow when
- 1:07:19everything is full of errors, right?
- 1:07:21So, at least the checks would pass.
- 1:07:23Accordingly, it generates a special file
- 1:07:25where it describes all of this as
- 1:07:26exceptions. And then, essentially, you
- 1:07:29just need to request a separate task or
- 1:07:31run an agent that takes this baseline
- 1:07:33file, removes those exclusions bit by
- 1:07:36bit, and fixes the code this way until
- 1:07:38everything is resolved. So, this is a
- 1:07:40very cool mechanic in all modern
- 1:07:42verification systems that allows you to
- 1:07:44connect it without worrying about the
- 1:07:45thousands of errors you have, waiting
- 1:07:47for them all to turn green before you
- 1:07:49can finish. That's the kind of thing it
- 1:07:51is.
- 1:07:51By the way, when I was talking, I forgot
- 1:07:54to mention something else, you know what
- 1:07:56kind of thing exists. While I was
- 1:07:58looking for all these tools, I found a
- 1:08:00cool tool, for example. You'll find it
- 1:08:02in the dev quality gates; it looks at
- 1:08:05your Open API and sees the changes
- 1:08:07you've made, let's say in a new release
- 1:08:09, and checks, for example, for backward
- 1:08:12compatibility violations. If there are
- 1:08:14any, it won't let it pass. How do you
- 1:08:16like that? I probably wouldn't have
- 1:08:17thought about it that way, or at least
- 1:08:19it wouldn't have occurred to me until it
- 1:08:21was suggested. Well, perhaps, again,
- 1:08:23because the project is still young and
- 1:08:25we haven't reached production yet—we’re
- 1:08:27still in the process, especially with
- 1:08:29our design-first approach.
- 1:08:31But overall, I think there will be
- 1:08:33plenty of new ideas and concepts,
- 1:08:35especially if people notice them and
- 1:08:37pull them from different languages,
- 1:08:39because different languages have various
- 1:08:42cool gadgets that will ultimately allow
- 1:08:44you to wrap everything up like this and
- 1:08:46force the project to follow a large
- 1:08:48number of formal rules, and generally
- 1:08:50move many things to a formal level.
- 1:08:54Well, guys, that's probably about the
- 1:08:55story I wanted to tell today. Thank you
- 1:08:57all very much. I hope it was interesting
- 1:08:59and useful.
- 1:09:00Be sure to write in the comments what
- 1:09:02new things you learned, what you applied
- 1:09:04, how it helped you, or any new tricks I
- 1:09:06didn't mention that you think everyone
- 1:09:08should know about.
- 1:09:10I will definitely read them, check them
- 1:09:11out, add to them if needed, and give
- 1:09:12them a like. And, of course, send over a
- 1:09:14pull request. So, until next time. Bye
- 1:09:17everyone.
- 1:09:23Hey
About this transcript
This page contains the full transcript of Как контролировать код ИИ-агентов: Quality Gates, архитектура и инструменты разработчика by Организованное программирование | Кирилл Мокевнин, generated from the public captions YouTube serves with the video. The transcript has 13,481 words across 2,105 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.
What you can do with it
Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to choose a caption track available on the video.
Free YouTube transcript tool
YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, caption language selection, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.