What Is Proper Continuous Integration?
semaphoreci.com
semaphoreci.com
Yes.
> Continuous integration (CI) is confusing.
At core, no. Not really. See the 1st paragraph of https://en.wikipedia.org/wiki/Continuous_integration :
> In software engineering, continuous integration (CI) is the practice of merging all developer working copies to a shared mainline several times a day.
So the 2 words are defined as follows:
Continuous: at least several times a day.
Integration: merge changes to master.
It's not a tool: it's a practice, a workflow that builds, tests and tools can help you do safely.
Some of these "CI Server" tools also support "build and test the branches" which is useful but is not CI. This is a common mistake.
See also: https://trunkbaseddevelopment.com/
Your working copy is just an informal branch. Sticking it in a feature branch while your working on it is just convince.
But some people have the idea that the build and test of any branch, i.e the automated production of a binary that passes checks, is the "integration" itself. Look out for statements like "We do CI of branches on our CI server".
As software is a popularity contest industry driven by hype and career building blogposts, now everyone needs to do $buzzword so that they can play SEO with their resumes. This is a highly competitive market after all and you gotta put food on the table.
smug-faced guru enters the scene: "Oh it looks like you're not actually doing proper $buzzword. Shame on you for raising the hand!"
Now you're trapped. You either a) do what the guru says or b) remove $buzzword from your resume before you kiss your children goodbye and prepare for your new homeless life.
Well, my project misses the 10 minute target by a factor of four, but does include tests and have 670kloc of C++. I claim continuous in this context, thanks very much.
A lot can be done to reduce your typical or average build times (make everything data driven so you don't even have to rebuild the code!), but C++ makes it very hard to keep your worst-case build times in check. And I tend to be one of the guys tweaking and fixing things that invoke those worst-case build times. A simple example: Annotating logging macros to catch printf-style format string errors at build time instead of crashing at runtime if you're lucky.
Properly testing involves rebuilding most source files, on at least 3 build flavors to test against MSVC, Clang, and GCC...
I'd enjoy working on this :) It looks like a nice application of true build pipelines using GoCD. If you're interested to discuss this offline, do let me know.
We managed to get it down under about 15 minutes for the most common platform by using concatenation builds. It's much much faster to build half a dozen files than a thousand.
At a previous employer we were up to 1.25mloc by the time I left and we had a different solution: ccache+distcc distributing the build across a room full of computers. Few files took longer than 5m to build all by themselves, and the link phase also took about 5m.
(Splitting up large C++ projects that have grown organically is really hard. It requires re-architecting and commitment to spend time on this technical debt.)
I don't deny that can happen, but I have seen teams with build times that exceed 10 minutes that don't have issues. People aren't generally dumb, so they find a way to work that doesn't involve constantly sitting around waiting on the build.
I'm working with a weather model and it takes around 1 hour to build and test everything: We build against 2 super computers, 3 different compilers, 2 different architectures (CPU, GPU) and single and double precision. Building alone takes 30 minutes (more in some cases). For testing we reserve 1x node with 8 GPUs and 9 CPU cores on one machine and 2x nodes with 1 GPUs in a 30 minutes debug slot.
With a pull-request based workflow we are able to push to the master multiple times a day. 40 minutes might be achievable by massively revamping our build mechanism and getting jenkins to store gigabytes in build artifacts for each run. However, I do not think it is worth it, because changes can take multiple days, or in some rare cases months to implement. If people need to wait for an hour for their tests to validate that's not so bad.
And that was two years ago...
The original poster is a cofounder of Semaphore.
E.g. one of our own builds took longer than 10mins at some point. You just assume that it's a function of size of the code and it's normal to rise over time. So my goal is to share that idea & why I think it matters, and get feedback. :)
It would be perfect if one could somehow keep the build quick using tools. A hard limit on a build might not be the best way. If the test is taking Limit minus one millisecond, and I add one new test that takes one millisecond, I break the build. But the culprit was really commit yesterday that added a test that takes 9 minutes. The worst thing one can do in CI is somehow flag the build as "not good enough" and point the blame the wrong way.
A tool that treated test quality/perf like any other asset and fails builds based on time limits etc would be perfect. It's really hard to do that especially on shared CI servers because of fluctuating performance.
I'm really not trying to crap on your decisions. I just want to know the rationale behind it. There are projects where everything is written in house with 10K lines of code. There are behemoths with 500k+ LoC and numerous dependencies. How does this factor into the decision?
But if we have a rule of thumb, we can know when it's time to start thinking about optimizations.
Code size is certainly a factor but it doesn't have to imply constant time increase. Speaking from experience in web apps, optimization of setup (whatever needs to happen before first test runs) + more parallelism + thinking more about decoupling is usually the right answer.
The point of these discussions is mostly to help people avoid ending up with a single 500k+ LoC behemoth.
I'll typically just merge into master on GH, let the CI server take it from there and not bother checking the site manually when the build is complete, it's not necessary. Our QA and CI process handles that.
I consider it a major advantage (benefits far outweigh risk) that I can typically merge my ticket into master, close my laptop and head home.
I like to think "we'll get there".
I think one big reason why organizations don't integrate and deploy often is that people are afraid they will break something when they do this. Then you end up pushing this big and scary thing forward and forward. This of course does not take away any of the risks, but at least you need to close your eyes and wish for the best only once a month.
I've seen situations where people had Selenium tests for every possible validation error on a form. A lower level test would have been sufficient to test all validation permutations and making sure they return the right error message, and then a single high level test can ensure that when an error message is returned it is properly rendered on the screen.
Overall unit tests should greatly outnumber UI/integration/acceptance tests. And when you catch a bug with Selenium test, replicate it at the right place with a unit test. Look up "test pyramid" if you're perhaps not familiar with it.
- Do not use sleep() for synchronisation - use explicit waits (e.g. wait until element is visible, then proceed immediately)
[1] https://www.martinfowler.com/articles/continuousIntegration....