[{"data":1,"prerenderedAt":798},["ShallowReactive",2],{"/en-us/blog/how-we-are-closing-the-gap-on-replicating-everything-in-gitlab-geo":3,"navigation-en-us":43,"banner-en-us":443,"footer-en-us":453,"blog-post-authors-en-us-Michael Kozono":695,"blog-related-posts-en-us-how-we-are-closing-the-gap-on-replicating-everything-in-gitlab-geo":709,"assessment-promotions-en-us":749,"next-steps-en-us":788},{"id":4,"title":5,"authorSlugs":6,"body":8,"categorySlug":9,"config":10,"content":14,"description":8,"extension":30,"isFeatured":12,"meta":31,"navigation":32,"path":33,"publishedDate":20,"seo":34,"stem":38,"tagSlugs":39,"__hash__":42},"blogPosts/en-us/blog/how-we-are-closing-the-gap-on-replicating-everything-in-gitlab-geo.yml","How We Are Closing The Gap On Replicating Everything In Gitlab Geo",[7],"michael-kozono",null,"unfiltered",{"slug":11,"featured":12,"template":13},"how-we-are-closing-the-gap-on-replicating-everything-in-gitlab-geo",false,"BlogPost",{"title":15,"description":16,"authors":17,"heroImage":19,"date":20,"body":21,"category":9,"tags":22},"How we are closing the gap on replicating *everything* in GitLab Geo","Developing an internal framework to enable other teams to add Geo support for their features",[18],"Michael Kozono","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669673/Blog/Hero%20Images/engineering.png","2021-04-29","\n\n{::options parse_block_html=\"true\" /}\n\n\n\nIn early 2020, it took 3.5 months of solid work to implement replication of a new data type in Geo. One year later, support can be added within a month -- including development and all required reviews. How did we do it? First, let me introduce you to Geo.\n\n## What is Geo?\n\n[GitLab Geo](https://about.gitlab.comhttps://docs.gitlab.com/ee/administration/geo/index.html) is the solution for widely distributed development teams and for providing a warm-standby as part of a disaster recovery strategy. Geo replicates your GitLab instance to one or more local, read-only instances.\n\n## What are data types?\n\n[GitLab Geo was released in June 2016 with GitLab 8.9](https://about.gitlab.com/releases/2016/06/22/gitlab-8-9-released/#gitlab-geo-new-product) with the ability to replicate project repositories to a read-only secondary GitLab site. Developers located near secondary sites could fetch project repositories as quickly as if they were near the primary.\n\nBut what about wiki repositories? What about LFS objects or CI job artifacts? In GitLab, each of these things is represented by different Ruby classes, database tables, and storage configurations. In Geo, we call these data types.\n\n## Is it really that hard to copy data?\n\nWhen we say a new data type is supported by Geo, this is what we mean:\n\n* Backfill existing data to Geo secondary sites\n* As fast as possible, replicate new or updated data to Geo secondary sites\n* As fast as possible, replicate deletions to Geo secondary sites\n* Retry replication if it fails, for example due to a transient network failure\n* Eventually recover missing or inconsistent data, for example if Sidekiq jobs are lost, or if infrastructure fails\n* Exclude data according to [selective sync settings](https://docs.gitlab.com/ee/administration/geo/replication/configuration.html#selective-synchronization) on each Geo secondary site\n* Exclude remote stored data unless [Allow this secondary node to replicate content on Object Storage](https://docs.gitlab.com/ee/administration/geo/replication/object_storage.html#enabling-gitlab-managed-object-storage-replication) is enabled on a Geo secondary site\n* Verify data integrity against the primary data, after replication\n* Re-verify data integrity at regular intervals\n* Report metrics to Prometheus\n* Report metrics in the Admin UI\n* View replication and verification status of any individual record in the Admin UI\n* Replication and verification job concurrency is configurable in Admin UI\n* Retry replication if data mismatch is detected ([coming soon to all data types using the framework](https://gitlab.com/gitlab-org/gitlab/-/issues/301244))\n* Allow manual re-replication and re-verification in the Admin UI ([coming soon to all data types using the framework](https://gitlab.com/gitlab-org/gitlab/-/issues/216100))\n* And more\n\n## How to iterate yourself into a problem\n\n[Iteration is a core value](https://handbook.gitlab.com/handbook/values/#iteration) at GitLab. In the case of Geo, by [GitLab 12.3](https://about.gitlab.com/releases/2019/09/22/gitlab-12-3-released/#geo-natively-supports-docker-registry-replication) we had added replication support for the most important data types, for example:\n\n* Project Git repositories\n* Project wiki Git repositories\n* Issue/MR/Epic attachments\n* LFS objects\n* CI job artifacts\n* Container/Docker registry\n\nAnd we had added a slew of features around these data types. But suddenly it was clear we had a problem. **We were falling behind in the race to replicate and verify all of GitLab's data.**\n\n* A new data type was being added by other teams, every few months. It was painful to prioritize 3 months of development time only to add replication to one data type. And even if we caught up, the latest features would always be unsupported by Geo for 3 months.\n* Automatic verification of Project and Wiki repositories was implemented, but adding it to a single data type was going to take 3 months.\n* Maintenance and other new features were increasing in effort due to the amount of code duplication.\n* Our event architecture needed too much boilerplate and overhead to add new events\n\n## How to iterate yourself out of a problem\n\nJust because it's possible to iterate yourself into a problem doesn't mean iteration failed you. Yes, ideally we would have seen this coming earlier. But consider that fast and small iteration has likely saved many hours of upfront work on features that have been quickly validated, and have since been changed or removed. It's also possible to [DRY up](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) code too soon into bad abstractions, which can be painful to tear apart.\n\nBut we reached a point where everyone agreed that the most efficient way forward required consolidating existing code.\n\n### Do the design work\n\n[Fabian](https://gitlab.com/fzimmer), our esteemed product manager, [proposed an epic](https://gitlab.com/groups/gitlab-org/-/epics/2161):\n\n> to build a new geo replication and verification framework with the explicit goal of enabling teams across GitLab to add new data types in a way that supports geo replication out of the box\n\nMost of the logic listed above in [Is it really that hard to copy data?](#is-it-really-that-hard-to-copy-data) is exactly the same for all data types. An internal framework could be used to significantly reduce duplication, which could deliver huge benefits:\n\n* Bugs in the framework only have to be fixed once, increasing reliability and maintainability.\n* New features could be added to the framework for all data types at once, increasing velocity and consistency.\n* Implementation details would be better hidden. Changes outside the framework become safer and easier.\n\nThe proposal went further than making it easy for *ourselves* to add Geo support to new data types. The goal was to make it easy for *non-Geo engineers* to do so. To achieve this goal, the framework must be easy to use, easy to understand, and well-documented. Besides the usual benefits of reducing duplication, this higher standard would help:\n\n* Minimize the effort to implement Geo support of new features, whether it's done by a Geo engineer or not.\n* Minimize lag time to add Geo support. If it's easy to do, and anyone can do it, then it's easy to prioritize.\n* Increase awareness in other teams that new features may require Geo support.\n* Influence the planning of new features. There are ways to make it more difficult to add Geo support. This is much easier to avoid during initial planning.\n\nAs a first step, Fabian [proposed creating a proof of concept of a framework](https://gitlab.com/gitlab-org/gitlab/-/issues/35540) leveraging lessons learned and incorporating improvements we already wanted to make to the existing architecture. The issue stimulated lots of design discussion in the team, as well as multiple POCs riffing off one another.\n\nThe biggest change was the introduction of a `Replicator` class which could be subclassed for every data type. The subclasses would contain the vast majority of the specifics to each data type.\n\nIn order to further reduce duplication, we also introduced the concept of a `Replicator strategy`. Most data types in GitLab could be categorized as blobs (simple files) or Git repositories. Within these categories, there was relatively little logic that needed to be specific to each data type. So we could encapsulate the logic specific to these categories in strategies.\n\nAnother significant decision was to make the event system more flexible and lightweight. We wanted to be able to quickly implement new kinds of events for a `Replicator`. We decided to do this without rewriting the entire event processing layer, by packaging and transmitting `Replicator` events within a single, generic event leveraging the existing heavyweight event system. We could then leave the old system behind, and after migrating all data types to the framework, we could easily replace it.\n\nOnce a vision is chosen, it can be difficult to see how to get there with small iterations. But there are often many ways to go about it.\n\n### Code\n\n#### High-level approach\n\nAt a high-level, we could have achieved our goal by taking two data types that were already supported, DRYing up their code, and refactoring toward the desired architecture. This is a proven, safe, and effective method.\n\nBut to me it felt more palatable overall to deliver customer value along the way, by adding support for a brand-new data type while developing the reusable framework. We already had practice implementing many data types, so there was little risk that we would, for example, take too long or use suboptimal abstractions. So we decided to do this with [Package registry](https://docs.gitlab.com/ee/user/packages/).\n\n#### Lay the foundation\n\nOur POCs already answered the biggest open questions about the shape of the architecture. The next step was to get enough of a skeleton merged, as quickly as possible, so that we could unlock further parallel work. To ensure correctness, we aimed to get something working end-to-end. We decided to implement \"replication of newly created Package files\". Much was left out, for example:\n\n* Replication of changes. (Most Blob types, including Package files, are immutable anyway)\n* Replication of deletes\n* Backfill of existing files\n* Verification was left out entirely from the scope of the first epic, since we already knew replication alone provides most of the value to users.\n\nSince the work still required many specific design decisions, we decided to [pair program](https://en.wikipedia.org/wiki/Pair_programming). [Gabriel Mazetto](https://gitlab.com/brodock) and I used [Zoom](https://zoom.us/) and [Visual Studio Live Share](https://visualstudio.microsoft.com/services/live-share/), which worked well for us, though there are many options available. [See a recording of our first call](https://www.youtube.com/watch?v=2XedCiU634s).\n\n[The spike](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23447) was merged and we thought ourselves safe under the feature flag. Looking back on this particular merge request, we did make a couple mistakes:\n\n1. An [autoloading bug was discovered](https://gitlab.com/gitlab-org/gitlab/-/issues/202044). The merge request was reverted, fixed, and remerged. Thanks to [CI](https://docs.gitlab.com/ee/ci/) and end-to-end QA tests using actual builds, the impact was limited.\n1. The size of the spike was unnecessarily large and difficult to review for a single merge request. As it grew, we should have used it as a \"reference\" merge request from which we could break out smaller merge requests. Since then, GitLab policies have further emphasized [smaller iterations](https://handbook.gitlab.com/handbook/product/product-principles/#iteration).\n\n#### Build on the foundation\n\nWith the skeleton of the framework in the main branch, we could implement multiple features without excessive conflicts or coordination. The feature flag was enabled on [GitLab's staging environment](https://handbook.gitlab.com/handbook/engineering/infrastructure/environments/staging-ref/), and each additional slice of functionality was tested as it was merged. And new issues for bugs and missing features were opened.\n\nWe built up the [developer documentation](https://docs.gitlab.com/ee/development/geo/framework.html) as we went along. In particular, we documented specific instructions to implement a new data type, aimed at developers with no prior knowledge of Geo. These instructions have since been moved to issue templates. For example, [this is the template for adding support to a new Git repository type](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Geo%20Replicate%20a%20new%20Git%20repository%20type.md). This caught a lot of would-be pain points for users of the framework.\n\nFinally, we released [Geo supports replicating GitLab Package Registries in GitLab 13.2](https://about.gitlab.com/releases/2020/07/22/gitlab-13-2-released/#geo-supports-replicating-gitlab-package-registries)!\n\n## Reaping the benefits\n\nFollowing the release of Geo support for Package Registries, we added support for many new data types in quick succession. Automatic verification was added to the framework. This recently culminated in a non-Geo engineer implementing replication *and verification* for a new data type, within one month!\n\n* In GitLab 13.5, [Geo replicates external merge request diffs and Terraform state files](https://about.gitlab.com/releases/2020/10/22/gitlab-13-5-released/#geo-replicates-external-merge-request-diffs-and-terraform-state-files). These were added by Geo engineers who had been less involved in building the framework. Many refinements to the framework, and especially to the documentation, came out of this.\n* In GitLab 13.7, [Geo supports replicating Versioned Snippets](https://about.gitlab.com/releases/2020/12/22/gitlab-13-7-released/#geo-supports-replicating-versioned-snippets). This was also added by a Geo engineer, and it was the first Git repository type in the framework, so it required more work than adding new Blob types.\n* In GitLab 13.10:\n  * [Geo supports replicating Group wikis](https://about.gitlab.com/releases/2021/03/22/gitlab-13-10-released/#geo-supports-replicating-group-wikis) was implemented by a non-Geo engineer.\n  * [Geo verifies replicated package files](https://about.gitlab.com/releases/2021/03/22/gitlab-13-10-released/#geo-verifies-replicated-package-files). This was a big new feature in the framework, adding automatic verification to any data type that can be checksummed.\n* GitLab 13.11:\n  * [Geo supports Pipeline Artifacts](https://about.gitlab.com/releases/2021/04/22/gitlab-13-11-released/#geo-supports-pipeline-artifacts) was implemented by a non-Geo engineer.\n  * [Geo verifies replicated Versioned Snippets](https://about.gitlab.com/releases/2021/04/22/gitlab-13-11-released/#geo-verifies-replicated-versioned-snippets).\n* GitLab 13.12:\n  * [An already supported data type, LFS objects, is migrated to the framework under feature flag](https://gitlab.com/gitlab-org/gitlab/-/issues/276696). Following this will be the migration of \"Uploads\" and \"CI Job artifacts\", and then **deleting thousands of lines of code**. This should improve both reliability and velocity, for example, verification will be added to these data types.\n\nIn aggregate:\n\n* In GitLab 12.9, we replicated ~56% of all data types (13 out of 23 in total) and verified ~22%.\n* In GitLab 13.11, we replicate ~86% of all data types (25 out of 29 in total) and verify ~45%.\n* **In the last year, GitLab released six new features that needed Geo support. We replicate 100% of those new features and verify ~57%.**\n\n## What did it cost?\n\nFor comparison, it took around 3.5 months to [implement replication of Design repositories](https://gitlab.com/groups/gitlab-org/-/epics/1633). It took around 6 months to [implement the framework for replication of Package files](https://gitlab.com/groups/gitlab-org/-/epics/2346). So the cost to produce the framework for replication was roughly 2.5 months of work.\n\nWe don't really have a comparable for [implementation of verification](https://gitlab.com/groups/gitlab-org/-/epics/1817), but it looked like it would take about 3 months to implement for a single data type, while it took about 4 months total to implement for Package files and simultaneously add to the framework, for a cost of about 1 month.\n\nGiven that new data types now take about 1 month to implement replication *and verification*, the work to produce the framework **paid for itself with the implementation of a single data type**. All the rest of the benefits and time saved are more icing on the cake.\n\nMy only regret is that we should have done it sooner. I intend to be more cognizant of this kind of opportunity in the future.\n\n## What to expect in the future\n\n* [Already supported data types will be migrated into the framework](https://gitlab.com/groups/gitlab-org/-/epics/3588)\n* New features will be added more quickly, for example, verification will be rolled out for all [Blob](https://gitlab.com/groups/gitlab-org/-/epics/5285) and [Git repository](https://gitlab.com/groups/gitlab-org/-/epics/5286) data types\n* Duplication will be further reduced, for example, by [leveraging Rails generators](https://gitlab.com/gitlab-org/gitlab/-/issues/326842)\n\nHuge thanks to everyone who contributed to closing the gap on replicating *everything* in Geo!\n",[23,24,25,26,27,28,29],"agile","collaboration","design","features","inside GitLab","remote work","workflow","yml",{},true,"/en-us/blog/how-we-are-closing-the-gap-on-replicating-everything-in-gitlab-geo",{"title":15,"description":16,"ogTitle":15,"ogDescription":16,"noIndex":12,"ogImage":19,"ogUrl":35,"ogSiteName":36,"ogType":37,"canonicalUrls":35},"https://about.gitlab.com/blog/how-we-are-closing-the-gap-on-replicating-everything-in-gitlab-geo","https://about.gitlab.com","article","en-us/blog/how-we-are-closing-the-gap-on-replicating-everything-in-gitlab-geo",[23,24,25,26,40,41,29],"inside-gitlab","remote-work","1KtKvn-m2myf7nA2EvunzxBl-Hr0y5Fg9tdwAXXdqhA",{"data":44},{"logo":45,"freeTrial":50,"sales":55,"login":60,"items":65,"search":373,"minimal":404,"duo":423,"pricingDeployment":433},{"config":46},{"href":47,"dataGaName":48,"dataGaLocation":49},"/","gitlab logo","header",{"text":51,"config":52},"Get free trial",{"href":53,"dataGaName":54,"dataGaLocation":49},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":56,"config":57},"Talk to sales",{"href":58,"dataGaName":59,"dataGaLocation":49},"/sales/","sales",{"text":61,"config":62},"Sign in",{"href":63,"dataGaName":64,"dataGaLocation":49},"https://gitlab.com/users/sign_in/","sign in",[66,93,188,193,294,354],{"text":67,"config":68,"cards":70},"Platform",{"dataNavLevelOne":69},"platform",[71,77,85],{"title":67,"description":72,"link":73},"The intelligent orchestration platform for DevSecOps",{"text":74,"config":75},"Explore our Platform",{"href":76,"dataGaName":69,"dataGaLocation":49},"/platform/",{"title":78,"description":79,"link":80},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":81,"config":82},"Meet GitLab Duo",{"href":83,"dataGaName":84,"dataGaLocation":49},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":86,"description":87,"link":88},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":89,"config":90},"Learn more",{"href":91,"dataGaName":92,"dataGaLocation":49},"/why-gitlab/","why gitlab",{"text":94,"left":32,"config":95,"link":97,"lists":101,"footer":170},"Product",{"dataNavLevelOne":96},"solutions",{"text":98,"config":99},"View all Solutions",{"href":100,"dataGaName":96,"dataGaLocation":49},"/solutions/",[102,126,149],{"title":103,"description":104,"link":105,"items":110},"Automation","CI/CD and automation to accelerate deployment",{"config":106},{"icon":107,"href":108,"dataGaName":109,"dataGaLocation":49},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[111,115,118,122],{"text":112,"config":113},"CI/CD",{"href":114,"dataGaLocation":49,"dataGaName":112},"/solutions/continuous-integration/",{"text":78,"config":116},{"href":83,"dataGaLocation":49,"dataGaName":117},"gitlab duo agent platform - product menu",{"text":119,"config":120},"Source Code Management",{"href":121,"dataGaLocation":49,"dataGaName":119},"/solutions/source-code-management/",{"text":123,"config":124},"Automated Software Delivery",{"href":108,"dataGaLocation":49,"dataGaName":125},"Automated software delivery",{"title":127,"description":128,"link":129,"items":134},"Security","Deliver code faster without compromising security",{"config":130},{"href":131,"dataGaName":132,"dataGaLocation":49,"icon":133},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[135,139,144],{"text":136,"config":137},"Application Security Testing",{"href":131,"dataGaName":138,"dataGaLocation":49},"Application security testing",{"text":140,"config":141},"Software Supply Chain Security",{"href":142,"dataGaLocation":49,"dataGaName":143},"/solutions/supply-chain/","Software supply chain security",{"text":145,"config":146},"Software Compliance",{"href":147,"dataGaName":148,"dataGaLocation":49},"/solutions/software-compliance/","software compliance",{"title":150,"link":151,"items":156},"Measurement",{"config":152},{"icon":153,"href":154,"dataGaName":155,"dataGaLocation":49},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[157,161,165],{"text":158,"config":159},"Visibility & Measurement",{"href":154,"dataGaLocation":49,"dataGaName":160},"Visibility and Measurement",{"text":162,"config":163},"Value Stream Management",{"href":164,"dataGaLocation":49,"dataGaName":162},"/solutions/value-stream-management/",{"text":166,"config":167},"Analytics & Insights",{"href":168,"dataGaLocation":49,"dataGaName":169},"/solutions/analytics-and-insights/","Analytics and insights",{"title":171,"items":172},"GitLab for",[173,178,183],{"text":174,"config":175},"Enterprise",{"href":176,"dataGaLocation":49,"dataGaName":177},"/enterprise/","enterprise",{"text":179,"config":180},"Small Business",{"href":181,"dataGaLocation":49,"dataGaName":182},"/small-business/","small business",{"text":184,"config":185},"Public Sector",{"href":186,"dataGaLocation":49,"dataGaName":187},"/solutions/public-sector/","public sector",{"text":189,"config":190},"Pricing",{"href":191,"dataGaName":192,"dataGaLocation":49,"dataNavLevelOne":192},"/pricing/","pricing",{"text":194,"config":195,"link":197,"lists":201,"feature":281},"Resources",{"dataNavLevelOne":196},"resources",{"text":198,"config":199},"View all resources",{"href":200,"dataGaName":196,"dataGaLocation":49},"/resources/",[202,235,253],{"title":203,"items":204},"Getting started",[205,210,215,220,225,230],{"text":206,"config":207},"Install",{"href":208,"dataGaName":209,"dataGaLocation":49},"/install/","install",{"text":211,"config":212},"Quick start guides",{"href":213,"dataGaName":214,"dataGaLocation":49},"/get-started/","quick setup checklists",{"text":216,"config":217},"Learn",{"href":218,"dataGaLocation":49,"dataGaName":219},"https://university.gitlab.com/","learn",{"text":221,"config":222},"Product documentation",{"href":223,"dataGaName":224,"dataGaLocation":49},"https://docs.gitlab.com/","product documentation",{"text":226,"config":227},"Best practice videos",{"href":228,"dataGaName":229,"dataGaLocation":49},"/getting-started-videos/","best practice videos",{"text":231,"config":232},"Integrations",{"href":233,"dataGaName":234,"dataGaLocation":49},"/integrations/","integrations",{"title":236,"items":237},"Discover",[238,243,248],{"text":239,"config":240},"Customer success stories",{"href":241,"dataGaName":242,"dataGaLocation":49},"/customers/","customer success stories",{"text":244,"config":245},"Blog",{"href":246,"dataGaName":247,"dataGaLocation":49},"/blog/","blog",{"text":249,"config":250},"Remote",{"href":251,"dataGaName":252,"dataGaLocation":49},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":254,"items":255},"Connect",[256,261,266,271,276],{"text":257,"config":258},"GitLab Services",{"href":259,"dataGaName":260,"dataGaLocation":49},"/services/","services",{"text":262,"config":263},"Community",{"href":264,"dataGaName":265,"dataGaLocation":49},"/community/","community",{"text":267,"config":268},"Forum",{"href":269,"dataGaName":270,"dataGaLocation":49},"https://forum.gitlab.com/","forum",{"text":272,"config":273},"Events",{"href":274,"dataGaName":275,"dataGaLocation":49},"/events/","events",{"text":277,"config":278},"Partners",{"href":279,"dataGaName":280,"dataGaLocation":49},"/partners/","partners",{"backgroundColor":282,"textColor":283,"text":284,"image":285,"link":289},"#2f2a6b","#fff","Insights for the future of software development",{"altText":286,"config":287},"the source promo card",{"src":288},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":290,"config":291},"Read the latest",{"href":292,"dataGaName":293,"dataGaLocation":49},"/the-source/","the source",{"text":295,"config":296,"lists":298},"Company",{"dataNavLevelOne":297},"company",[299],{"items":300},[301,306,312,314,319,324,329,334,339,344,349],{"text":302,"config":303},"About",{"href":304,"dataGaName":305,"dataGaLocation":49},"/company/","about",{"text":307,"config":308,"footerGa":311},"Jobs",{"href":309,"dataGaName":310,"dataGaLocation":49},"/jobs/","jobs",{"dataGaName":310},{"text":272,"config":313},{"href":274,"dataGaName":275,"dataGaLocation":49},{"text":315,"config":316},"Leadership",{"href":317,"dataGaName":318,"dataGaLocation":49},"/company/team/e-group/","leadership",{"text":320,"config":321},"Team",{"href":322,"dataGaName":323,"dataGaLocation":49},"/company/team/","team",{"text":325,"config":326},"Handbook",{"href":327,"dataGaName":328,"dataGaLocation":49},"https://handbook.gitlab.com/","handbook",{"text":330,"config":331},"Investor relations",{"href":332,"dataGaName":333,"dataGaLocation":49},"https://ir.gitlab.com/","investor relations",{"text":335,"config":336},"Trust Center",{"href":337,"dataGaName":338,"dataGaLocation":49},"/security/","trust center",{"text":340,"config":341},"AI Transparency Center",{"href":342,"dataGaName":343,"dataGaLocation":49},"/ai-transparency-center/","ai transparency center",{"text":345,"config":346},"Newsletter",{"href":347,"dataGaName":348,"dataGaLocation":49},"/company/contact/#contact-forms","newsletter",{"text":350,"config":351},"Press",{"href":352,"dataGaName":353,"dataGaLocation":49},"/press/","press",{"text":355,"config":356,"lists":357},"Contact us",{"dataNavLevelOne":297},[358],{"items":359},[360,363,368],{"text":56,"config":361},{"href":58,"dataGaName":362,"dataGaLocation":49},"talk to sales",{"text":364,"config":365},"Support portal",{"href":366,"dataGaName":367,"dataGaLocation":49},"https://support.gitlab.com","support portal",{"text":369,"config":370},"Customer portal",{"href":371,"dataGaName":372,"dataGaLocation":49},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":374,"login":375,"suggestions":382},"Close",{"text":376,"link":377},"To search repositories and projects, login to",{"text":378,"config":379},"gitlab.com",{"href":63,"dataGaName":380,"dataGaLocation":381},"search login","search",{"text":383,"default":384},"Suggestions",[385,387,391,393,397,401],{"text":78,"config":386},{"href":83,"dataGaName":78,"dataGaLocation":381},{"text":388,"config":389},"Code Suggestions (AI)",{"href":390,"dataGaName":388,"dataGaLocation":381},"/solutions/code-suggestions/",{"text":112,"config":392},{"href":114,"dataGaName":112,"dataGaLocation":381},{"text":394,"config":395},"GitLab on AWS",{"href":396,"dataGaName":394,"dataGaLocation":381},"/partners/technology-partners/aws/",{"text":398,"config":399},"GitLab on Google Cloud",{"href":400,"dataGaName":398,"dataGaLocation":381},"/partners/technology-partners/google-cloud-platform/",{"text":402,"config":403},"Why GitLab?",{"href":91,"dataGaName":402,"dataGaLocation":381},{"freeTrial":405,"mobileIcon":410,"desktopIcon":415,"secondaryButton":418},{"text":406,"config":407},"Start free trial",{"href":408,"dataGaName":54,"dataGaLocation":409},"https://gitlab.com/-/trials/new/","nav",{"altText":411,"config":412},"Gitlab Icon",{"src":413,"dataGaName":414,"dataGaLocation":409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":411,"config":416},{"src":417,"dataGaName":414,"dataGaLocation":409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":419,"config":420},"Get Started",{"href":421,"dataGaName":422,"dataGaLocation":409},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":424,"mobileIcon":429,"desktopIcon":431},{"text":425,"config":426},"Learn more about GitLab Duo",{"href":427,"dataGaName":428,"dataGaLocation":409},"/gitlab-duo/","gitlab duo",{"altText":411,"config":430},{"src":413,"dataGaName":414,"dataGaLocation":409},{"altText":411,"config":432},{"src":417,"dataGaName":414,"dataGaLocation":409},{"freeTrial":434,"mobileIcon":439,"desktopIcon":441},{"text":435,"config":436},"Back to pricing",{"href":191,"dataGaName":437,"dataGaLocation":409,"icon":438},"back to pricing","GoBack",{"altText":411,"config":440},{"src":413,"dataGaName":414,"dataGaLocation":409},{"altText":411,"config":442},{"src":417,"dataGaName":414,"dataGaLocation":409},{"title":444,"button":445,"config":450},"See how agentic AI transforms software delivery",{"text":446,"config":447},"Watch GitLab Transcend now",{"href":448,"dataGaName":449,"dataGaLocation":49},"/events/transcend/virtual/","transcend event",{"layout":451,"icon":452},"release","AiStar",{"data":454},{"text":455,"source":456,"edit":462,"contribute":467,"config":472,"items":477,"minimal":684},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":457,"config":458},"View page source",{"href":459,"dataGaName":460,"dataGaLocation":461},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":463,"config":464},"Edit this page",{"href":465,"dataGaName":466,"dataGaLocation":461},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":468,"config":469},"Please contribute",{"href":470,"dataGaName":471,"dataGaLocation":461},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":473,"facebook":474,"youtube":475,"linkedin":476},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[478,525,579,623,650],{"title":189,"links":479,"subMenu":494},[480,484,489],{"text":481,"config":482},"View plans",{"href":191,"dataGaName":483,"dataGaLocation":461},"view plans",{"text":485,"config":486},"Why Premium?",{"href":487,"dataGaName":488,"dataGaLocation":461},"/pricing/premium/","why premium",{"text":490,"config":491},"Why Ultimate?",{"href":492,"dataGaName":493,"dataGaLocation":461},"/pricing/ultimate/","why ultimate",[495],{"title":496,"links":497},"Contact Us",[498,501,503,505,510,515,520],{"text":499,"config":500},"Contact sales",{"href":58,"dataGaName":59,"dataGaLocation":461},{"text":364,"config":502},{"href":366,"dataGaName":367,"dataGaLocation":461},{"text":369,"config":504},{"href":371,"dataGaName":372,"dataGaLocation":461},{"text":506,"config":507},"Status",{"href":508,"dataGaName":509,"dataGaLocation":461},"https://status.gitlab.com/","status",{"text":511,"config":512},"Terms of use",{"href":513,"dataGaName":514,"dataGaLocation":461},"/terms/","terms of use",{"text":516,"config":517},"Privacy statement",{"href":518,"dataGaName":519,"dataGaLocation":461},"/privacy/","privacy statement",{"text":521,"config":522},"Cookie preferences",{"dataGaName":523,"dataGaLocation":461,"id":524,"isOneTrustButton":32},"cookie preferences","ot-sdk-btn",{"title":94,"links":526,"subMenu":535},[527,531],{"text":528,"config":529},"DevSecOps platform",{"href":76,"dataGaName":530,"dataGaLocation":461},"devsecops platform",{"text":532,"config":533},"AI-Assisted Development",{"href":427,"dataGaName":534,"dataGaLocation":461},"ai-assisted development",[536],{"title":537,"links":538},"Topics",[539,544,549,554,559,564,569,574],{"text":540,"config":541},"CICD",{"href":542,"dataGaName":543,"dataGaLocation":461},"/topics/ci-cd/","cicd",{"text":545,"config":546},"GitOps",{"href":547,"dataGaName":548,"dataGaLocation":461},"/topics/gitops/","gitops",{"text":550,"config":551},"DevOps",{"href":552,"dataGaName":553,"dataGaLocation":461},"/topics/devops/","devops",{"text":555,"config":556},"Version Control",{"href":557,"dataGaName":558,"dataGaLocation":461},"/topics/version-control/","version control",{"text":560,"config":561},"DevSecOps",{"href":562,"dataGaName":563,"dataGaLocation":461},"/topics/devsecops/","devsecops",{"text":565,"config":566},"Cloud Native",{"href":567,"dataGaName":568,"dataGaLocation":461},"/topics/cloud-native/","cloud native",{"text":570,"config":571},"AI for Coding",{"href":572,"dataGaName":573,"dataGaLocation":461},"/topics/devops/ai-for-coding/","ai for coding",{"text":575,"config":576},"Agentic AI",{"href":577,"dataGaName":578,"dataGaLocation":461},"/topics/agentic-ai/","agentic ai",{"title":580,"links":581},"Solutions",[582,584,586,591,595,598,602,605,607,610,613,618],{"text":136,"config":583},{"href":131,"dataGaName":136,"dataGaLocation":461},{"text":125,"config":585},{"href":108,"dataGaName":109,"dataGaLocation":461},{"text":587,"config":588},"Agile development",{"href":589,"dataGaName":590,"dataGaLocation":461},"/solutions/agile-delivery/","agile delivery",{"text":592,"config":593},"SCM",{"href":121,"dataGaName":594,"dataGaLocation":461},"source code management",{"text":540,"config":596},{"href":114,"dataGaName":597,"dataGaLocation":461},"continuous integration & delivery",{"text":599,"config":600},"Value stream management",{"href":164,"dataGaName":601,"dataGaLocation":461},"value stream management",{"text":545,"config":603},{"href":604,"dataGaName":548,"dataGaLocation":461},"/solutions/gitops/",{"text":174,"config":606},{"href":176,"dataGaName":177,"dataGaLocation":461},{"text":608,"config":609},"Small business",{"href":181,"dataGaName":182,"dataGaLocation":461},{"text":611,"config":612},"Public sector",{"href":186,"dataGaName":187,"dataGaLocation":461},{"text":614,"config":615},"Education",{"href":616,"dataGaName":617,"dataGaLocation":461},"/solutions/education/","education",{"text":619,"config":620},"Financial services",{"href":621,"dataGaName":622,"dataGaLocation":461},"/solutions/finance/","financial services",{"title":194,"links":624},[625,627,629,631,634,636,638,640,642,644,646,648],{"text":206,"config":626},{"href":208,"dataGaName":209,"dataGaLocation":461},{"text":211,"config":628},{"href":213,"dataGaName":214,"dataGaLocation":461},{"text":216,"config":630},{"href":218,"dataGaName":219,"dataGaLocation":461},{"text":221,"config":632},{"href":223,"dataGaName":633,"dataGaLocation":461},"docs",{"text":244,"config":635},{"href":246,"dataGaName":247,"dataGaLocation":461},{"text":239,"config":637},{"href":241,"dataGaName":242,"dataGaLocation":461},{"text":249,"config":639},{"href":251,"dataGaName":252,"dataGaLocation":461},{"text":257,"config":641},{"href":259,"dataGaName":260,"dataGaLocation":461},{"text":262,"config":643},{"href":264,"dataGaName":265,"dataGaLocation":461},{"text":267,"config":645},{"href":269,"dataGaName":270,"dataGaLocation":461},{"text":272,"config":647},{"href":274,"dataGaName":275,"dataGaLocation":461},{"text":277,"config":649},{"href":279,"dataGaName":280,"dataGaLocation":461},{"title":295,"links":651},[652,654,656,658,660,662,664,668,673,675,677,679],{"text":302,"config":653},{"href":304,"dataGaName":297,"dataGaLocation":461},{"text":307,"config":655},{"href":309,"dataGaName":310,"dataGaLocation":461},{"text":315,"config":657},{"href":317,"dataGaName":318,"dataGaLocation":461},{"text":320,"config":659},{"href":322,"dataGaName":323,"dataGaLocation":461},{"text":325,"config":661},{"href":327,"dataGaName":328,"dataGaLocation":461},{"text":330,"config":663},{"href":332,"dataGaName":333,"dataGaLocation":461},{"text":665,"config":666},"Sustainability",{"href":667,"dataGaName":665,"dataGaLocation":461},"/sustainability/",{"text":669,"config":670},"Diversity, inclusion and belonging (DIB)",{"href":671,"dataGaName":672,"dataGaLocation":461},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":335,"config":674},{"href":337,"dataGaName":338,"dataGaLocation":461},{"text":345,"config":676},{"href":347,"dataGaName":348,"dataGaLocation":461},{"text":350,"config":678},{"href":352,"dataGaName":353,"dataGaLocation":461},{"text":680,"config":681},"Modern Slavery Transparency Statement",{"href":682,"dataGaName":683,"dataGaLocation":461},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":685},[686,689,692],{"text":687,"config":688},"Terms",{"href":513,"dataGaName":514,"dataGaLocation":461},{"text":690,"config":691},"Cookies",{"dataGaName":523,"dataGaLocation":461,"id":524,"isOneTrustButton":32},{"text":693,"config":694},"Privacy",{"href":518,"dataGaName":519,"dataGaLocation":461},[696],{"id":697,"title":18,"body":8,"config":698,"content":700,"description":8,"extension":30,"meta":704,"navigation":32,"path":705,"seo":706,"stem":707,"__hash__":708},"blogAuthors/en-us/blog/authors/michael-kozono.yml",{"template":699},"BlogAuthor",{"name":18,"config":701},{"headshot":702,"ctfId":703},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679544/Blog/Author%20Headshots/mkozono-headshot.jpg","mkozono",{},"/en-us/blog/authors/michael-kozono",{},"en-us/blog/authors/michael-kozono","AiC6Je8T03SBlbqoIQ-KqCIdVSd8TYCUTTmzuk5Cu_k",[710,721,736],{"content":711,"config":719},{"title":712,"description":713,"authors":714,"heroImage":716,"date":717,"body":718,"category":9},"CEO Shadow Takeaways from Jacie","Recap of my experience in the CEO Shadow Program.",[715],"Jacie Bandur","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664102/Blog/Hero%20Images/gitlab-values-cover.png","2021-05-18","\n\n{::options parse_block_html=\"true\" /}\n\n\nHi! I’m Jacie Bandur. I completed GitLab’s CEO Shadow program from 2021-04-26 through 2021-05-07. It was a really enlightening experience. I generally work in Learning and Development and consider myself a lifelong learner. I can’t even explain how much I learned in such a short about of time. I learned a lot about the business. I learned a lot about the product. But learned even more about the importance of iteration in everything we do.\n\n### Qualifications to Participate\n\nI wanted to start this off with touching on qualifications to participate in the program.\n\nI am the type of person that has gone through most of my life thinking I’m not qualified for things. I’m not qualified for that job, that promotion, that program. The list goes on and on.\n\nWhen I saw the [CEO Shadow program](/blog/ceo-shadow-impressions-takeaways/) kick off in 2019, I really wanted to participate. I was a little intimidated. Who wouldn’t be, spending 2 weeks with the CEO of any company? But time passed and all the sudden it was 2021 and I had not taken any steps to participating in the program.\n\nIf you are sitting there waiting for someone to tell you that you are qualified to participate in this program, I’m not big on giving “pep talks,” but here’s me telling you - You are qualified for this program. There’s never going to be a good or perfect time to do it. Tell your manager you want to do the CEO Shadow program. Stop waiting. Sign up today.\n\nNote: Take a look at the [eligibility](https://handbook.gitlab.com/handbook/ceo/shadow/#eligibility) section of the CEO Shadow page for more information on signing up.\n\n### Pre-Program Tips\n\nThere are many things recommended for shadows to do pre-program outlined on the CEO Shadow handbook page. As I was going through the program there were things that I thought helped me (or would have helped me).\n\nHere are my top 6 recommendations:\n\n1. Make sure your team knows you will be unavailable for 2 weeks. This isn’t a program that can or should be done alongside your normal day to day work. I found catching up from the 2 weeks away kind of difficult because I was trying to keep up on what was going on and I had a bunch of half done things.\n1. Talk with people who have done the shadow program - schedule at least 3 coffee chats with CEO Shadow Alumni.\n1. Have food that is easy to eat quickly. Sid’s meetings are back to back most days, so you will have small amounts of time to eat throughout the day. Sid does eat during calls, which you are welcome to do, too, but if you are taking notes, it is difficult to eat. And this will make you realize why speedy meetings are so important!\n1. Listen to the [Executive Leadership LinkedIn Learning course](https://www.linkedin.com/learning/executive-leadership/).\n1. Be prepared to ask questions. When doing the program virtually, there isn’t a ton of time for asking questions, so when one would come up, I would add it to a note on my computer and ask if there was ever time with just the shadows and Sid.\n1. Take at least 1 day off after the program. Take even a couple of days off if you can! This is recommended on the handbook page, but I can’t stress this enough.\n\n\n### Takeaways\n\n**Group Conversations**\n\nI’ve been at GitLab for almost 4 years. When I joined, I made it a point to attend as many GC’s as I could. I had gotten out of the habit of attending Group Conversations. After attending them again for 2 weeks, I realized how important they are to understand better what is going on across the business. Everything in the organization is so intertwined. It’s helpful to understand what other teams are working on and succeeding in.\n\n**Feedback**\n\nWe should all be giving and receiving feedback often. We have a whole [handbook page on giving and receiving feedback](https://handbook.gitlab.com/handbook/people-group/guidance-on-feedback/). Read the handbook page and watch the videos, as well. Practice giving feedback. I recommend using the [1-1 agenda](https://handbook.gitlab.com/handbook/leadership/1-1/suggested-agenda-format/) Sid uses, because Feedback is an essential piece of that agenda, and it makes feedback more of a routine thing.\n\n**Biggest Takeaway**\n\nWe have an incredible team here at GitLab, from Engineering to Product to Sales to People and all the groups in between. There are so many great ideas. I observed the constant reinforcement by Sid to start with something small and build on it. You can ALWAYS make something more complex. It’s hard to go back to something more simple when you start with something complex.\n\nA couple of quotes that I heard from Sid during the program that reinforced this point:\n\n- “Every complex system evolves from a simple system that worked.”\n- “It’s very clear what is the simple solution. We can always make it more complicated as we go on.”\n\nI know they are very similar, but they happened in different meetings on different days, so the point was reinforced repeatedly.\n\nDuring the program, I reflected on the projects that I’am working on. How many of them am I trying to do too much on before releasing. Probably all of them. When I’m working on projects in the future, I will break them down into smaller, more doable chunks. Iteration is hard - it’s a skill to be practicing constantly.\n\n\n### Overall\n\nOverall, the program was really insightful and impactful. If you haven’t participated in it yet, I cannot encourage you enough to do so!\n",{"slug":720,"featured":12,"template":13},"ceo-shadow-recap",{"content":722,"config":734},{"title":723,"description":724,"authors":725,"heroImage":727,"date":728,"body":729,"category":9,"tags":730},"Why I love contributing to GitLab","Making small meaningful changes is what it's all about.",[726],"Austin Regnery","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679501/Blog/Hero%20Images/new-feature.png","2021-05-11","It was mid-morning on a Tuesday in February, and I had 10 minutes in between meetings. So I decided to try and solve a pain point of mine.\nYou see, I had to memorize this HTML snippet to create a collapsible section in GitLab Issue descriptions and comments, but I kept forgetting it. Was it `summary` or `section`? I could never remember.\n```html\n\u003Cdetails>\n\u003Csummary>Insert Title\u003C/summary>\nHidden content\n\u003C/details>\n```\nEven though it is not vanilla Markdown, GitLab knows how to interpret some HTML. I used this formatting trick fairly often since full-page screenshots can occupy a lot of screen space, which leads to excessive scrolling.\nSo I decided to poke around our codebase to see how the other Markdown shortcuts worked. To my surprise, it was pretty straightforward. Each shortcut had a simple text input that mapped to each button. This implementation was simple to replicate since I just needed to copy/paste and replace a few words.\n![Image of Vue and Haml files with editor shortcuts](https://about.gitlab.com/images/blogimages/why-i-love-contributing-to-gitlab/vue-haml.png){: .shadow}\nThe Vue and Haml files with the new shortcut\n\nI started a branch and began hacking away at the code. Now, I would never call myself a Software Engineer, but I like to try and make things from time to time. I was able to add a new shortcut to the toolbar to insert this code snippet for me in less than 10 minutes. No more memorizing! Making contributions like this is what makes working at GitLab so special.\nNow, it wasn't ready for production, but I at least had something that worked. I shared it with my UX colleagues in Slack, and it started to gain traction with several up-votes and few constructive comments on how to make it better.\nWith the functionality flushed out, a few other designers helped me get a better icon added to our SVG library. Using clear iconography is critical for communicating information more clearly.\n| Initial Icon | Final Icon |\n| - | - |\n| ![SVG of chevron right icon](https://about.gitlab.com/images/blogimages/why-i-love-contributing-to-gitlab/chevron-right.svg) | ![SVG of details block icon](https://about.gitlab.com/images/blogimages/why-i-love-contributing-to-gitlab/details-block.svg) |\n\nThe last thing to do was resolve my failing tests, and I had several teammates help me do that.\n![Gif of the shortcut being used](https://about.gitlab.com/images/blogimages/why-i-love-contributing-to-gitlab/demo.gif)\n\nToday [this change](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54938) merged! Now I solved a pain point for me and others. It took a few months to go from idea to production, but the effort was super low. I'd say the return on my initial investment, 10 minutes, is super high.\n> Having a direct impact on a product was never an option for me before joining GitLab.\n\n![Image of participants in the Merge Request](https://about.gitlab.com/images/blogimages/why-i-love-contributing-to-gitlab/participants.png)\n\n\nThank you to everyone that helped me deploy this\n",[731,732,733],"UX","product","AWS",{"slug":735,"featured":12,"template":13},"why-i-love-contributing-to-gitlab",{"content":737,"config":747},{"title":738,"description":739,"authors":740,"heroImage":742,"date":728,"body":743,"category":9,"tags":744},"Placebo Lines on the Pipeline Graph","Have you noticed the connecting lines missing on your pipelines lately? Here's why",[741],"Sam Beckham","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679507/Blog/Hero%20Images/ci-cd.png","\n\n{::options parse_block_html=\"true\" /}\n\n\n\nHave you ever pressed the close door button on the elevator, in the hope that you'll save a few precious seconds?\nOr got frustrated at the person stood next to you at the cross-walk, neglecting to press the button?\nWell, maybe they know something you don't, or perhaps you know this already.\nMany buttons in our society lie to us.\n[David McRaney](https://youarenotsosmart.com/2010/02/10/placebo-buttons/) dubbed these, \"Placebo buttons\" and they're everywhere.\nThose elevator doors won't close any faster and the cross-walk button has no effect on the lights.\nThe only lights they control are the lights on the buttons themselves.\nThey give you the feedback you crave, but that's all they're doing.\n\nThese placebos aren't constrained to the physical world, they're prevalent in [UI design](/blog/the-evolution-of-ux-at-gitlab/) too.\nFrom literal placebo buttons like [YouTube's downvote](https://www.quora.com/Does-downvoting-a-comment-on-YouTube-even-do-anything), to more subtle effects like Instagram always [pretending to work](https://www.fastcompany.com/1669788/the-3-white-lies-behind-instagrams-lightning-speed), or progress bars that have a [fixed animation](https://www.theatlantic.com/technology/archive/2017/02/why-some-apps-use-fake-progress-bars/517233/).\nThey're everywhere if you know where to look.\n\nAt GitLab, we created a placebo of our own in one of our core features; the pipeline graph.\n\nThose of you who have used our pipeline graph, will be familiar with its appearance.\nThere's a series of jobs, grouped by stages, connected by a series of lines depicting the relationships between the jobs.\nBut these lines might be lying to you.\nThese lines are indiscriminately drawn between each job in a stage, regardless of their relationship.\nThese lines are placebos.\n\n![The old pipeline rendering with lines connecting every job in a stage](https://about.gitlab.com/images/blogimages/placebo-lines_old-graph.png)\n\nThis wasn't a problem to begin with.\nA basic pipeline has several jobs across a handful of stages.\nJobs in each stage would run parallel to each other, but each stage would run sequentially.\nIn the image shown above, all the jobs in the test stage would trigger at the same time. Once those jobs had finished, all the jobs in the build stage would trigger.\nWe used rudimentary CSS to draw lines connecting each job in one stage to each job in the next.\nThese lines weren't calculated based on their connections, but still reflected the story they were telling.\n\nSince the introduction of `needs` relationships in [v12.2](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47063), pipelines got a bit more complicated.\nNow you could configure a job in a later stage to trigger as soon as a job in an earlier stage completed.\nLooking at our old example, we could set the API deployment to run as soon as our spec tests passed.\nThis skips the remaining tests and the entire build stage, turning our lines into pretty little liars.\n\nWe had many internal discussions about these lines, and how to show the relationships between jobs.\nThere's the [`needs` visualization](https://docs.gitlab.com/ee/ci/directed_acyclic_graph/#needs-visualization), which does an excellent job of displaying these relationships, but the main pipeline graph was still inaccurate.\nFor the past few months, we've been [refactoring the pipeline graph](https://gitlab.com/gitlab-org/gitlab/-/issues/276949), giving it a new lease of life and fixing some of its issues along the way.\nOne of those issues were the faked lines.\nIn the new version, we can accurately draw lines between jobs.\nLines that actually depict the relationships jobs have with each other.\nNow the lines no-longer lie!\n\n![The newer pipeline graph showing the correct needs links between jobs](https://about.gitlab.com/images/blogimages/placebo-lines_new-graph.png)\n\nThe above image shows an unreleased version of the pipeline graph.\nYou can see the lines drawn between the jobs to show that the `deploy:API` job can start as soon as the `rspec` job is successful.\nSomething the old lines (shown earlier in this post) would have been unable to depict.\n\nOne unfortunate downside of this is that these lines can be quite expensive to calculate.\nThey're actual DOM nodes, drawn deliberately and placed precisely.\nOn smaller graphs this isn't a problem, but some of our initial tests have found pipelines with a potential 8000+ job connections.\nThat kind of calculation would grind the browser to a halt, and nobody wants that.\n\nAt GitLab, we believe in boring solutions.\nWe make the simple change that sets us on the path towards where we want to be.\nShip it, get feedback, and iterate.\nSo that's what we did.\nIn the first phase of this rollout, we shipped the new pipeline graph with no lines connecting the jobs.\nWe don't have to worry about the expensive calculations, and we still get to roll out the refactored pipeline graph.\n\n![The current (v13.11) pipeline graph showing no links between jobs](https://about.gitlab.com/images/blogimages/placebo-lines_current-graph.png)\n\nWe know some of you will miss them, but fear not.\nBoring solutions are just technical debt if you don't iterate on them.\nSo the [improved lines are coming](https://gitlab.com/groups/gitlab-org/-/epics/4509) in a future release, along with several other improvements to the pipeline graph.\nWe're already starting to roll out the new [Job Dependencies](https://gitlab.com/gitlab-org/gitlab/-/issues/298973) view which shows the jobs in a (much closer to) execution order.\nStay tuned for more updates, and watch [Sarah Groff Hennigh Palermo's talk](https://www.youtube.com/watch?v=R2EKqKjB7OQ) for the technical side of this effort and a deeper dive into some of the decisions we made.\n",[745,746,23,25],"CI","frontend",{"slug":748,"featured":12,"template":13},"placebo-lines-on-the-pipeline-graph",{"promotions":750},[751,765,776],{"id":752,"categories":753,"header":755,"text":756,"button":757,"image":762},"ai-modernization",[754],"ai-ml","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":758,"config":759},"Get your AI maturity score",{"href":760,"dataGaName":761,"dataGaLocation":247},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":763},{"src":764},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":766,"categories":767,"header":768,"text":756,"button":769,"image":773},"devops-modernization",[732,563],"Are you just managing tools or shipping innovation?",{"text":770,"config":771},"Get your DevOps maturity score",{"href":772,"dataGaName":761,"dataGaLocation":247},"/assessments/devops-modernization-assessment/",{"config":774},{"src":775},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":777,"categories":778,"header":780,"text":756,"button":781,"image":785},"security-modernization",[779],"security","Are you trading speed for security?",{"text":782,"config":783},"Get your security maturity score",{"href":784,"dataGaName":761,"dataGaLocation":247},"/assessments/security-modernization-assessment/",{"config":786},{"src":787},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"header":789,"blurb":790,"button":791,"secondaryButton":796},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":792,"config":793},"Get your free trial",{"href":794,"dataGaName":54,"dataGaLocation":795},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":499,"config":797},{"href":58,"dataGaName":59,"dataGaLocation":795},1772652074355]