Comments by "Daniel Sandberg" (@ddanielsandberg) on "Continuous Delivery" channel.

  1. 36
  2. The problem is that you end up with developers that has no clue how their things actually works in the real world so they can't make informed decisions, or even know who to ask the right questions. How do you expect to grow seniors, innovate and be competitive when you have devs that has no clue about CI/CD, TDD/BDD, observability, operability or how their decisions affects the system in production and are stuck with the some kind of "I write code, then magic happen" culture? While a good developer-friendly platform is a good thing, it should be there to help with the everyday BAU work and add constraints (governance and compliance). It shall not be an excuse to "dumb it down for developers". An anti-pattern I see all the time is seniors "controlling" and doing "programming by remote control" with an attitude of "I must review everything because I'm the senior". So many organizations hire juniors to just fill a seat and expects them to be productive and because of all the new people they try to control the work with processes and the aforementioned programming by remote control, not (wanting to) understand that for every junior developers they add they are actually removing a senior developer for the next six months. Because that is the job of seniors - to mentor and coach so that the new people *can* be a trusted productive member of the team. An organization with senior devs that does not understand these "sociological" things is not a good place to be. I don't care if they have been doing it for 20 years and can write the most beautiful code ever written; if these things are alien to them they are *not* seniors (you'd be surprised how common this is). The primary job of a senior engineer is to create more senior engineers.
    24
  3. 23
  4. 14
  5. 14
  6. 13
  7. 10
  8. 9
  9. 8
  10. 7
  11. 7
  12. 7
  13. 6
  14. 5
  15. 5
  16. 4
  17. 4
  18. 4
  19. 4
  20. Do you mean "trying TBD" just like organizations "tries Scrum" by replacing requirement with user-story, milestone with sprint, deadline with release-trains, keep assigning devs by "percentage utilization" and doing annual budgets, writing 500 pages of "design" for a year before starting, developers communicating using Jira-tickets instead of talking, and nothing really changes, culturally or behavioral, et. al? You can't just decide to "go CI/TBD" unless you have the practices and tools that makes it possible. Like pairing, TDD, good fast build system, being able to make changes by many-many small steps without ripping 23 modules apart for 3 days and a culture that supports it. CI/TBD is a skill, and just like everything else it takes time to get there. I would suggest to start by setting up some things: 1. Make sure there are high-level tests covering the most important happy-paths. 2. Make these tests fast, unfragile, and make them/the system runnable on developers machines. 3. No changes gets committed without some kind of test covering the code being changed. 4. No feature branch lasts for more than 1 day. 5. Get a build system that tests main at every merge/commit. 6. If the build turn red - you have 10 minutes to fix it, or revert it. 7. If you can't get the build back to green EVERYBODY in the team stops what they are doing and do anything they can to get it back to green. There is no situation where a failing build is OK to just leave and keep doing other work (which usually happens with branches - habits matters). Getting these things into place, and making them a habit will go a long way. Next we turn the heat up: 8. Pair program as much as possible. Not every change requires a review (and some changes can be reviewed after the fact. See "Ship / Show / Ask" by martin fowler). 9. Try to slice changes into small parts that takes a couple of hours or less. 10. No feature branch lasts longer than a couple of hours. 11. TDD and refactor mercilessly. Make changes easy. 12. Make it hot: Any changes that has made it into main may be deployed 30 minutes after you commit, when you're on lunch. Now code-hygiene, care and practices really starts to matter. 13. Start doing some changes without a feature branch/PR. Evaluate, practice, habit. 14. Remove organizational/cultural issues: The entire team succeeds or fails together. As long as everything is driven by "individual tasks" (and associated rewards), stupid "sprint commitments", and "done" that means - "I coded it, it's done, right? Then a separate QA-department is trying to inspect quality in after the fact and it's someone elses problem after that" - nothing you do will matter. Culture eats strategy and intentions for breakfast. 15. Expect things to go wrong, learn to deal with it and improve. It takes years for a team to get good at CI/TBD. It takes even more years for an organization to get good at CD.
    3
  21. 3
  22. 3
  23. 3
  24. 3
  25. 3
  26. 3
  27. 3
  28. 3
  29. In part. Continuous Integration is a human practice where it is expected that the developers pulls the latest changes and run the unit tests, lint, checkstyle, findbugs, (and component integration tests) before pushing. Those same checks are then run at push, which is called a "commit build" and should give you a high confidence that everything works. In CD there are other kinds of tests and checks downstream that takes different aspects of the entire system into account. As I understand it, the embargo shown here is seldom used. Again, CI is a human practice and a social contract: if the build is not fixed within 10 minutes, anyone can revert the commit that broke it. The key here is to be disciplined and don't break things all the time, and the few times it breaks we do whatever we can to get back to a working state. Shit happens, learn from it and move on. Part of the issue with feature branches is that it optimizes for individual developers working alone in their corner with headphones on. This is a bad thing. Sure, you can use short-lived feature branches if you must; where (in my view) short means a couple of hours. But if most only live 30 minutes to a few hours what's the point of branching in the first place? Look, I'm just an opinionated a-hole that's tired of arguing with people and also thinks that part of the popularity around FB/PR is an amazing feat of social engineering by the tool-vendors that has even the oil and tobacco companies in awe. So I'm just going to give up and drop this Twitter thread by Jez Humble: https://twitter.com/jezhumble/status/982988370942025728
    3
  30. 3
  31. 3
  32. 3
  33. 3
  34. 3
  35. 2
  36. 2
  37. 2
  38. 2
  39. 2
  40. 2
  41. 2
  42. 2
  43. 2
  44. 2
  45. 2
  46. 2
  47. First of all, don't get hung up on the "18 months" thing. That was just an example how bad it can get, i.e a slippery-slope scenario. The first thing (that is painfully obvious in this comment section) is that apparently everyone are working alone, everyone is focusing on finishing "their" tasks, their changes. This is so wrong it hurts. The second worst scenario you can have in an IT organization is a bunch of developers working alone in their corners with headphone on, thinking they are a team. The absolute worst scenario you can have is a lead/manager assigning tasks to individual developers and keeping some kind of tabs/score and handing out gold stars like in first grade. Combining these two scenarios will just create a culture where Bob won't give a sh*t if Anna is in trouble and need help, because he "got to get his tasks done on time or the manager will get angry at him". And then if there is some kind of (merge) conflict it will escalate into a personal conflict. Why not also start paying testers for the number of bugs found, and developers for the number of lines of code written? Wait, we tired that in the 80's - disaster! As a developer you are supposed to refactor. If you are making changes to a module anyway and spot something that's a bit off, just fix it, now! It's there, right in-front of you, you know how it should be, pair up and just do it. This is a really good habit. Look up the term "refactor mercilessly". Regarding OSS: Feature branching and pull-requests were invented for and by the open source community. A situation where you have maybe 1000s of untrusted contributers and just a few trusted committers. This is where FB/PR shines. If you do not find yourself in that situation, there are better ways, like TBD and CI.
    2
  48. 2
  49. 2
  50. 2
  51. 2
  52. 2
  53. 2
  54. What you just described is an argument *for* CI. CIs main purpose is to *expose* all these faults (code, technical, culture) and by extension: XP's and agile's purpose is to expose all the *systemic* issues in the organization and give everyone a health dose of reality. If it's broken all the time and some project manager still thinks "it will be delivered on time, work properly and be of good quality" and developers just keep adding more code to a broken system, someone is lying to themselves. Version control is not your personal backup-system, it's an auditable, versioned, *publication* mechanism. As a developer your job is not to just implement some tasks, push to git when you go home for the day and the rest is "someone else's problem" or "other developers fault". Either the entire team wins, or the entire team fails. 1. You make sure to merge other peoples changes from master to your local clone many times per day, and run the build, unit-tests, linting, and functional tests *before* you push to master. That way you know if there is a conflict before you push. This is the prime directive of CI - check your sh*t before you push. And if it still breaks on the build servers, stop working, drop everything and fix it! Did it break because you made a change or did someone else make a change that conflicted with yours? Doesn't matter, say "huh, that's odd?" and then talk to your team members and fix it. 2. Someone deleted a database record/table/whatever in a test-environment and broke something? Well, then everyone stops, figure out what and why it happened and then *talk* and solve the real problem (people, process and culture), not just the symptoms and complaining "Aaah, it's broken again!!!". 3. "Algorithm works here but not there"? Not sure how that could happen. But here is a tip: build it **once**, deploy the same code/binary/package in the same way, by the same mechanism, to every environment, every time, and 95% of all the "works here, but not there problems" goes away. 4. Acceptance tests break but you haven't bothered to run it? How do I even respond to that!? "If it hurts, do it more, and bring the pain forward." - Jez and Dave
    2
  55. 2
  56. ​ @appuser  Not sure how to answer that directly... I can say this: Pair programming is not - two - people - programming. Pair programming is "two people programming". It's collaborative, not cooperative. It's the difference between having fun with your friends and having fun with your spouse. That doesn't mean everyone spend all their time pairing. It's like a relationship, we spend a lot of time "collaborating", but it's occasionally punctuated with times of alone time and deep focus. You'll probably end up divorced if you insist that your spouse spend all their time with you and vice-versa. It's like everything, it takes time to learn and get comfortable with. If you have never pair programmed and spent your career "sitting alone in your corner, with your headphones on, typing code" it's not easy, and quite frankly you've been mismanaging your job. Deep collaboration and high bandwidth social interaction is a very important part of SWE. Unfortunately too many of us thought that working in software would be the same as when we got into it as a hobby. We were either lied to, or lied to ourselves. We are not getting paid to do our hobby of just writing code and it's easy to be disenfranchised when it turns our to be different than we thought. And thus we tend to invent all these handoffs and roles where we push the uncomfortable things away... we add layer after layer and build walls and "specialist groups", all so that we won't have to change and do that scary thing we don't really want to do... And that is what I reacted to; I interpreted it as if you wanted to add yet another specialist group to avoid changing/keep the status quo. I may have overreacted... 😕
    2
  57. 2
  58. 2
  59. 2
  60. 2
  61. 2
  62. 2
  63. Open Source is a different context. Linus created Git to slow down changes *because* he's the author of the biggest open source project there is - The Linux OS kernel. FB/PR was built *for* open source, where you have 1000's of unknown contributors all over the world and a few trusted committers. Pretty sure Dave said [paraphrased] "async, pre-merge, blocking review using pull requests in your *team and organization* is where the problem lies." And I don't buy the "introvert" argument for one damn second. There are two sides to that argument. 1. It's used as an excuse so that developers can sit alone in their corner, with their headphones on, writing code in isolation, getting paid to do their hobby. Probably why FB/PR has become so popular... It avoids interactions. It defers integration. 2. For 50 years the industry has been built on the notion of "the lonely geek" and the "superhero programmer"; attracting a certain kind of personality. If the situation is that "people can't collaborate with other humans" we probably did that to ourselves and it's time to stop digging the hole deeper. Programming is fundamentally a social activity and too many of us thought that choosing it as career would mean to continue what we did when we learned on late evenings in our rooms when we grew up. It's still a job and we have to do things that's uncomfortable. We need to become much better of getting out of our comfort zones. That doesn't mean we need to sit in each others laps all the time. Most of the time we should pair and collaborate in small groups, punctuated with moments of deep focus work alone or pair. It's not all or nothing. PS: I'm an outgoing introvert.
    2
  64. 2
  65. 2
  66. 2
  67. 2
  68. 2
  69. 2
  70. ​ @OzoneGrif  Why is it unacceptable? I don't mean to sound antagonistic but you need to think outside the box of release-trains, Gantt charts, milestone-driven release schedules, and manual test-and-stabilization phases. First of all, all code shall be tested whether they are "feature complete or not", and then you have an evolution: 1. Early in development the features may be excluded/included from the build by using build profiles. This allows local development and testing as the team fleshes out the basics of the feature. 2. Later on features may be included but be disabled by default and enabled by a deployment flag in different environments. Great for feedback and early testing. See "branch-by-abstraction pattern" for one example of implementation details. 3. Once we reach the "this is a nice feature, polish it"-stage we may choose to convert the flag to a runtime property or keep it as a deployment flag. Context and technology matters. 4. When we finally are ready to release the feature to the world we can turn it into a user preference (Opt-in/beta users for the new feature), or even using Geo-location or target groups of who will see it. 5. This allows the business to then decide if the feature shall be available for all users and we can remove all the flags and gunk around it. Or we may decide that it's an "enterprise feature" and customers have to pay for the feature to be enabled. The point is - you can have a lot of unfinished changes in-flight, in a single repo/branch and still always be able to deploy a hotfix. This is kind of how facebook implemented their chat-system. It was running (by bots in your browser) in production, in secret, behind users timelines, and only facebook employees could actually use it. It had been running in production for over six months before normal users could access it and then they incrementally rolled it out to users - without needing to build/deploy/release a special version.
    2
  71. 2
  72. 2
  73. 2
  74. 2
  75. I have no answer shorter than an entire book on this... The problem is if team members are working on multiple projects at the same time then you don't actually have a team. That's like having a football team playing 5 different matches at the same time. This is a symptom of something being wrong with how things are prioritized and/or how the organization is structured... The job of a senior/lead is not to gatekeep, to check everyone's work and approve of it. A senior can't behave like a curling/helicopter parent and protect juniors from themselves all the time. That tends to hold back peoples learning and growth, and also teaching people to not trust themselves. You need to find a way of working where everyone can contribute, learn and make mistakes, without a senior handholding them or taking the company down in the process. I don't care what that is, as long as it's a minimal measure and not someone gatekeeping everything (the seniors might as well do all the work by themself in that case). You should be able to find a way of working where in the end "everyone" would make similar (or better) decisions, even when the seniors aren't in the room. After all, the job of a senior engineer is to create more senior engineers. There are no "do this"-answer except "get good at pair and group programming" and build "defenses" into the system of work so that the blast radius of mistakes is as small as possible. Dave has another video here "A Guide To Managing Technical Teams" and Dan North has a video from "Goto conference" called "Beyond developer", check them out and show them to your team next time you have a "tech friday" get-together.
    2
  76. 2
  77. 2
  78. 2
  79. 2
  80. 1
  81. 1
  82. 1
  83. 1
  84. 1
  85. 1
  86. 1
  87. Wall of text, partially off-topic warning! Let's take this from the start - releases In the olden days we used to have something called RTM (release to manufacturing) - basically meaning (after months of testing and polishing) sending the software to a factory that put it on floppies, CD-ROMs, etc. and shipped it out to stores in pretty boxes. There was a really high cost of delivering and patching software back then. Then came tools like Maven that took the old concept of "cutting a release" and made it mean "make a final (re)build and stamp a version number and publish it for deployment". Later CI/CD/DevOps came into the picture and things started to change; we came up with terms like "separate deployment from release". What is meant by that is that deployment comes before release. Enabling new functionality or changing old becomes some kind of configuration change instead of a "all hand on deck deployment 3 AM" thing. This also enables A/B-testing, user opt-in and deploying many many small changes all the time - thus reducing the blast-radius if something goes wrong as well as knowing that every change actually works in real life. This doesn't mean that every change gets a deployment, it's just that deployments becomes a choice by need instead of a planned date/deadline. How does it (ideally) works with CI/CD? With CI/CD we instead try to subscribe to the (impossible) ideal of Toyota "one-piece flow". Instead of keeping track of the state of the software by using branches/merges (with all the management overhead) and thinking in terms of "master represents production" or "let's build a release and a release branch" (a bit like the previously mentioned "cutting a release") - we commit to main, we build it once , we record the version/tag/commit/buildnumber/digest of that build; we test and validate it, and then pass that immutable piece from environment to environment, from validation to deployment and finally release. It's a survival of the fittest scenario to try to prove that a build does not meet the criteria for deployment. Extrapolating and deeper context As with everything there are contexts and compromises. But if we default to use branches for change control, separate departments for frontend, backend and testing, huge ops-teams getting software thrown over the wall from developers (we made a release, your turn) because it feels easier and it worked 20 year ago we are not making any progress or improvements. According to some of the "old IT/tech people" the amount of programmers doubles every 5 years. About 10 years ago everyone went nuts with FB/PR/GitFlow. So we can extrapolate that 75% of all programmers have never done anything but, and so have no idea about Continuous Integration. I'm really passionate about this because I see the same thing repeating in every org I've been in. As long as our thinking doesn't change it doesn't matter how much technology, tools, languages, frameworks and processes we throw at software development - nothing changes.
    1
  88. 1
  89. 1
  90. This assumes that the only work happening is the feature, that we would know where conflicts are likely to happen. The thing about TBD and CI is that it has really nothing to do with "optimal isolation of features and workflow for individual developers to avoid conflicts". It is the opposite. There is this thing/strategy called "artificial constraints" which basically sets out guardrails and signs to push peoples behavior in a certain direction. This can be used both in a limiting sense (like feature branching which generally arises due to some kind of culture/trust issues and some need for illusion of control), but it can also be used to change behavior and level-up the entire organisation (like when your personal trainer pushes you and says "only 3 more minutes to go" even though "but it was only 3 more minutes - 15 minutes ago!!!"). Imagine the following scenario: You are working on some feature in your branch, you get a bit stuck, it won't work and you can't figure out why. You start to follow the code-path, you rip your hair and after two hours you figure that there is a function elsewhere that your code is calling and your change causes this function to be called twice. It is named getTicket(username) and it obviously gives you a ticket, right, RIGHT? What you didn't know is that this function actually creates a new ticket every time and that made you waste 2 hours. Now the question becomes - what do you do? Do you just fix your feature code based on this new understanding, commit, create a PR, move on to the next feature? What if you instead fixed the name of the function to its proper name createNewTicket() and also moved it to a different file/class/module because you realized it was in the wrong place. Or do you think "not in scope, feature first, don't touch it, too scary"? Think about it, you just spent 2 hours staring at this thing before you figured out that you were misled by the function name. You could fix it now while the understanding is fresh in your head and save everyone 2 hours in the future, every time they use the function. What if everyone did that all the time; made some little change that improved the life of everyone, forever? How much better would everyone and everything have become after a year, after three years? Now for the kicker; if there is a whole bunch of feature branches and pull requests waiting to get merged and people are doing this opportunistic refactoring that continuously improves the code base for everyone. How long does it takes before people starts getting angry due to merge conflicts and then the culture becomes "Don't refactor! Don't improve!". Feature Branching, when used dogmatically (often due to culture and trust issues) without understanding the long term impact and taking a more holistic systemic view on quality and culture, will actually inhibit learning . There is a difference between learning and being taught. And that is the nuance that is missed when all everyone is talking about is "optimal isolation of features and workflow for individual developers".
    1
  91. 1
  92. 1
  93. A pipeline does not replace the steps and tasks in a build script (npm, gulp, gradle, maven, etc). This is a common mistake I see, where teams replaces everything they had in their scripts with a pipeline YAML that can only run on some build management system. When practicing CI you should be able to run the majority of the build steps including unit test, some component and functional testing locally. Whole system acceptance tests is difficult and often too slow to run locally. It also serves as feedback; if it is difficult to run, build, test, lint, you probably need to look into the structure and design of both tests and code. If it is very hard or slow to build/test locally you may need to look into the the technology choices made (like frameworks, etc). It is an optimization technique where you should be able to compile, package and run 10000s of tests locally in minutes. Enough that it gives the developers a high degree of confidence that it will work before pushing. The build management system will of course run the commit build as well, plus a bunch of slow wider system tests, performance, etc. This also has the added benefit that if GitHub is down (like it is now as I write this) you can have a "break glass" process and build an emergency patch on a (monitored) local computer and push that to production. While the build system runs the commit build you are not allowed to go away, lunch, or home. If it breaks you have 10 minutes to fix it or revert the change. If it's still broken the team swarm around the problem and get it back to green.
    1
  94. 1
  95. 1
  96. 1
  97. 1
  98. 1
  99. 1
  100. 1
  101. 1
  102. 1
  103. Not sure if I understand your question correctly. I will assume that you are talking about how downstream stages/jobs would not having the code constantly changing under them. This kind of gets to the core of how developers tend to misunderstand version control. Version control is not a file-server and a branch is not a directory . Version control should be viewed as a versioned acyclic graph database. This mean one cannot really "build a branch" or "deploy a branch". One would in most cases produce a build artifact (package, zip, pip, npm, etc) from a specific commit and place it in a binary repository of some kind. But even in those other cases when a deployment would mean that we are simply "copying a branch" to a webserver we would never copy HEAD , we always copy the commit/version/tag we have tested even if there are 100 new commits in trunk. This is probably another reason why people get hung up on "we must use feature branches because master must be pristine and represent production" and then fights breaks out because we talk past each other (which is evident in this comment section). For each job in the pipeline we have the following information provided to downstream jobs: - repo - branch - commit - generated build number and version - a copy of the workspace with produced artifacts OR a reference to an artifact repository - other metadata as needed So to answer your question (as I understood it); even if trunk is constantly changing we use the same "version" we started with in all downstream jobs . The other changes that gets queued up are separate instances/runs of the entire pipeline. When it comes to dependencies between projects/repos/components it always gets a bit messy, but it's solvable. For example, a downstream project could have a script that updates the list of dependencies (like a package.json lock-file) based on the properties passed down. I.e. "as project B gets triggered it detects it got triggered because dependency A has a new build/version, try to build B using the new version of A and if the build is successful commit the updated lock-file and save the build, and so on". In a general sense, as people commit their changes to trunk a new "commit-build" is kicked off and if it is successful then the downstream jobs get triggered in turn. But what if the downstream job takes one hour and people are committing to trunk 10 times per hour? The long-running job still only runs twice - triggered once by the first commit and then again after the 10th commit - i.e it gets batched up. Every build becomes a "release candidate" that may make it into production at a later stage. There are exceptions of course depending on context. Summary: Essentially we can say that the "unit of work" that flows through the pipeline is "a commit" and not "a branch" (remember, its not a directory).
    1
  104. 1
  105. 1
  106. 1
  107. 1
  108. Never really had that problem myself. But then I have always been vocal when I see conflicts and hero-culture and try to break out of it as soon as I see the signs. There is a saying in the DevOps world - "a bug, is a bug, is a bug". Meaning that bad code, bad process, bad security, bad compliance, low trust, bad logging, metrics and audit are all bugs. But we tend to pretend they are someone else's problem because "I'm just trying to get my task done". As long as everyone has the mindset that it's a contest, that developers shall sit alone in their corners with their headphones on, typing code all day. Instead of working as a team (across roles), have good practices, a good modular design (so that there is less chance of stepping on each other), working in pairs and sometimes entire groups (see mob programming) we tend to default to defensive behaviour and then there will be friction, frustration and no joy. And then we try to smooth over the cultural issues with processes, Gitflow and feature branches and silos and handoffs with 27 new roles. A team should be measured based on result and outcomes - not individual contributions. My point? Any mindset or culture that focuses on individual "performance" (stack ranking, ego, loudest-guy-opinion, "winners-and-losers") and cop-outs like "but I'm an introvert" is A BUG! The issue with seeing ourselves as heroic loners is indeed the biggest issue in SWE. Since in your scenario both of you apparently were working in related parts of the codebase - I think you should have taken a step back, sat down with each other, talk, plan, pair-program and collaborate on both of the changes instead if sitting there frustrated that "the other guy screwed up my changes again and now I'm getting behind and losing the scrum story-point race". Maybe I'm taking this over the top, but only because I've seen it happen to other teams so many times. Learned helplessness is the worst place to be, because it absolutely drains all energy and joy of going to work and life in general.
    1
  109. 1
  110. ​ @aprilmintacpineda2713  It is not your job as a tech lead to decide what should be worked on, and it is not your job to decide how the work should be done. It is your job to make sure that the team knows how to do their job properly, to coach them, to share your knowledge and thinking so that they can make good decisions without you in the room. Regarding your point about "why you haven't seen TBD in the wild?" is because, as I have stated before, it has become the silver bullet solution to everything. And software people, devs and managers alike, tend to jump on every bandwagon that will save them. We tend to forget what came before and going around in this 10 year cycle where everything old is new again. Then every job ad is filled with all these things and no-one knows why but we got to have "full stack engineers" and "15 years of Angular experience" and "working with GitFlow". Unfortunately it is all based on local optimization instead of looking at the whole system of work. Like putting on a band-aid instead of doing the hard work of actually changing how we work and think. This is further exacerbated when the incentives, trust and power structures does not change in any meaningful way, and we just end up hiding the real issues behind processes in some kind of "change theater". I have no problem with branches per se - when they serve a purpose. When they are used as an excuse to "be sloppy" or a "mechanism to avoid trusting people", or just implemented by rote - then they are just harmful as they often tend to hide systemic issues within the organization. The example I gave was NOT a description of my situation. It was a projection of what I could see happening at your place based on your original reply. So I'll ask the same question back - if you feel the need to make decisions for the team, to instruct them how and if to do things, to control when and what they refactor, maybe the real problem is that you don't trust the team and should ask yourself why you hired them in the first place. If trusting the team to make the right decisions and do a good job without you looking over their shoulders sounds scary, you have to ask yourself if it's the team that is the real problem. Why put refactoring tasks in a ticketing system? The only time I would do that is if it's something more general like "make order processing simpler in the order module" and then every time someone is in that module, or has some time over they help to move us closer to that goal. Refactoring is not a task/shore, it's a means to an end. And if everyone did that all the time, everything would get better and better.
    1
  111. 1
  112. 1
  113. 1
  114. 1
  115. 1
  116. 1
  117. 1
  118. 1
  119. 1
  120. 1
  121. I assume that you mean to work by a pre-defined release plan where you have Gantt-chart like planning that "next month it's A, B", the month after that it's C and D, and by summer it will be E and F? In CI/TBD/CD we do things differently. We associate the readiness of the a release with a version instead of associate it with where it lives in version control. We also try to separate "code fixes, improvements, etc" from "feature releases", meaning that we can get any change out at any time, in hours, irregardless of plan, without hot-fix branches and special processes. We then promote versions between environments. Having separate testing teams, hand-offs, approvals, etc is pure death to CI/CD. Even if the case is that we plan to release features at specific intervals we can handle that using feature flags at multiple levels. In CI/TBD/CD we don't treat a release as a deployment in the same way. Instead deployments comes *before* release, meaning that unfinished features are deployed, but disabled/hidden until ready. This is how Facebook release their chat way back in pre-historic times. They had "javascript bots" running behind the scenes on a subset of users timelines; testing, trying, measuring and logging stability and security. Later on it was rolled out to a subset of users for trial, that subset then grew and after a few iterations (and performance fixes) it was rolled out to 1 billion users. Note that they did not do a "all hands on deck and deploy the universe and hope it can handle 1 billion users" on release day - it had already been running in production for over 6 months.
    1
  122. 1
  123. It's more complicated than that. Humans tend to gravitate towards easy solutions to complex problems, while the best solutions tend to be counter-intuitive. That "lure of easy" often leads to local optimization, isolation and tribalism. Sometimes it goes so far that the system becomes optimized for developers sitting alone in a corner, with headphones, typing code and occasionally popping their heads up exclaiming "I'm done, sent it to QA" and then keep typing. Meanwhile managers starts measuring "performance" based on number of tickets closed, PRs merged, bugs found, story points delivered, etc. This is a death spiral where the best, most senior people leaves and to compensate management hires more people, and the only way to get any order or structure is to impose even more rules, process and managers. Because so many of us grew up with programming as a hobby, often alone, late at night, we also never learned how to collaborate. We mistake "cooperate by divide and conquer" for collaboration and when we then end up in an organization where we have to interact with other fickle people all the time we build walls (branches, functional teams, layers of management, rules and processes) to protect ourselves from those interactions. It is similar to the reasons why so many developers are "afraid" of TDD, pair programming, etc. We have to *change and unlearn* old behaviours and accept that we will be crap and slow at the new thing for a while and that is hard to get past. My point is that XP/TBD/CI/CD is hard indeed. But instead of making the case for isolation by branch-driven development, PR/Jira-driven communication, etc. as the norm; what if people actually learned code hygiene, single-branch development, TDD, pair programming, etc., and got good at it first, and then turned to branches and more complex processes as the exceptions, when needed, based on context, instead of as the default strategy "because it's easier"? We also have to take into account that we have 2-3 generations of programmers that has grown up with GitHub, FB/PR, lone programmer, etc and has never seen or tried TBD/CI. Where it has always been that way and branches has always represented environments and development has always been individual programmers communicating using tickets. Fear, cognitive biases and personal incredulity makes these opposing practices feel offensive, wrong and unprofessional.
    1
  124. 1
  125. 1
  126. 1
  127. 1
  128. 1
  129. Yes. Three things. Assumption: We are talking about software that is run as a service, provided by your company (user installed software is a different beast). 1. There is no such thing as a major refactor that's broken for days. No wonder managers get heartburn when developers mentions the word "refactor", and then the XP people comes along and say "refactor mercilessly" and the managers dies of heart attacks. 2. When doing a big re-write in a messy, badly tested codebase a common solution is to implement the new version of the module parallel with the old module directly on master branch. This is called "branch by abstraction" and has nothing to do with version control branches. Perhaps we put the code under a new namespace/package, and then have a configuration flag so that the new code only runs locally when developing. Once the new module is "complete" we can expose the configuration flag so that the build and test environments can verify both implementations. Further, when we later deploy to production this flag can be used to turn on/off the new implementation at will. If things go badly - just turn it off and the old code is running instead. When the new implementation is deemed "good" it should become the default; we remove the configuration flags, the old implementation and possibly any other "complications" left in the code. This is properly managing risk by providing an escape hatch without needing to revert, rebuild, retest, redeploy anything. 3. Another way to do it is of course to make the changes in small increments and use automated tests and verification every step of the way. Jez stated it wonderfully: "...we have to work in very small batches. This is antithetical to the way lots of developers like to work: sitting off on their own going down a coding rabbit hole for days before re-emerging. The elevation of "flow" (by which I mean individual flow, not lean/team flow, which is actually inhibited by this behavior.) [is much at fault here]. Trunk-based development is about putting the needs of the team above the needs of individual. The premise of CI and trunk-based development is that coding is fundamentally a social, team activity. This presents a challenge to the mythos of the developer-as-hero which is still pervasive in our industry." https://twitter.com/jezhumble/status/982988370942025728
    1
  130. 1
  131. 1
  132. 1
  133. 1
  134. 1
  135. 1
  136. ​ @prdoyle  Wall of text incoming - duck and cover! 1. Sure, but it is not integrated until it's ON main. 2. Even if you rebase your branch, you still only check integration with what has made it into main this far. Everything else that is not on main is an unknown. As an example: If everyone "merge into main" at the end of the day or end of sprint, you won't know if everything actually integrates until that time. That is way to intermittent and is similar to old school waterfall "integrate and test at the end", although at least it's a more frequent than once per year. If everyone merges their code into main several times per day - fine - but what do you need FB/PR for in the first place if it only lasts a couple of hours anyway? Seems like a lot of ceremony. I have actually been there, twice, kind of - in a highly compliant industry. We had armies of testers, reviewers, configuration management people, merge bosses, process and branches, and yet we had very expensive production issues all the time. Then I took over as tech lead for the most certification-critical components. The only changes we made was that we skipped all the ceremony/merges/handoffs and started doing proper XP/CI/TBD and our response time became 10x better and our production issues went down by 2 orders of magnitude. That alone saved the company $2M per year. A few years later a bunch of managers decided that "everyone must do FB/PR because we have to be compliant (BS, yadda, blah) and we read on the internet that that is everyone else is doing so we should too" and it became dogma and enforced by people not doing the actual work. After that we had slowed down and were right back in the tank and half of us had left within a year. *We didn't need FB/PR - we were doing better without them already!* Because so many are used to treat version control as a kind of personal junk-drawer where we throw things into a branch, fiddling around for a while, have it being broken for hours/days, flaky and unstable and then pick up the pieces into a whole at the end, then squash merge and PR; they get stuck in that cycle. 1. This is often a sign of bad design or issues with the culture. 2. There is a world of difference between "half baked", "incomplete" and "messy crap" - in XP/CI the software should still always work properly. 3. Code reviews are primarily there for learning and feedback. Async blocking reviews actually slows the organization down and have questionable effect on the quality. And even so not all changes requires review and not all reviews have to be blocking - see Martin Fowlers 3 types of reviews "ship-show-ask". FB/PR proponents are stuck 100% on "ask". You can always refactor and improve things after the fact, after it's on main, and even after it's gone live. Something people seem terrified of.
    1
  137. 1
  138. 1
  139. 1
  140. 1
  141. 1
  142. 1
  143. 1
  144. 1
  145. 1
  146. 1
  147. ​ @primevalpursuits  Ok. I understand. In the olden days we used to have something called RTM (release to manufacturing) - basically meaning (after months of testing and polishing) sending the software to a factory that put is on floppies, CD-ROMs, etc. and shipped it out to stores in pretty boxes. There was a really high cost of delivering and patching software back then. Then came tools like Maven that took the old concept of "cutting a release" and made it mean "make a final (re)build and stamp a version number and publish it for deployment". This kind of clashes with the notion of a release in DevOps circles in which a release comes after a deployment. What we usually try to do in CI/CD is to stamp *every build* (deployable artifact) that comes out of the commit build (on push to main) with a unique version number (build number, etc) and make it immutable. We then move that reference through the pipeline. Preferably we should treat deployment scripts, and application configuration the same if possible. There is an article on Hackernoon: "A Guide to Git with Trunk Based Development" that has some nice solutions. It does require us to invent some kind of manifest and control repo and tooling to handle it. If you're using Kubernetes then Flux CD is basically using the same solution, but based on some kind of GitOps branching pattern. Now, I'm not using K8S (we're using Fargate and Terraform+GitHub Actions) so I can't really speak for Flux. I recommend to read "Investments Unlimited: A novel about DevOps..." - it's written in the same form as The Goal and The Phoenix Project but is based around a financial institution and how they get a year to fix things or the government are coming with the hammer. Now they chose FB/PR (which I dislike), and many other solutions they bring up are great.
    1
  148. 1
  149. 1
  150. 1
  151. 1
  152. 1
  153. ​ @vyli1  I have a question. What does it matter that trunk is broken just once-in-a-while (meaning seldom)? If it's broken so that unit tests, functional tests or acceptance tests fails it will be discovered (and fixed) quickly. If it's broken in such a way that it's only found during manual testing, you would probably have that happen anyway, and sometimes it's broken without us knowing - we call that a production bug. There is this misunderstanding that "always releasable" means "mainline never broken, always pristine, represents production, etc". "Always" is not black and white! While we should strive to minimize the time mainline is broken (because it blocks everyone else) the goal is not to eradicate all mistakes (impossible). The purpose of CI, CD and TBD is fast feedback IF we broke something. It's okay if it was due to an honest mistake, if it was due to sloppiness then the team have some difficult learning to do. In both cases we have learned something we can act on. To para-quote Jez Humble: "Every build is a release candidate. The goal of the CI/CD pipeline is not to prove that it works, it is to prove that it does NOT work. If you can't prove that it doesn't work you should be able to deploy that version (if you choose to)." . As I have written elsewhere, you don't release a branch, you don't deploy a branch, you deploy a good known commit/version of your code. If the mainline is broken the same hour that we need to deploy to production - it doesn't matter - because we always use/deploy the latest known working commit/version. Version control is not a file server and a branch is not a directory, it is a versioned graph of snapshots in time so we can use whichever one we'd like.
    1
  154. By "Never" he means - don't branch for development purposes. There are still business-cases where we for example might want to support multiple versions of the software (for example if it is customer installed applications), but at the speed software moves/changes today we might just as well create a fork of the application and manually backport bugfixes. There is a reason that companies charges a lot of money for subscription licenses - maintaining old versions is expensive. To answer your question: Branch by abstraction and a feature toggle. That is; create a "variation" of the pages/auth/config/whatever and have a flag that can be turned on/off if the new auth system should be used or not. This way we can turn on the new auth in some test environments but have it off in production and we can test and perform audit/penetration tests until happy. We can even just have the auth flag turned on a subset of pages to begin with and expand from there. Later on we can remove the flag if we want so that the app/site always requires auth. In CI/TBD/CD we don't equate a release with merge and deployment in the traditional sense. Deployments comes *before* release, meaning that unfinished features are deployed, but disabled/hidden until ready. This is how Facebook released their chat way back in pre-historic times. They had "javascript bots" running behind the scenes on a subset of users timelines; testing, measuring and logging stability and security. Later on it was rolled out to a subset of users for trial, that subset then grew and after a few iterations (and performance fixes) it was rolled out to 1 billion users. Note that they did not do a "all hands on deck and merge and deploy the universe and hope it can securely handle 1 billion users" on release day - it had already been running in production for over 6 months.
    1
  155. 1
  156. 1
  157. 1
  158. 1
  159. I think there is this idea that we programmers only get one chance to implement something. Everything is a one-off "task/project" and then we move on to the next thing. Nothing is ever perfect, learn to accept that and then do something about it. Committing unperfect code, unperfect design, janky solutions (that nevertheless works) is actually OK. What it requires is that people actually have to learn to refactor, redesign, and do continuous improvement all the time. It's never perfect, it's never done, so get into the mindset of always fixing and improving things that looks "off". It is a good idea for the team to have reoccurring reviews of the current state of the software and always improve issues as they are found. The second problem is that every programmer thinks to believe that programming is a solemn activity. That is wrong; it's a social activity. In a company setting I see FB/PR as a symptom of missing teamwork and/or bad organizational leadership. If every developer wants to work alone and only intermittently "communicate" and "integrate" using PRs and "do their own stuff" you don't have a team. Don't you talk? And yes, we love to use dumb excuses like "but I'm an introvert", etc which is just BS to avoid having to talk with other people and getting paid doing our hobby. (I'm an introvert and I love pair programming and co-located teams and problem solving with a bunch of people in the same room. I hate parties and "social crap".) Like Jesus fing Christ. We programmers need to get over ourselves.
    1
  160. 1
  161. 1
  162. 1
  163. 1
  164. 1
  165. 1
  166. 1
  167. 1
  168. 1
  169. 1
  170. Copy-pasting my usual long rant regarding the belief that "we must have reviews to stop bad code from other bad programmers getting into the code base". I think there is this idea that we programmers only get one chance to implement something. Everything is a one-off "task/project" and then we move on to the next thing. Nothing is ever perfect, learn to accept that and then do something about it. Life is messy, sh*t happens, deal with it and move on. Committing unperfect code, unperfect design, janky solutions (that nevertheless works) is actually OK. What it requires is that people actually have to learn to refactor, redesign, and do continuous improvement *all* the time. It's never perfect, it's never done, so get into the mindset of always fixing and improving things that looks "off". It is a good idea for the team to have recurring reviews of the current state of the software and always improve issues as they are found. Keeping the code clean and working is more important than adding more features, or following a project plan or some rules put down by people not doing the job, all separated by 5 levels of management. The second problem is that every programmer appears to believe that programming is a solemn activity. That is wrong; it's a social activity. In a company setting I see FB/PR as a symptom of missing teamwork and/or bad organizational leadership. If every developer wants to work alone in their corner with headphones and only intermittently "communicate" and "integrate" using PRs and "do their own stuff" you do not have a team. Don't you talk? And yes, we love to use dumb excuses like "but I'm an introvert", etc which is just BS to avoid having to talk with other people while getting paid to do our hobby.
    1
  171. Not looking for an argument here, just wanting to point some things out. CI and TBD is designed to "solve" the problems you describe by exposing them instead of trying to work around them with band aids, processes, phases, hand-offs, etc. I would go so far as to say that the whole point/secret to (agile) software development has been forgotten in-place of process-itis and navel gazing. Just my opinion. Here is a great quote about agile "Agile's biggest strength lies not in solving problems, per se, but rather in exposing your buried problems and making them visible so you can deal with them. For a team switching to agile it can feel like things are getting worse, not better, but that’s often because they’re being made aware of pre-existing problems they didn’t know they had. It may not seem like it but this is actually a good thing." - Someone over 10 years ago. Or in the words of Jez Humble (co-author of continuous delivery) "If it hurts, do it more frequently, and bring the pain forward." Instead of getting bogged down in the thinking that "we can't" or "we must", what if you asked yourself a different question? "What would need to change for master/main to no longer be blocked/deployable for new features, fixes, etc; to be able to do any of these things as needed, when needed, and never be more than a few minutes from being able to deploy to production?" Problem-solving is more about asking the right questions than providing solutions. Adding complicated processes to hide the systemic issues is seldom the answer.
    1
  172. 1
  173. 1
  174. 1
  175. 1
  176. 1
  177. 1
  178. 1
  179. 1
  180. 1
  181. 1
  182. 1
  183. 1
  184. 1
  185. 1
  186. 1
  187. 1
  188. 1
  189. 1
  190. 1
  191. 1
  192. 1
  193. 1
  194. 1
  195. 1
  196. 1
  197. 1