Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Let's discuss why CI tools and CI are completely different concepts.

What problem is CI meant to solve, where did the idea come from, what are the latest confirmations that it works, and how to understand if you have a practice rather than just an installed Jenkins.

The idea to give a talk on Continuous Integration came about a year ago when I was attending interviews looking for a job. I spoke with 10-15 companies, and only one was able to clearly explain what CI is and how they understood that they didn't have it. The others spouted vague nonsense about Jenkins 🙂 Well, we have Jenkins, it does builds, CI! In this talk, I will try to explain what Continuous Integration really is and why Jenkins and similar tools have very little to do with it.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

So, what usually comes to mind when you hear CI? Most people will think of Jenkins, Gitlab CI, Travis, etc.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Even if we Google it, we’ll get these tools.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

If you ask someone familiar, right after listing the tools, they will tell you that CI is when you have builds and tests running in your Pull Request on a commit.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Continuous Integration is not about tools, not about builds with tests in a branch! Continuous Integration is the practice of frequently integrating new code, and it is by no means necessary to set up Jenkins, GitLab, etc., to apply it.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Before we dig into what full CI looks like, let's first immerse ourselves in the context of the people who came up with it and feel the pain they were trying to solve.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

And that pain was collaborative work in a team!

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Let's look at examples of the challenges developers face when working in a team. We have a project, a master branch in git, and two developers.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

And they started working as everyone has long been accustomed to. They took a task in JIRA, created a feature branch, and wrote code.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

One finished the feature faster and merged it into master.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

The second needed more time, merged later, and encountered a conflict. Now, instead of writing the necessary features for the business, the developer spends their time and energy resolving conflicts.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

The more complex it is to integrate your feature with the main branch, the more time we spend on it. And this is still a fairly simple example. This example involves just two developers. Imagine if 10, 15, or even 100 people in a company are writing in one repository. You would go crazy resolving all these conflicts.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

There is a slightly different scenario. We have a master branch and several developers who are working on something.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

They created their own branches.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

One developer merged their work, everything went smoothly, and the task was submitted.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Meanwhile, the second developer completed their task. Let's say they submitted it for review. Many companies practice code reviews. On one hand, this is a good and beneficial practice, but on the other hand, it slows us down in many ways. We won't dive into that, but here's a great example of what a crooked review process can lead to. You submitted a pull request for review. The developer has nothing else to do. What do they start doing? They begin to take on other tasks.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

During this time, the second developer has been working on something else.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

The first developer completed a third task.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

After some considerable time, their review was tested, and they try to merge. What happens? They encounter a huge number of conflicts. Why? Because while their pull request was under review, the code changed significantly.

Besides the conflict issues, there's also the communication issue. While your branch is pending review, while you’re taking a long time on the feature, you lose track of what else is changing in the codebase of your service. It’s possible that what you’re trying to solve now was resolved yesterday, and you could simply reuse a method. But you won’t see that because you’re always working with an outdated branch. This outdated branch inevitably leads to merge conflicts.

So, when we work as a team, meaning that it’s not just one person tinkering in the repository, but rather 5-10 people, the longer we refrain from adding our code to the master branch, the more we suffer because ultimately something needs to be merged. The more conflicts we have, and the older the version we’re working with, the more problems we encounter.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Collaborating on something is painful! We always disrupt each other.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

This issue was noted more than 20 years ago. The first mention of Continuous Integration practice I found was in extreme programming.

Extreme programming is the first agile framework. The page appeared in 1996. The idea was to use certain programming, planning, and other practices to make development as flexible as possible, allowing us to respond more quickly to changes and requirements from our clients. They started facing the issue 24 years ago that if you work on something for a long time in isolation, you end up spending more time on it due to conflicts.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

Now, let's break down the phrase 'Continuous Integration' word by word. If translated literally, it means continuous integration. But how continuous it is is not very clear; it's actually quite intermittent. Also, how much it is integration is not so obvious either.

Therefore, I will now present quotes from extreme programming. We'll break down both words separately.

Integration — As I mentioned, we strive for each engineer to work with the most up-to-date version of the code, aiming to add their code to the main branch as frequently as possible, keeping these branches small. Because if they are large, we can easily get stuck for a week on merge conflicts. This is especially true if we have a long development cycle, like waterfall, where a developer spends a month building a huge feature. At the integration stage, they can get stuck for a very long time.

Integration is when we take our branch and integrate it with the master; we merge it. There is an ultimate version where we transbase developers, aiming to write directly to the master without any extra branches.

In general, integration means taking your code and bringing it into the master.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

What does the term 'continuous' mean here, what is referred to as continuity? The practice implies that the developer aims to integrate their code as quickly as possible. This is their goal when performing any task – to ensure that their code appears in the master as soon as possible. In an ideal world, developers would do this every few hours. That is, you take a small task, merge it into master. Everything is great. You strive for this. And it needs to be done continuously. As soon as you finish something, you immediately push it to master.

And the developer who does something is responsible for what they have done, ensuring it works and hasn’t broken anything. This is usually where testing comes into play. We want to run some tests on our commit, on our merge, to make sure this works. And this is where Jenkins can really help you.

However, with the idea that changes should be small, that tasks should be small, and that we should complete a task and immediately try to merge it into master – this is where no Jenkins can help. Because Jenkins will only help you run the tests.

You can manage without them. It won’t hinder you at all. Because the goal of the practice is to merge as often as possible, to avoid wasting a lot of time on conflicts in the future.

Imagine that it’s the year 2020 and, for some reason, there’s no internet. We’re working locally. We don’t have Jenkins. That’s fine. You can still take and create a local branch. You wrote some code in it. Completed a task in 3-4 hours. Switched to master, did a git pull, and merged your branch there. Done. If you do this often – congratulations, you have Continuous Integration!

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

What evidence is there in the modern world that this effort is worth it? Because overall it’s challenging. If you try to work like this, you’ll find that you need some planning, you’ll have to spend more time decomposing tasks. Because if you’re working on large tasks, you won’t be able to merge quickly and, accordingly, you’ll run into trouble. You won’t have any practice left.

And this will be expensive. Starting to work with Continuous Integration from tomorrow won't be possible. You will all take a long time to get used to it, a long time to learn to decompose tasks, and a long time to adjust your review practices, if you have any. Because our goal is to merge it today. If your reviews take three days, you have problems, and Continuous Integration won't work for you.

But do we have any relevant proofs right now that tell us investing in this practice makes sense?

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

The first thing that came to my mind is the State of DevOps. This is a study that they've been conducting for 7 years now. They are currently doing it as an independent organization, but under Google.

Their study in 2018 showed a correlation between companies that strive to use short-lived branches that integrate quickly and often, and have better IT performance metrics.

What are these metrics? They identify 4 metrics from all companies in their surveys: deployment frequency, lead time for changes, time to restore service, and change failure rate.

Firstly, there is this correlation; we know that companies that merge frequently have much better metrics. They categorize companies into several groups: slow companies that produce things slowly, medium performers, high performers, and the elite. The elite includes Netflix, Amazon, who are super fast, doing everything quickly, beautifully, and with quality.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

The second story that happened just a month ago. A wonderful note about Gitflow appeared in the Technology Radar. Gitflow differs from all others in that its branches live long. There are release branches that live for a long time, and feature branches that also last a long time. This practice was moved to HOLD in the Technology Radar. Why? Because people are facing integration pains.

If your branch lives for a very long time, it gets stuck, becomes stale, and we start spending more time making changes to it.

Recently, the author of Gitflow mentioned that if you aim for Continuous Integration and want to merge as often as possible, then Gitflow is not a good idea. He elaborated in the article that if you have a backend where you can strive for this, Gitflow becomes unnecessary because it will slow you down and create integration issues.

This does not mean that Gitflow is bad or that you shouldn't use it. It's suitable for different scenarios. For instance, when you need to maintain multiple versions of a service or application, i.e., when you need to support it over an extended period.

However, if you talk to people who maintain such services, you’ll hear a lot of frustration about versions like 3.2 that were released four months ago and didn’t include a certain fix. Now, to incorporate it, a lot of changes are required. They get stuck again, spending a week trying to merge a new feature.

As Alexander Kovalev correctly noted in the chat, correlation does not equal causation. That is, there isn’t a direct relationship that if you have Continuous Integration, all metrics will be excellent. However, there is a positive correlation that if one is true, the other is likely to be as well. It's not guaranteed, but it's probable. It’s merely a correlation.

Continuous Integration as a practice, not Jenkins. Andrey Alexandrov

It seems like we are already doing something, like merging, but how can we know that we genuinely have Continuous Integration and that we are merging often enough?

Jez Humble is the author of the Handbook, Accelerate, the Continuous Delivery website, and the book "Continuous Delivery." He proposes the following test:

  • An engineer's code is merged into the master branch daily.
  • You run unit tests on every commit.
  • If a build in the master branch fails, it is fixed in about 10 minutes.

He suggests using this test to ensure that you are indeed practicing Continuous Integration.

The last point I find somewhat disputable. That is, if you can fix it in 10 minutes, it means you have Continuous Integration, which sounds a bit strange to me, but it makes sense. Why? Because if you merge frequently, it means your changes are small. If a small change causes your master build to break, you can quickly find an example because the change is tiny. You had a small merge that changed 20-30 lines. Accordingly, you can quickly understand what the cause was because the changes are minuscule, giving you a very small area to search for the issue.

And even if our production breaks after a release, if we have Continuous Integration practice, it will be much easier for us to act because the changes are tiny. Yes, this will affect planning. It will be painful. And probably the hardest part of this practice is getting used to breaking tasks down, that is, figuring out how to take something and complete it in a few hours while also going through a review, if you have one. The review is a separate pain.

Unit tests are just a helper that helps you understand whether your integration has succeeded, whether anything is broken. In my opinion, this is also not an entirely mandatory point because the essence of the practice is not in that.

This is a brief overview of Continuous Integration. That's everything in this practice. I'm ready for questions.

Let me summarize once again briefly:

  • Continuous Integration is not Jenkins, it is not Gitlab.
  • It is not a tool; it is a practice about merging our code into the master as frequently as possible.
  • We do this to avoid the immense pain that arises from merges in the future, that is, we experience a small pain now to avoid a larger one later. That's the whole point.
  • Communication flows through the code, but I see it very rarely, though that was the intention behind it.

Questions

What to do with tasks that cannot be decomposed?

Decompose them. What’s the problem? Can you provide an example where there is a task that cannot be decomposed?

There are tasks that cannot be decomposed at all, for instance, those that require very deep expertise and can actually take a month to achieve a manageable result.

If I understand you correctly, there's a large and complex task whose results will only be visible in a month?

Yes, that's right. The result won't be assessable until at least a month has passed.

Okay. Generally, this is not a problem. Why? Because in this case, when we talk about branches, we are not referring to a feature branch. Features can be large and complex. They may involve many components. And we might not be able to complete everything in one branch. That's okay. We just need to break this down. If the feature isn't fully ready, it doesn't mean that certain parts of its code can't be merged. For example, you've added a migration and there are stages within the feature. Suppose you have a stage — to execute the migration, add a new method. You can already start merging those pieces daily.

Alright. What’s the point of that?

What's the point of merging small things daily?

Yes.

If something breaks, you'll notice it right away. When you have a small piece that caused the issue, it's easier to fix. The point is that merging a small piece now is much simpler than merging something large in a few weeks. And another point is that your other engineers will be working with the current code version. They'll see the migrations that have been added, and there's a method that they might want to use as well. Everyone will be aware of what's happening in the code. It's precisely for these three reasons that this practice is adopted.

Thanks, the question is resolved!

(Oleg Soroka) May I add something? You are absolutely correct; I just want to add one phrase.

Go ahead.

With Continuous Integration, code is merged into the main branch not when the feature is fully ready, but when the build stops breaking. And you can confidently commit to master as many times a day as you want. The second aspect is that if for some reason you can't break a month's task down into at least three-day tasks, let alone three-hour ones, then you have a huge problem. The fact that you don't have Continuous Integration is the least of your worries. It indicates that you have architectural issues and engineering practices are at zero. Because even if it's research, it still needs to be framed as hypotheses or cycles.

We discussed four metrics that distinguish successful companies from those that lag behind. You need to reach those four metrics first. If your average task takes a month, I would focus initially on that metric. I would reduce it to three days first and then think about Continuous.

Did I understand you correctly that you think it's not worth investing in engineering practices if any task takes a month?

You have Continuous Integration. And there's this point where you either fix a bug within ten minutes or roll it back. Imagine you deployed it. Moreover, you have continuous deployment, you pushed it to production, and only then noticed that something went wrong. You need to roll it back, but your database migration has already occurred. Your database schema is now at the next version, and moreover, there's been a backup, and data has already been written there.

And what alternative do you have? If you roll back the code, it won't be compatible with this updated database anymore.

The database only moves forward, yes.

People who have poor engineering practices likely haven't read a thick book about ... either. What to do with the backup? If you're restoring from a backup, it means you're losing data that was accumulated during that time. For example, you worked for three hours with the new version of the database, and users registered there. If you revert to an old backup because the schema doesn't work with the new version, you lose those users. And they are unhappy, they are complaining.

To master the full spectrum of practices supporting Continuous Integration and Continuous Delivery, it's not enough to just learn to write code. Firstly, there can be a lot of these practices, which makes it impractical. Additionally, there are numerous other practices like Scientific. There is one such practice that GitHub popularized at one time. This is when both old and new code are executed simultaneously. It's when you have an unfinished feature that can return some value, either as a function or through a Rest API. You're running both the new code and the old code and comparing the differences between them. If there is a difference, you log that event. This way, you know you are ready to deploy the new feature over the old one, as long as there have been no discrepancies between the two for a certain period of time.

There are hundreds of such practices. I would suggest starting with transbase development. It’s not 100% Continuous Integration, but the practices are similar; one cannot thrive without the other.

Did you mention transbase development as an example of where one can observe practices, or are you suggesting people start using transbase development?

To observe, as they won't be able to use it. To use it, one needs to read a lot. And when someone asks, 'What should I do with a feature that takes a month?' it means they haven't read about transbase development. I wouldn't advise it just yet. I would recommend focusing solely on how to correctly architecturally break down large tasks into smaller ones. That’s the essence of decomposition.

Decomposition is one of the architect's tools. We first conduct an analysis, then decompose, then synthesize, and finally integrate. This way, everything comes together. And one still needs to grow into Continuous Integration through decomposition. Questions arise at the first stage while we are already discussing the fourth stage, meaning that the more frequently integration is done, the better. It might still be too early for that; it would be better to refine your monolith first.

We need to draw some arrows and squares in some diagram. You can't say that now I'll show the architectural diagram of the new application and just show one square, inside which there's a green button for the application. In any case, there will be more squares and arrows. In every diagram I've seen, there were more than one. Decomposition is already happening even at the level of graphical representation. Therefore, the squares can be made independent. If not, then I have significant questions for the architect.

There's a question from the chat: "If the review is mandatory and takes a long time, somewhere a day or more?"

You have issues with practice. A review shouldn't take a day or more. This is similar to the previous question, just a bit softer. If the review takes a day, then it's likely because this review involves some very large change. It needs to be smaller. In the transbase development that Oleg recommended, there's this thing called continuous review. The idea is that we intentionally make the pull request so small because we aim to merge constantly and in small increments. As a result, the pull request changes one abstraction or 10 lines. Thanks to this, our reviews take a couple of minutes.

If the review takes a day or more, then something is wrong. First, you may have some issues with the architecture. Either it's a large chunk of code, say 1,000 lines. Or you have such a complicated architecture that a person can't understand it. This is a problem on the side, but it also needs to be addressed. Perhaps reviewing isn't even necessary. This is something to think about. Review - it’s the thing that slows you down. It has its benefits overall, but you need to understand why you are doing it. Is it a fast way to convey information for you, is it a way to establish some standards internally, or what? Why do you need it? Because the review should either be very quick or completely canceled. It's like transbase development - a very nice concept, but only for mature teams.

Regarding the 4 metrics, I would still recommend collecting them to understand what they lead to. Look at the numbers, see the picture of how bad everything is.

(Dmitry) I'm ready to discuss this with you. Numbers and metrics are great, practices are great. But we need to understand if it's necessary for the business. Some businesses do not require such rapid changes. I know companies where changes cannot be made every 15 minutes. And it's not because they're bad. It's just a lifecycle. To implement feature branches or feature toggles, deep knowledge is needed.

It's complicated. If you want to read more about feature toggles, I highly recommend it. https://trunkbaseddevelopment.com/. There's a wonderful article by Martin Fowler about feature toggles: the types, lifecycles, etc. Feature toggles – it's complex.

And you still haven't answered the question: 'Is Jenkins necessary or not?'

Jenkins isn't necessary in any case, really. To be serious, tools like Jenkins and Gitlab offer convenience. You'll see whether a build succeeded or not. They can help you, but they won't provide you with practices. They only give you a circle – Ok, not Ok. And that's if you are writing tests, because if there are no tests, it’s almost meaningless. So it's needed because it’s more convenient, but you can live without it; you won't lose much.

So if you have practices, does that mean you don't need it?

That's right. I recommend the Jez Humble test. I have mixed feelings about the last point. But overall, if you have three things: you merge constantly, you run tests on commits to the master, and you quickly fix the build in the master, then perhaps you don't need much more.

While we wait for questions from the participants, I have a question. We were talking about product code. Have you used it for infrastructure code as well? Is it the same code with the same principles and lifecycle, or are there different lifecycles and principles? Usually, when everyone talks about Continuous Integration and Development, they forget that there's infrastructure code too. And lately, it’s been growing more and more. Should all these rules be applied there?

Not just should they be applied, it would be great because it will definitely simplify life. As soon as we work with code, not with bash scripts, and we have proper code.

Hold on, a bash script is also code. Don't mess with my old love.

Alright, I won't trample on your memories. I have a personal aversion to bash. It breaks down unsightly and frighteningly all the time. And it breaks down often unpredictably, which is why I don't like it much. But okay, let's assume you have code in bash. Maybe I really don't understand it, and there are decent testing frameworks there. I'm just out of the loop. And we get the same advantages.

Once we treat infrastructure as code, we face all the same problems as developers. A few months ago, I encountered a situation where a colleague sent me a pull request with 1,000 lines of bash. And you get stuck in the review for 4 hours. The same issues arise. It's still code. And still collaborative work. We get stuck with pull requests and struggle with the same merge conflicts in bash, for example.

Right now, I'm actively looking at the most beautiful programming of infrastructure. I’ve introduced Pulumi into the infrastructure. This is programming in its purest form. It's even more appealing because I have all the features of a programming language—meaning I created pretty toggles with the same ifs effortlessly, and everything is good. My changes are already in the master branch. Everyone can see them. Other engineers are aware of it. It's already influenced something. However, it hasn't been enabled for all infrastructures. It's enabled for my test environments, for example. So, answering your question once again, it's necessary. It definitely simplifies life for us as engineers working with code.

Does anyone have any more questions?

I have a question. I want to continue the discussion with Oleg. Overall, I think you are right that if a task takes you a month, you have an issue with architecture, analysis, decomposition, planning, etc. But I have a feeling that if you start trying to live by Continuous Integration, you will begin to address the pains relating to planning, because there's no escaping from it.

(Oleg) Yes, that's right. In terms of effort, this practice is comparable to any other serious practice that changes culture. The hardest part to overcome is habits, especially bad ones. If implementing this practice requires a significant change in the habits of those around you: developers, management, production managers, then surprises await you.

What kind of surprises can there be? Let's say you've decided to do integration more frequently. And your integration is tied to other things, such as artifacts. Suppose your company has a policy that each artifact must be accounted for in some kind of artifact storage system. This takes a certain amount of time. A person needs to check that, as a release manager, they have approved this artifact for readiness for production release. If this takes 5-10-15 minutes, but you deploy once a week, then spending half an hour once a week is a small tax.

If you're doing Continuous Integration 10 times a day, then you need to multiply that by 30 minutes. And that exceeds the amount of working time for that release manager. They simply get tired of doing it. There are ongoing costs associated with certain practices. That's it.

You either need to cancel this rule so you don't engage in such nonsense, i.e., you no longer manually assign a degree of compliance of something to something else. You fully rely on some automated set of readiness tests.

And if you need proof from someone for the chief to sign off, and you don't go into production until Vasya says it’s okay, etc. – all this nonsense gets in the way of practices. Because if there are related activities that act as a tax, everything becomes a hundred times more cumbersome. So, the shift will often not be welcomed by everyone. Because it's difficult to change people's habits.

When a person does familiar work, they do it almost automatically. The cognitive load is almost zero. They just plug away at what’s ready; they already have a checklist in their head, having done it a thousand times. And as soon as you come in and say, 'Let's cancel this practice and implement a new one starting Monday,' it becomes a significant cognitive load for them. This shift happens for everyone at once.

Therefore, the simplest thing is, although not everyone can afford this luxury, that's exactly what I always do. When a new project launches, it's common to immediately integrate all untested practices into it. While the project is new, we don't take many risks. There’s no production yet; there's nothing to ruin. So it can be used as a training ground. This approach works. However, not all companies have the opportunity to frequently start such projects. Although this seems a bit strange too, as right now there's a total digital transformation happening, everyone should launch experiments to keep up with competitors.

Here you run into the fact that you need to first understand what you need to do. The world is not perfect, and production is not perfect either.

Yes, these things are interconnected.

Businesses also don't always understand that they need to head in a certain direction.

There are situations where no changes are possible at all. This happens when there's increased pressure on the team. The team is quite burned out already. They have no spare time for any experiments. They are busy all day long with features. And the management always wants more and more features. In such a situation, no changes are possible at all. The team can only be told that tomorrow they will do it just like yesterday, but they need to deliver a few more features. No transitions to any practices are possible in this sense. This is a classic situation where there’s no time to sharpen the axe; the trees must be cut down, so they are cutting with a dull axe. There are no simple solutions here.

(Dmitry) I’ll read a clarification from the chat: "But a large coverage in tests at different levels is necessary. How much time is allocated for testing? It seems a bit expensive, it takes a lot of time."

(Oleg) This is a classic misconception. There should be enough tests for you to have confidence in your code. Continuous Integration isn’t about running 100% tests first and then starting to apply the practice. Continuous Integration reduces your cognitive load because every change you see is so obvious that you can tell whether it will break something, even without tests. You can quickly validate it in your mind because they are small changes. Even if you only have manual testers, it is also easier for them. You roll it out and say, 'Check, did anything break?' They check and say, 'No, nothing broke.' Because the tester knows where to look. You have one commit linked to one piece of code. And this exploits specific behavior.

Here, you're embellishing a bit.

(Dmitry) I disagree here. There is a practice called Test-Driven Development that will help with this.

(Oleg) I haven't reached that point yet. The first illusion is that you must write exactly 100% tests or you shouldn't engage in Continuous Integration at all. This is false. These are two parallel practices that do not directly depend on each other. Your test coverage should be optimal. Optimal means you are confident that the quality of your master after the commit allows you to confidently hit the 'Deploy' button on a Friday evening while under the influence. How do you achieve this? Through reviews, coverage, and good monitoring.

Good monitoring is indistinguishable from tests. If you run tests once on pre-prod, they check all your user scenarios only once. But if you run them in an infinite loop, that’s your expanded monitoring system, which continuously tests everything—whether it has failed or not. In this case, the difference is only in the frequency of execution. A very good set of tests..., run infinitely, is monitoring. And proper monitoring should be like that.

And so how exactly you achieve that state, where you can deploy on a Friday evening and go home, is another question. Maybe you are just a bold daredevil.

Let's step back a bit to Continuous Integration. We veered off into another complex practice.

The second illusion is that MVP needs to be created quickly, so tests are not necessary at all. That's not quite true. The thing is, when you write user stories for an MVP, you can either develop them aimlessly, meaning you hear about some user story and immediately rush to code it, or you can follow TDD. And with TDD, as practice shows, it doesn't take longer; tests are merely a byproduct. The essence of TDD is not about testing. Despite being called Test Driven Development, it's really not about the tests at all. It's more of an architectural approach. It's a way of ensuring you're writing exactly what’s needed and not writing what isn't. This practice focuses on the next iteration of your thinking regarding the application's architecture.

Therefore, it’s not easy to shake off these illusions. MVP and tests don't contradict each other. In fact, it's quite the opposite: if you're creating an MVP using TDD practice, you'll do it better and faster than if you approach it without any practice, just haphazardly.

This is a very non-obvious and complex thought. When you hear that now you’re going to write tests and still accomplish something faster, it sounds absolutely absurd.

(Dmitry) Many people, when they mention MVP, are just too lazy to write something proper. These are still different things. Don’t turn MVP into something that doesn't work.

Yes, you're right.

And then suddenly MVP in production.

Forever.

TDD sounds very unusual when you hear that you're writing tests and seemingly doing more work. This sounds really strange, but it actually leads to faster and neater outcomes. When you're writing a test, you're already considering a lot about what the code will look like, how it will be invoked, and what behavior we expect from it. You're not just saying that you wrote some function that does something. You first think about the conditions it has, how it will be called. You cover that with tests, and from this, you understand how your code interfaces will look internally. It greatly impacts the architecture. Your code automatically becomes more modular because you first try to understand how you will test it, and only then do you write it.

My experience with TDD was that at one point I hired a mentor for Ruby when I was still a Ruby programmer. He said, "Let's do TDD." I thought, "Great, now I have to write even more stuff." We agreed that for two weeks, I would write all my working code in Python using TDD. After two weeks, I realized I didn't want to go back. After trying to apply it everywhere for two weeks, I understood how much easier it became to even just think. But it's not obvious, so I recommend to everyone that if you feel TDD is difficult, time-consuming, and unnecessary, try sticking to it for just two weeks. Two weeks were enough for me.

(Dmitry) We can expand on this idea from the perspective of infrastructure operation. Before launching anything new, we first do monitoring, and then we go live. In this case, monitoring becomes a normal form of testing. There's development through monitoring. But almost everyone says it takes too long, they're too lazy, and they've created a temporary draft. If we set up monitoring properly, we understand the state of the CI system. And a CI system has a lot of monitoring. We understand the system's status and what’s happening within it. During development, we actually create the system to reach the desired state.

These practices have been known for a long time. We discussed them about four years ago. But in those four years, almost nothing has changed.

But I suggest we conclude the official discussion on that note.

Video (inserted as a media element, but for some reason it doesn't work):

https://youtu.be/zZ3qXVN3Oic

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers đŸ”„ Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster