[{"data":1,"prerenderedAt":1980},["ShallowReactive",2],{"/blog/better-code-reviews":3,"navigation-en-us":1194,"banner-en-us":1622,"footer-en-us":1632,"blog-post-authors-en-us-David O'Regan":1876,"blog-related-posts-en-us-better-code-reviews":1892,"blog-promotions-en-us":1916,"next-steps-en-us":1970},{"id":4,"title":5,"authors":6,"body":8,"category":1173,"date":1174,"description":1175,"extension":1176,"externalUrl":1177,"faq":1177,"featured":1178,"heroImage":1179,"meta":1180,"navigation":286,"path":1181,"seo":1182,"slug":1186,"stem":1187,"tags":1188,"template":1192,"updatedDate":1177,"__hash__":1193},"blogPosts/en-us/blog/better-code-reviews.md","Better Code Reviews GitLab Style",[7],"David O'Regan",{"type":9,"value":10,"toc":1152},"minimark",[11,18,31,39,42,59,65,70,81,84,87,95,98,105,108,139,153,157,170,178,185,206,209,212,215,218,255,258,305,308,315,323,326,329,343,346,354,360,369,382,386,396,408,413,416,421,424,459,463,470,571,578,602,606,612,629,632,635,651,654,667,701,711,715,718,729,732,745,753,757,762,771,776,779,788,796,800,803,806,826,829,843,850,854,863,870,875,878,881,899,902,913,917,927,947,950,953,960,963,970,980,983,991,994,998,1001,1005,1019,1023,1028,1031,1034,1041,1050,1066,1070,1083,1086,1100,1106,1115,1119,1129,1136,1145,1148],[12,13,14],"blockquote",{},[15,16,17],"p",{},"A love letter to anyone that's ever reviewed or been reviewed.",[15,19,20,21,25,26,30],{},"This blog post originally started as a thank-you message inside the GitLab slack channel ",[22,23,24],"code",{},"#thanks",", however, the scope of the message grew to such a degree that I wanted to take it a step further and see if I could not only thank the amazing people this post is dedicated to, but also hopefully share some of the amazing things they taught me to help ",[27,28,29],"em",{},"you",", dear reader.",[15,32,33,34,38],{},"I have always been rather passionate about feedback. For as long as I can remember, I have always sought feedback on everything I was interested in. It's as true for me in software as it is for my non computer related hobbies like bodybuilding or grammar.....",[35,36,37],"strong",{},"cough cough",". Feedback is so important for every aspect of life, and in software it is no different. Feedback matters and in GitLab, we deliver most if not all of our feedback to one another via the code review.",[15,40,41],{},"This post is designed to deliver a selection of the most fantastic things I have seen in code reviews here at GitLab, with two goals:",[43,44,45,56],"ol",{},[46,47,48,49,55],"li",{},"Acknowledge the people who work hard to ensure the feedback cycle they provide is as good as it can be, because at GitLab we like to ",[50,51,54],"a",{"href":52,"rel":53},"https://handbook.gitlab.com/handbook/values/#say-thanks",[],"say thanks",".",[46,57,58],{},"Offer you, the reader, a selection of tools for your toolbelt when it comes to code reviews.",[15,60,61,62,55],{},"Enter - ",[35,63,64],{},"Better Code Reviews",[66,67,69],"h2",{"id":68},"self-reviews-details-matter","Self Reviews - Details Matter",[12,71,72],{},[15,73,74,75,80],{},"Before assigning MRs to the reviewer I practice a self-review to help the reviewer and the maintainer understand quirks and caveats of the MR. I am trying to anticipate their concerns/questions. As a maintainer I find it also very valuable. - Peter Leitzen (",[50,76,79],{"href":77,"rel":78},"https://gitlab.com/splattael",[],"@splattael",")",[15,82,83],{},"We often take for granted that details are hard. Moreover, we often take for granted that details in software are even harder. The majority of software consists of layers upon layers of deep abstractions and obscure logic that can be difficult, if not impossible, to really understand without spending a significant amount of time parsing it line by line.",[15,85,86],{},"This process is made even harder when the details or context are incorrect. Though it's natural for this to happen, humans are not spell checkers, nor do the majority of us like to revisit a piece of work a fourth or fifth time to ensure it's as correct as it can be. If we all did this, nothing would ever be delivered.",[15,88,89,90,55],{},"But - there is a sweet spot to be found for this dilemma in software where we can keep the velocity of delivery high, and also reduce the feedback cycle time through a small amount of dedicated effort to the details. We talk about some of the details ",[50,91,94],{"href":92,"rel":93},"https://docs.gitlab.com/development/code_review/#the-responsibility-of-the-merge-request-author",[],"here in the responsibility of the merge request author",[15,96,97],{},"For the merge request author, step through a checklist. Here is mine. If you can't read my chicken-scratch handwriting, I'll type it out too:",[15,99,100],{},[101,102],"img",{"alt":103,"src":104},"merge-checklist","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398651/blog/Content%20Images/merge-checklist.png",[15,106,107],{},"Before every feedback cycle:",[109,110,111,114,117,120,123,126,129,136],"ul",{},[46,112,113],{},"Re-read every line",[46,115,116],{},"Test your code locally",[46,118,119],{},"Write a test for every change (or as many as you can)",[46,121,122],{},"Write a clear description and update it after each feedback cycle",[46,124,125],{},"Include at least one screenshot per change. More is better",[46,127,128],{},"Check, re-check and re-check your labels",[46,130,131,132,135],{},"Consider using a ",[22,133,134],{},"~\"workflow::refinement\""," label for issues ahead of time like we do in the Monitor:Health team",[46,137,138],{},"Review the code as if you were the reviewer. Be proactive, answer the likely questions, and open followup issues ahead of time",[15,140,141,142,147,148,55],{},"If you want to see the last and most important part in action, check out one of our frontend maintainers Natalia Tepluhina(",[50,143,146],{"href":144,"rel":145},"https://gitlab.com/ntepluhina",[],"@ntepluhina",") pre-answer a question she knew would be asked in ",[50,149,152],{"href":150,"rel":151},"https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33587#note_353564612",[],"one of her merge requests",[66,154,156],{"id":155},"conventional-comments-communicate-intent","Conventional Comments - Communicate Intent",[12,158,159],{},[15,160,161,164,165,80],{},[35,162,163],{},"Shaming"," This is horrible code. How about re-writing all of it so that it stops being that bad? - Frédéric Caplette (",[50,166,169],{"href":167,"rel":168},"https://gitlab.com/f_caplette",[],"@f_caplette",[15,171,172,173,55],{},"One of the hardest parts of getting a code review right is communicating the human touch. When we offer feedback and receive feedback, human habit creates cognitive distortion by defaulting to the most negative aspects of that feedback. At GitLab, we try to highlight that in our ",[50,174,177],{"href":175,"rel":176},"https://handbook.gitlab.com/handbook/values/#assume-positive-intent",[],"value system",[15,179,180,181,184],{},"In the world of psychology, this is called ",[35,182,183],{},"mental filtering",", and it's something that all humans have a tendency to do. Though in software this affliction can be more common, as working in software goes hand-in-hand with valuing yourself based on how intelligent others think you are.",[15,186,187,188,193,194,199,200,205],{},"Enter ",[50,189,192],{"href":190,"rel":191},"https://conventionalcomments.org/",[],"conventional comments"," by Paul Slaughter (",[50,195,198],{"href":196,"rel":197},"https://gitlab.com/pslaughter",[],"@pslaughter",") - a well thought-out system for leaving comments in a useful way for both the reviewer and author of the merge request. It's so popular one amazing person made a ",[50,201,204],{"href":202,"rel":203},"https://gitlab.com/conventionalcomments/conventional-comments-button",[],"browser extension (chrome, firefox)"," for it!",[15,207,208],{},"So why does adding a single bolded word to the top of a comment help with the human touch? Well, it's all about intent.",[15,210,211],{},"When you start the comment with an eye-catching single word that defines the intent and tone for the comment, it gives the reader a chance to understand where your comment is coming from.",[15,213,214],{},"Let's try an experiment. If you had submitted code for review, which comment would you prefer to read?",[15,216,217],{},"Option one:",[219,220,225],"pre",{"className":221,"code":222,"language":223,"meta":224,"style":224},"language-bash shiki shiki-themes github-light","What do you think about X instead?\n","bash","",[22,226,227],{"__ignoreMap":224},[228,229,232,236,240,243,246,249,252],"span",{"class":230,"line":231},"line",1,[228,233,235],{"class":234},"s7eDp","What",[228,237,239],{"class":238},"sYBdl"," do",[228,241,242],{"class":238}," you",[228,244,245],{"class":238}," think",[228,247,248],{"class":238}," about",[228,250,251],{"class":238}," X",[228,253,254],{"class":238}," instead?\n",[15,256,257],{},"or option two:",[219,259,261],{"className":221,"code":260,"language":223,"meta":224,"style":224},"**suggestion (non-blocking)**\n\nWhat do you think about X instead?\n",[22,262,263,281,288],{"__ignoreMap":224},[228,264,265,269,273,276,278],{"class":230,"line":231},[228,266,268],{"class":267},"sD7c4","**",[228,270,272],{"class":271},"sgsFI","suggestion (",[228,274,275],{"class":234},"non-blocking",[228,277,80],{"class":271},[228,279,280],{"class":267},"**\n",[228,282,284],{"class":230,"line":283},2,[228,285,287],{"emptyLinePlaceholder":286},true,"\n",[228,289,291,293,295,297,299,301,303],{"class":230,"line":290},3,[228,292,235],{"class":234},[228,294,239],{"class":238},[228,296,242],{"class":238},[228,298,245],{"class":238},[228,300,248],{"class":238},[228,302,251],{"class":238},[228,304,254],{"class":238},[15,306,307],{},"Now if you're anything like me, you took a preference to option two. It had context, communicated empathy, and was an invitation to try something different rather than a command.",[15,309,310,311,314],{},"The magic part of this comment is the first line ",[22,312,313],{},"**suggestion (non-blocking)**",". Straightaway, before you even read the comment, you know the two most important things about it:",[43,316,317,320],{},[46,318,319],{},"It's a suggestion from the reviewer",[46,321,322],{},"It's non-blocking, communicating it's more of a friendly suggestion then a hard change that's needed",[15,324,325],{},"Another massive advantage this style of commenting has: it allows merge request authors to understand the reviewer is neither trying to block nor act as a gatekeeper for their work. By highlighting what counts as a blocking and a non-blocking comment, merge authors get the full context of what the reviewer is trying to communicate.",[15,327,328],{},"To demonstrate this, let's try another thought experiment! You have submitted a merge request for review and your review comes back with eight comments.",[109,330,331,337],{},[46,332,333,336],{},[35,334,335],{},"Scenario A: No context in comments."," All comments are treated equally because they lack context for what counts as a blocker and what doesn't.",[46,338,339,342],{},[35,340,341],{},"Scenario B:"," Context added via conventional comments system.",[15,344,345],{},"The comments can be treated via priority:",[43,347,348,351],{},[46,349,350],{},"Blockers => What's needed to get the merge over the line.",[46,352,353],{},"Non-blockers => What can be a separate merge or perhaps a discussion.",[15,355,356,357,359],{},"Next time you're reviewing code, try using conventional comments and watch how it affects not only the way the merge request author feels about the review, but the way ",[35,358,29],{},", the reviewer, feel leaving the review. My guess is you'll feel a lot better.",[15,361,362,363,368],{},"We're currently looking at ",[50,364,367],{"href":365,"rel":366},"https://gitlab.com/gitlab-org/gitlab/-/issues/26891",[],"integrating this feature directly into GitLab"," because we believe in making GitLab the best possible place for code reviews, and want you to have the best experience possible.",[15,370,371,372,375,376,381],{},"If you want to see a real-life example of some of Paul Slaughter's (",[50,373,198],{"href":196,"rel":374},[],") awesome work using conventional comments, check out ",[50,377,380],{"href":378,"rel":379},"https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24897",[],"his reviews of my community contributions"," here at GitLab. That empathy shines through.",[66,383,385],{"id":384},"the-patch-file","The Patch File",[12,387,388],{},[15,389,390,391,80],{},"Here's a patch file to better explain - Denys Mishunov (",[50,392,395],{"href":393,"rel":394},"https://gitlab.com/dmishunov",[],"@dmishunov",[15,397,398,399,402,403,55],{},"Wanna know a ",[22,400,401],{},"git"," secret? Patch files are the stuff of magic. If you want to read about them, ",[50,404,407],{"href":405,"rel":406},"https://git-scm.com/docs/git-format-patch",[],"check the Git documentation for patches",[409,410,412],"h3",{"id":411},"how-to-make-a-patch-file","How To Make A Patch File",[15,414,415],{},"You can make a patch file via your editor, or via the command line.",[417,418,420],"h4",{"id":419},"via-the-editor","Via The Editor",[15,422,423],{},"Rocking a nice fancy IDE or text editor? Most of them support patch files via plugins, or out of the box!",[109,425,426,433,440,447],{},[46,427,428],{},[50,429,432],{"href":430,"rel":431},"https://github.com/paragdiwan/vscode-git-patch",[],"VSCode",[46,434,435],{},[50,436,439],{"href":437,"rel":438},"https://www.jetbrains.com/help/webstorm/using-patches.html",[],"Webstorm",[46,441,442],{},[50,443,446],{"href":444,"rel":445},"https://atom.io/packages/git-plus",[],"Atom",[46,448,449,454,455,458],{},[50,450,453],{"href":451,"rel":452},"https://vim.fandom.com/wiki/How_to_make_and_submit_a_patch",[],"Vim"," …life is what happens when you're trying to exit ",[22,456,457],{},"vim","?",[417,460,462],{"id":461},"via-the-cli","Via The CLI",[15,464,465,466,469],{},"Okay, you’ve made some commits, here’s your ",[22,467,468],{},"git log",":",[219,471,475],{"className":472,"code":473,"language":474,"meta":224,"style":224},"language-shell shiki shiki-themes github-light","git log --pretty=oneline -3\n* da33d1k - (feature_branch) Reviewer Commit 1 (7 minutes ago)\n* 66a84ah - (feature_branch) Developer 1 Commit (12 minutes ago)\n* adsc8cd - (REL-0.5.0, origin/master, origin/HEAD, master) Release 13.0 (2 weeks ago)\n","shell",[22,476,477,491,517,538],{"__ignoreMap":224},[228,478,479,481,484,488],{"class":230,"line":231},[228,480,401],{"class":234},[228,482,483],{"class":238}," log",[228,485,487],{"class":486},"sYu0t"," --pretty=oneline",[228,489,490],{"class":486}," -3\n",[228,492,493,496,499,502,505,508,511,514],{"class":230,"line":283},[228,494,495],{"class":267},"*",[228,497,498],{"class":271}," da33d1k - (",[228,500,501],{"class":234},"feature_branch",[228,503,504],{"class":271},") Reviewer Commit 1 (",[228,506,507],{"class":234},"7",[228,509,510],{"class":238}," minutes",[228,512,513],{"class":238}," ago",[228,515,516],{"class":271},")\n",[228,518,519,521,524,526,529,532,534,536],{"class":230,"line":290},[228,520,495],{"class":267},[228,522,523],{"class":271}," 66a84ah - (",[228,525,501],{"class":234},[228,527,528],{"class":271},") Developer 1 Commit (",[228,530,531],{"class":234},"12",[228,533,510],{"class":238},[228,535,513],{"class":238},[228,537,516],{"class":271},[228,539,541,543,546,549,552,555,558,561,564,567,569],{"class":230,"line":540},4,[228,542,495],{"class":267},[228,544,545],{"class":271}," adsc8cd - (",[228,547,548],{"class":234},"REL-0.5.0,",[228,550,551],{"class":238}," origin/master,",[228,553,554],{"class":238}," origin/HEAD,",[228,556,557],{"class":238}," master",[228,559,560],{"class":271},") Release 13.0 (",[228,562,563],{"class":234},"2",[228,565,566],{"class":238}," weeks",[228,568,513],{"class":238},[228,570,516],{"class":271},[15,572,573,574,577],{},"This command creates a new file, ",[22,575,576],{},"reviewer_commit.patch",", with all changes from the reviewer's latest commit against the feature branch:",[219,579,581],{"className":472,"code":580,"language":474,"meta":224,"style":224},"git format-patch HEAD~1 --stdout > reviewer_commit.patch\n",[22,582,583],{"__ignoreMap":224},[228,584,585,587,590,593,596,599],{"class":230,"line":231},[228,586,401],{"class":234},[228,588,589],{"class":238}," format-patch",[228,591,592],{"class":238}," HEAD~1",[228,594,595],{"class":486}," --stdout",[228,597,598],{"class":267}," >",[228,600,601],{"class":238}," reviewer_commit.patch\n",[409,603,605],{"id":604},"apply-the-patch","Apply The Patch",[15,607,608,609,469],{},"First, take a look at what changes are in the patch. You can do this easily with ",[22,610,611],{},"git apply",[219,613,615],{"className":472,"code":614,"language":474,"meta":224,"style":224},"git apply --stat reviewer_commit.patch\n",[22,616,617],{"__ignoreMap":224},[228,618,619,621,624,627],{"class":230,"line":231},[228,620,401],{"class":234},[228,622,623],{"class":238}," apply",[228,625,626],{"class":486}," --stat",[228,628,601],{"class":238},[15,630,631],{},"Just a heads up! Despite the name, this command won't actually apply the patch. It will just show the statistics about what the patch will do.",[15,633,634],{},"So now that we've had a look, let's test it first, because not all patches are created equal:",[219,636,638],{"className":472,"code":637,"language":474,"meta":224,"style":224},"git apply --check reviewer_commit.patch\n",[22,639,640],{"__ignoreMap":224},[228,641,642,644,646,649],{"class":230,"line":231},[228,643,401],{"class":234},[228,645,623],{"class":238},[228,647,648],{"class":486}," --check",[228,650,601],{"class":238},[15,652,653],{},"No errors? Awesome! We can apply this patch without worry.",[15,655,656,657,660,661,663,664,666],{},"To apply the patch, you should use ",[22,658,659],{},"git am"," instead of ",[22,662,611],{},". The reason: ",[22,665,659],{}," allows you to sign off an applied patch with the reviewer's stamp.",[219,668,670],{"className":472,"code":669,"language":474,"meta":224,"style":224},"git am --signoff \u003C reviewer_commit.patch\nApplying: Reviewer Commit 1\n",[22,671,672,687],{"__ignoreMap":224},[228,673,674,676,679,682,685],{"class":230,"line":231},[228,675,401],{"class":234},[228,677,678],{"class":238}," am",[228,680,681],{"class":486}," --signoff",[228,683,684],{"class":267}," \u003C",[228,686,601],{"class":238},[228,688,689,692,695,698],{"class":230,"line":283},[228,690,691],{"class":234},"Applying:",[228,693,694],{"class":238}," Reviewer",[228,696,697],{"class":238}," Commit",[228,699,700],{"class":486}," 1\n",[15,702,703,704,706,707,710],{},"Now run ",[22,705,468],{}," and you can see the ",[22,708,709],{},"Signed-off-by"," tag in the commit message. This tag makes it very easy to understand how this commit ended up in the code base.",[409,712,714],{"id":713},"why-to-use-them-in-code-reviews","Why to use them in code reviews",[15,716,717],{},"So now that you know how to make a shiny patch file, why would you use patch files as part of a code review process? There are a few reasons you might consider offering a patch file for a change you feel strongly about:",[43,719,720,723,726],{},[46,721,722],{},"It communicates you have invested a large amount of effort into understanding the author's solution and reasoning",[46,724,725],{},"It demonstrates passion for reaching the best solution through teamwork",[46,727,728],{},"It offers a willingness on the reviewer's part to accept responsibility for this merge past the point of just reading the code",[15,730,731],{},"Some people might argue patch files are a cheeky way for a reviewer to force a change they would rather see make it into the code base, but I argue that anyone who has taken the time to check out a branch, run the project, implement a change, and then submit that change back for a discussion is embodying the value of collaboration to the fullest.",[15,733,734,735,738,739,744],{},"Want to see a awesome example of a patch file in action? Check out one of our frontend maintainers Denys Mishunov (",[50,736,395],{"href":393,"rel":737},[],") in action using a ",[50,740,743],{"href":741,"rel":742},"https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31686#note_341534370",[],"patch file to its maximum potential","!",[15,746,747,748,55],{},"We believe so much in creating the best code review experience here at GitLab, we're looking into how can we make this system a ",[50,749,752],{"href":750,"rel":751},"https://gitlab.com/gitlab-org/gitlab/-/issues/220044",[],"seamless part of the merge request and code review flow",[66,754,756],{"id":755},"fairness","Fairness",[12,758,759],{},[15,760,761],{},"Fairness is a person's ability to rise above their own prejudice.",[15,763,764,765,770],{},"Fairness is a odd word. Chris Voss, a former FBI negotiator, said in his book ",[50,766,769],{"href":767,"rel":768},"https://www.goodreads.com/book/show/26156469-never-split-the-difference",[],"Never Split The Difference"," that:",[12,772,773],{},[15,774,775],{},"“Fair”—the most powerful word in any negotiation scenario. To become a great negotiator, you must earn the reputation of being a fair one.",[15,777,778],{},"Code reviews can be viewed as a negotiation. It's you and another human being having a negotiation, based upon the idea that at the end, the result of this negotiation should be a selection of code that is both of value and of a high standard. While you might think that FBI negotiations and code reviews have little to do with one another, the concept being a fair negotiator often can be the most useful tool in your toolbox as both an author and reviewer.",[15,780,781,782,787],{},"You can actually see it mentioned twice in the ",[50,783,786],{"href":784,"rel":785},"https://handbook.gitlab.com/handbook/values/#permission-to-play",[],"permissions to play in points 2 and 7"," guidelines here at GitLab:",[109,789,790,793],{},[46,791,792],{},"\"Be dependable, reliable, fair, and respectful.\"",[46,794,795],{},"\"Seek out ways to be fair to everyone.\"",[409,797,799],{"id":798},"author-fairness","Author Fairness",[15,801,802],{},"Being fair as an author is the easier of the two. When you think of being fair as an author you need to adhere to a few simple Do's and Don'ts:",[15,804,805],{},"Do:",[109,807,808,811,814,817],{},[46,809,810],{},"Write a proper description with screenshots (can't stress this one enough)",[46,812,813],{},"Understand a reviewers point of view when they make suggestions",[46,815,816],{},"Pre-address strange parts of your merge (we all have them)",[46,818,819,820,825],{},"Be open to ",[50,821,824],{"href":822,"rel":823},"https://handbook.gitlab.com/handbook/values/#collaboration",[],"collaboration"," on your work",[15,827,828],{},"Don't:",[109,830,831,834,837,840],{},[46,832,833],{},"\"plz merge\"",[46,835,836],{},"Forget to write a description with screenshots",[46,838,839],{},"Be closed off or take offense to suggestions",[46,841,842],{},"Forget to include any steps needed to get the build running or in other words(reduce burden where possible!)",[15,844,845,846,849],{},"Honestly, it's pretty simple to be a fair author of a merge request if you use a small amount of empathy and remember that the person reviewing your code ",[35,847,848],{},"gets nothing extra"," for their time spend reviewing their code. They just want to help take your merge to the next level.",[409,851,853],{"id":852},"reviewer-fairness","Reviewer Fairness",[15,855,856,857,862],{},"Being fair as a reviewers is a tad harder than being fair as an author. But why, I hear you ask? The issue is something called \"bias\" - or ",[50,858,861],{"href":859,"rel":860},"https://handbook.gitlab.com/handbook/values/#unconscious-bias",[],"unconscious-bias",", as the handbook defines it.",[15,864,865,866,869],{},"Bias is, for better or for worse, something we all deal with when it comes to how we ",[27,867,868],{},"want"," things to be. We all have our own styles, preferences, and ideas on how software should be written:",[12,871,872],{},[15,873,874],{},"Eslint be damned I want you to use double quotes!",[15,876,877],{},"This creates issues when it comes to code reviews, because it's normal for a lot of your own bias to bleed into a comment. You begin thinking in absolutes and the unresolved discussion count rises.",[15,879,880],{},"Let me ask you something. Have you ever reviewed a merge request and found yourself saying things like:",[109,882,883,886,889,896],{},[46,884,885],{},"\"It should be written like this?\"",[46,887,888],{},"\"Why would they do it like that?\"",[46,890,891,892,895],{},"\"I would have done it ",[27,893,894],{},"this"," way.\"",[46,897,898],{},"\"That's not how that should be done!\"",[15,900,901],{},"Well, my friends, welcome to another common cognitive distortion called \"Should/must statements\". Do you want to be a better code reviewer? The next time you write a comment and it includes the word \"should\" or \"must\", pause right there and really think about why you felt the need to use that word. Sometimes it will be fair and warranted - such as if your company follows a set of coding conventions like we do at GitLab - but stay vigilant for when those statements are a thin veil for a personal preference. Ask yourself if you're being fair with your review. As a reviewer, if you find yourself in need of using a should/must statement, be sure to supply a reference to supporting documentation that is driving your statement.",[15,903,904,905,908,909,912],{},"One lesson I have learned through my own experience is that there is almost always a reason for something to be done the way it is. The fair response to something you don't agree with is to ask ",[27,906,907],{},"why"," it's being done like that, not saying it ",[27,910,911],{},"must"," be another way. That is how you become a fair and great negotiator.",[66,914,916],{"id":915},"the-follow-up","The Follow Up",[12,918,919],{},[15,920,921,922,80],{},"I feel like the follow up issue should become a first class citizen. - Sarah Yasonik (",[50,923,926],{"href":924,"rel":925},"https://gitlab.com/syasonik",[],"@syasonik",[15,928,929,930,935,936,941,942,55],{},"Long merges suck. They just do. And while the concept of \"big doesn't always mean good\" might have started with food, it bleeds into the world of software development through merge requests that are too big. They also directly conflict one of our ",[50,931,934],{"href":932,"rel":933},"https://handbook.gitlab.com/handbook/values/#make-small-merge-requests",[],"main values"," of iteration. In GitLab, we take this so seriously that ",[50,937,940],{"href":938,"rel":939},"https://docs.gitlab.com/development/dangerbot/",[],"Danger Bot"," will ask you to break down merges that are over a certain size, helping developers champion the ",[50,943,946],{"href":944,"rel":945},"https://handbook.gitlab.com/handbook/values/#iteration",[],"value of iteration",[15,948,949],{},"Large merge requests create huge amounts of complexity, they're hard to test, they're hard to reason about, they hard to maintain or extend.....and that's just for the author!",[15,951,952],{},"So what's worse than a large merge request? Reviewing a large merge request. If you've ever been pinged to review a merge request that was longer than 1000 lines, you understand what I am talking about. If it hasn't happened to you yet, count your lucky stars that your teammates live and breathe some good habits like simple solutions and iteration, and value a lack of complexity.",[15,954,955,956,959],{},"This creates a bigger problem than a complex reading exercise for the reviewer: it creates a context block. When a review grows past a certain amount of lines, it simply becomes too difficult to reason about without checking out the branch, booting the project and smoke testing. While smoke testing complex reviews are a great idea, it should ",[35,957,958],{},"not"," become the default ideal for reviewing.",[15,961,962],{},"If the merge request is too long, the code review is too complex / too long. The code rots, your merge conflicts grow, you can't iterate, you're constantly addressing breaking conflicts … and you're stuck for days, maybe weeks, maybe forever.",[15,964,965,966,969],{},"So how do we fix this? In the Monitor:Health team's iteration retrospective, my teammate Sarah Yasonik (",[50,967,926],{"href":924,"rel":968},[],") raised a point where she suggested the follow up issue / merge become a first class citizen. I thought she was onto something amazing. If your merge is too long, or your reviews are taking too long, break your merge down, keep the reviews small, and offer follow-ups.",[15,971,972,973,976,977,979],{},"Treat the follow-up merge as a first-class citizen. Do it right there ",[27,974,975],{},"while reading the reviewer's feedback"," instead of adding more code to a already too big merge! Do ",[35,978,958],{}," make a already bloated merge even worse by adding more scope. Divide and conquer where possible.",[15,981,982],{},"I think a lot of developers and reviewers find this process difficult because it's a contract of faith:",[109,984,985,988],{},[46,986,987],{},"I, the author, promise to deliver a follow-up.",[46,989,990],{},"I, the reviewer, put myself on the line by taking your word that you will in fact fix this issue later.",[15,992,993],{},"It's scary, and lacks polish. I get it, but you should never let tomorrow's perfect stop today's progress because - spoiler alert - tomorrow isn't here, and we really only have today.",[409,995,997],{"id":996},"the-author-follow-up","The Author Follow Up",[15,999,1000],{},"If you offer a follow up, deliver it. It's your only rule but you cannot break it. Your credit for wilding the follow up resides solely in your consistent ability to deliver on your promises over time. As a author you should also work with your PMs and EMs to help prioritize the follow up as part of a wider team effort.",[409,1002,1004],{"id":1003},"the-reviewer-follow-up","The Reviewer Follow Up",[109,1006,1007,1010,1013,1016],{},[46,1008,1009],{},"If you are offered a follow up, accept it with grace and trust the developer to make good on their promise.",[46,1011,1012],{},"Be open to suggesting follow ups as part of your review.",[46,1014,1015],{},"Be patient with people.",[46,1017,1018],{},"Allow for wiggle room, but know when to say no. (A follow-up for a non-critical issue is fine, but not a blatant break that won't add more lines or context.)",[66,1020,1022],{"id":1021},"the-art-of-the-gif","The Art Of The GIF",[12,1024,1025],{},[15,1026,1027],{},"If a Picture Speaks 1,000 Words a animated GIF Speaks 100,000.",[15,1029,1030],{},"While this is the least technical aspect of the entire post it is perhaps the most interesting and the easiest to implement.",[15,1032,1033],{},"Did you know that 93% of communication is nonverbal? I didn't, until I started seeing GIFs in code reviews. When I began to see them pop up in reviews, they deeply caught my attention, and I began to wonder why they had such a lasting impression on me as a developer.",[15,1035,1036,1037,1040],{},"Words are powerful, but images are particularly powerful because of their ties to our emotions. Images have the potential to create powerful emotional responses, and when you see something that sparks a sense of positivity, it sets the tone for the entire review. You ",[35,1038,1039],{},"understand fully"," that the reviewer really cares and wants to communicate that care non-verbally.",[15,1042,1043,1044,1049],{},"So how do you use GIFs in your merge requests and code reviews? Well, you could ",[50,1045,1048],{"href":1046,"rel":1047},"https://handbook.gitlab.com/handbook/product/product-processes/making-gifs/",[],"start with our handbook instructions",", but the short and sweet version:",[43,1051,1052,1055,1063],{},[46,1053,1054],{},"Use a screen recorder to capture the video you want to show as a GIF.",[46,1056,1057,1058,55],{},"Grab yourself a copy of ",[50,1059,1062],{"href":1060,"rel":1061},"https://github.com/vvo/gifify",[],"gifify",[46,1064,1065],{},"GIF all day long!",[409,1067,1069],{"id":1068},"gifs-that-show-you-care","GIFs That Show You Care",[15,1071,1072,1073,1078,1079,1082],{},"I won't ever forget the first time I saw a ",[50,1074,1077],{"href":1075,"rel":1076},"https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1193#note_307290889",[],"funny GIF in a code review",". I never even made it to reading the comment, because all I could comprehend was this animated GIF of a thumbs-up and I remember thinking: ",[27,1080,1081],{},"This merge would pass review. It would all be okay."," The sheer childlike giddy nature of seeing this image in action made me smile ear-to-ear. Every other comment could have been a rant about how awful my code was, but I wouldn't have cared.",[15,1084,1085],{},"If I can give you one piece of advice for your code reviews as a reviewer, use GIFs in a light-hearted way, because they are:",[109,1087,1088,1091,1094,1097],{},[46,1089,1090],{},"empathy-laden",[46,1092,1093],{},"soften the blow of a hard topic",[46,1095,1096],{},"foster positivity",[46,1098,1099],{},"make code reviews fun!",[15,1101,1102],{},[101,1103],{"alt":1104,"src":1105},"teamwork","https://media.giphy.com/media/vcHTRiZOglHNu/giphy.gif",[15,1107,1108,1109,1114],{},"We're currently looking at making ",[50,1110,1113],{"href":1111,"rel":1112},"https://gitlab.com/gitlab-org/gitlab/-/issues/17379",[],"Giphy a integrated feature here at GitLab",", making your code reviews even easier and more fun!",[66,1116,1118],{"id":1117},"tactical-code-reviews-through-the-value-of-iteration","Tactical code reviews through the value of iteration",[12,1120,1121],{},[15,1122,1123,1124,80],{},"Can we make this smaller? - Clement Ho(",[50,1125,1128],{"href":1126,"rel":1127},"https://gitlab.com/ClemMakesApps",[],"@ClemMakesApps",[15,1130,1131,1132,1135],{},"One thing I have noticed that help time and time again for better code reviews is the idea of breaking down a merge request into the smallest piece possible. A few people in my time here at GitLab have really put this across as a valuable way of working, but it was my frontend engineering manager Clement Ho(",[50,1133,1128],{"href":1126,"rel":1134},[],") that I really took notice championing this ideal. Given that I started paying close attention to this idea and began to notice benefits almost immediately when implementing the idea.",[15,1137,1138,1139,1144],{},"If we look at the GitLab value handbook's ",[50,1140,1143],{"href":1141,"rel":1142},"https://handbook.gitlab.com/handbook/values/#iteration-competency",[],"suggestions iteration competency"," you can see that the value in small, digestible merge requests which translates into smaller code reviews:",[15,1146,1147],{},"| Level | Demonstrates Iteration Competency by… |\n|",[1149,1150,1151],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}",{"title":224,"searchDepth":283,"depth":283,"links":1153},[1154,1155,1156,1161,1165,1169,1172],{"id":68,"depth":283,"text":69},{"id":155,"depth":283,"text":156},{"id":384,"depth":283,"text":385,"children":1157},[1158,1159,1160],{"id":411,"depth":290,"text":412},{"id":604,"depth":290,"text":605},{"id":713,"depth":290,"text":714},{"id":755,"depth":283,"text":756,"children":1162},[1163,1164],{"id":798,"depth":290,"text":799},{"id":852,"depth":290,"text":853},{"id":915,"depth":283,"text":916,"children":1166},[1167,1168],{"id":996,"depth":290,"text":997},{"id":1003,"depth":290,"text":1004},{"id":1021,"depth":283,"text":1022,"children":1170},[1171],{"id":1068,"depth":290,"text":1069},{"id":1117,"depth":283,"text":1118},"unfiltered","2020-06-08","Better Code Reviews - A selection of tools for your tool-belt when it comes to code reviews.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663502/Blog/Hero%20Images/paperclips.jpg",{},"/en-us/blog/better-code-reviews",{"title":5,"description":1175,"ogTitle":5,"ogDescription":1175,"noIndex":1178,"ogImage":1179,"ogUrl":1183,"ogSiteName":1184,"ogType":1185,"canonicalUrls":1183},"https://about.gitlab.com/blog/better-code-reviews","https://about.gitlab.com","article","better-code-reviews","en-us/blog/better-code-reviews",[1189,1190,1191],"code review","zero trust","GitOps","BlogPost","do30A2wterZT6vvRXHocbKxfViC6bFyIwoWUeRkqp9U",{"logo":1195,"freeTrial":1200,"sales":1205,"login":1210,"items":1215,"search":1542,"minimal":1573,"duo":1592,"switchNav":1601,"pricingDeployment":1612},{"config":1196},{"href":1197,"dataGaName":1198,"dataGaLocation":1199},"/","gitlab logo","header",{"text":1201,"config":1202},"Get free trial",{"href":1203,"dataGaName":1204,"dataGaLocation":1199},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":1206,"config":1207},"Request a demo",{"href":1208,"dataGaName":1209,"dataGaLocation":1199},"/sales/?contact-topic=request-demo","sales",{"text":1211,"config":1212},"Sign in",{"href":1213,"dataGaName":1214,"dataGaLocation":1199},"https://gitlab.com/users/sign_in/","sign in",[1216,1245,1345,1350,1464,1520],{"text":1217,"config":1218,"menu":1220},"Platform",{"dataNavLevelOne":1219},"platform",{"type":1221,"columns":1222},"cards",[1223,1229,1237],{"title":1217,"description":1224,"link":1225},"The intelligent orchestration platform for DevSecOps",{"text":1226,"config":1227},"Explore our Platform",{"href":1228,"dataGaName":1219,"dataGaLocation":1199},"/platform/",{"title":1230,"description":1231,"link":1232},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":1233,"config":1234},"Meet GitLab Duo",{"href":1235,"dataGaName":1236,"dataGaLocation":1199},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":1238,"description":1239,"link":1240},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":1241,"config":1242},"Learn more",{"href":1243,"dataGaName":1244,"dataGaLocation":1199},"/why-gitlab/","why gitlab",{"text":1246,"left":286,"config":1247,"menu":1249},"Product",{"dataNavLevelOne":1248},"solutions",{"type":1250,"link":1251,"columns":1255,"feature":1324},"lists",{"text":1252,"config":1253},"View all Solutions",{"href":1254,"dataGaName":1248,"dataGaLocation":1199},"/solutions/",[1256,1280,1303],{"title":1257,"description":1258,"link":1259,"items":1264},"Automation","CI/CD and automation to accelerate deployment",{"config":1260},{"icon":1261,"href":1262,"dataGaName":1263,"dataGaLocation":1199},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[1265,1269,1272,1276],{"text":1266,"config":1267},"CI/CD",{"href":1268,"dataGaLocation":1199,"dataGaName":1266},"/solutions/continuous-integration/",{"text":1230,"config":1270},{"href":1235,"dataGaLocation":1199,"dataGaName":1271},"gitlab duo agent platform - product menu",{"text":1273,"config":1274},"Source Code Management",{"href":1275,"dataGaLocation":1199,"dataGaName":1273},"/solutions/source-code-management/",{"text":1277,"config":1278},"Automated Software Delivery",{"href":1262,"dataGaLocation":1199,"dataGaName":1279},"Automated software delivery",{"title":1281,"description":1282,"link":1283,"items":1288},"Security","Deliver code faster without compromising security",{"config":1284},{"href":1285,"dataGaName":1286,"dataGaLocation":1199,"icon":1287},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[1289,1293,1298],{"text":1290,"config":1291},"Application Security Testing",{"href":1285,"dataGaName":1292,"dataGaLocation":1199},"Application security testing",{"text":1294,"config":1295},"Software Supply Chain Security",{"href":1296,"dataGaLocation":1199,"dataGaName":1297},"/solutions/supply-chain/","Software supply chain security",{"text":1299,"config":1300},"Software Compliance",{"href":1301,"dataGaName":1302,"dataGaLocation":1199},"/solutions/software-compliance/","software compliance",{"title":1304,"link":1305,"items":1310},"Measurement",{"config":1306},{"icon":1307,"href":1308,"dataGaName":1309,"dataGaLocation":1199},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[1311,1315,1319],{"text":1312,"config":1313},"Visibility & Measurement",{"href":1308,"dataGaLocation":1199,"dataGaName":1314},"Visibility and Measurement",{"text":1316,"config":1317},"Value Stream Management",{"href":1318,"dataGaLocation":1199,"dataGaName":1316},"/solutions/value-stream-management/",{"text":1320,"config":1321},"Analytics & Insights",{"href":1322,"dataGaLocation":1199,"dataGaName":1323},"/solutions/analytics-and-insights/","Analytics and insights",{"title":1325,"type":1250,"items":1326},"GitLab for",[1327,1333,1339],{"text":1328,"config":1329},"Enterprise",{"icon":1330,"href":1331,"dataGaLocation":1199,"dataGaName":1332},"Building","/enterprise/","enterprise",{"text":1334,"config":1335},"Small Business",{"icon":1336,"href":1337,"dataGaLocation":1199,"dataGaName":1338},"Work","/small-business/","small business",{"text":1340,"config":1341},"Public Sector",{"icon":1342,"href":1343,"dataGaLocation":1199,"dataGaName":1344},"Organization","/solutions/public-sector/","public sector",{"text":1346,"config":1347},"Pricing",{"href":1348,"dataGaName":1349,"dataGaLocation":1199,"dataNavLevelOne":1349},"/pricing/","pricing",{"text":1351,"config":1352,"menu":1354},"Resources",{"dataNavLevelOne":1353},"resources",{"type":1250,"link":1355,"columns":1359,"feature":1453},{"text":1356,"config":1357},"View all resources",{"href":1358,"dataGaName":1353,"dataGaLocation":1199},"/resources/",[1360,1393,1420],{"title":1361,"items":1362},"Getting started",[1363,1368,1373,1378,1383,1388],{"text":1364,"config":1365},"Install",{"href":1366,"dataGaName":1367,"dataGaLocation":1199},"/install/","install",{"text":1369,"config":1370},"Quick start guides",{"href":1371,"dataGaName":1372,"dataGaLocation":1199},"/get-started/","quick setup checklists",{"text":1374,"config":1375},"Learn",{"href":1376,"dataGaLocation":1199,"dataGaName":1377},"https://university.gitlab.com/","learn",{"text":1379,"config":1380},"Product documentation",{"href":1381,"dataGaName":1382,"dataGaLocation":1199},"https://docs.gitlab.com/","product documentation",{"text":1384,"config":1385},"Best practice videos",{"href":1386,"dataGaName":1387,"dataGaLocation":1199},"/getting-started-videos/","best practice videos",{"text":1389,"config":1390},"Integrations",{"href":1391,"dataGaName":1392,"dataGaLocation":1199},"/integrations/","integrations",{"title":1394,"items":1395},"Discover",[1396,1401,1406,1411,1415],{"text":1397,"config":1398},"Customer success stories",{"href":1399,"dataGaName":1400,"dataGaLocation":1199},"/customers/","customer success stories",{"text":1402,"config":1403},"Blog",{"href":1404,"dataGaName":1405,"dataGaLocation":1199},"/blog/","blog",{"text":1407,"config":1408},"Demo Hub",{"href":1409,"dataGaName":1410,"dataGaLocation":1199},"/demo-hub/","demo hub",{"text":1412,"config":1413},"The Source",{"href":1414,"dataGaName":1405,"dataGaLocation":1199},"/the-source/",{"text":1416,"config":1417},"Remote",{"href":1418,"dataGaName":1419,"dataGaLocation":1199},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1421,"items":1422},"Connect",[1423,1428,1433,1438,1443,1448],{"text":1424,"config":1425},"GitLab Services",{"href":1426,"dataGaName":1427,"dataGaLocation":1199},"/services/","services",{"text":1429,"config":1430},"Contribute",{"href":1431,"dataGaName":1432,"dataGaLocation":1199},"https://contributors.gitlab.com","contribute",{"text":1434,"config":1435},"Community",{"href":1436,"dataGaName":1437,"dataGaLocation":1199},"/community/","community",{"text":1439,"config":1440},"Forum",{"href":1441,"dataGaName":1442,"dataGaLocation":1199},"https://forum.gitlab.com/","forum",{"text":1444,"config":1445},"Events",{"href":1446,"dataGaName":1447,"dataGaLocation":1199},"/events/","events",{"text":1449,"config":1450},"Partners",{"href":1451,"dataGaName":1452,"dataGaLocation":1199},"/partners/","partners",{"config":1454,"title":1457,"text":1458,"link":1459},{"background":1455,"textColor":1456},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1460,"config":1461},"Read the latest",{"href":1462,"dataGaName":1463,"dataGaLocation":1199},"/whats-new/","whats new",{"text":1465,"config":1466,"menu":1468},"Company",{"dataNavLevelOne":1467},"company",{"type":1250,"columns":1469},[1470],{"items":1471},[1472,1477,1483,1485,1490,1495,1500,1505,1510,1515],{"text":1473,"config":1474},"About",{"href":1475,"dataGaName":1476,"dataGaLocation":1199},"/company/","about",{"text":1478,"config":1479,"footerGa":1482},"Jobs",{"href":1480,"dataGaName":1481,"dataGaLocation":1199},"/jobs/","jobs",{"dataGaName":1481},{"text":1444,"config":1484},{"href":1446,"dataGaName":1447,"dataGaLocation":1199},{"text":1486,"config":1487},"Leadership",{"href":1488,"dataGaName":1489,"dataGaLocation":1199},"/company/team/e-group/","leadership",{"text":1491,"config":1492},"Handbook",{"href":1493,"dataGaName":1494,"dataGaLocation":1199},"https://handbook.gitlab.com/","handbook",{"text":1496,"config":1497},"Investor relations",{"href":1498,"dataGaName":1499,"dataGaLocation":1199},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1501,"config":1502},"Trust Center",{"href":1503,"dataGaName":1504,"dataGaLocation":1199},"/security/","trust center",{"text":1506,"config":1507},"AI Transparency Center",{"href":1508,"dataGaName":1509,"dataGaLocation":1199},"/ai-transparency-center/","ai transparency center",{"text":1511,"config":1512},"Newsletter",{"href":1513,"dataGaName":1514,"dataGaLocation":1199},"/company/contact/#contact-forms","newsletter",{"text":1516,"config":1517},"Press",{"href":1518,"dataGaName":1519,"dataGaLocation":1199},"/press/","press",{"text":1521,"config":1522,"menu":1523},"Contact us",{"dataNavLevelOne":1467},{"type":1250,"columns":1524},[1525],{"items":1526},[1527,1532,1537],{"text":1528,"config":1529},"Talk to sales",{"href":1530,"dataGaName":1531,"dataGaLocation":1199},"/sales/","talk to sales",{"text":1533,"config":1534},"Support portal",{"href":1535,"dataGaName":1536,"dataGaLocation":1199},"https://support.gitlab.com/hc/en-us","support portal",{"text":1538,"config":1539},"Customer portal",{"href":1540,"dataGaName":1541,"dataGaLocation":1199},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1543,"login":1544,"suggestions":1551},"Close",{"text":1545,"link":1546},"To search repositories and projects, login to",{"text":1547,"config":1548},"gitlab.com",{"href":1213,"dataGaName":1549,"dataGaLocation":1550},"search login","search",{"text":1552,"default":1553},"Suggestions",[1554,1556,1560,1562,1566,1570],{"text":1230,"config":1555},{"href":1235,"dataGaName":1230,"dataGaLocation":1550},{"text":1557,"config":1558},"Code Suggestions (AI)",{"href":1559,"dataGaName":1557,"dataGaLocation":1550},"/solutions/code-suggestions/",{"text":1266,"config":1561},{"href":1268,"dataGaName":1266,"dataGaLocation":1550},{"text":1563,"config":1564},"GitLab on AWS",{"href":1565,"dataGaName":1563,"dataGaLocation":1550},"/partners/technology-partners/aws/",{"text":1567,"config":1568},"GitLab on Google Cloud",{"href":1569,"dataGaName":1567,"dataGaLocation":1550},"/partners/technology-partners/google-cloud-platform/",{"text":1571,"config":1572},"Why GitLab?",{"href":1243,"dataGaName":1571,"dataGaLocation":1550},{"freeTrial":1574,"mobileIcon":1579,"desktopIcon":1584,"secondaryButton":1587},{"text":1575,"config":1576},"Start free trial",{"href":1577,"dataGaName":1204,"dataGaLocation":1578},"https://gitlab.com/-/trials/new/","nav",{"altText":1580,"config":1581},"Gitlab Icon",{"src":1582,"dataGaName":1583,"dataGaLocation":1578},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1580,"config":1585},{"src":1586,"dataGaName":1583,"dataGaLocation":1578},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1588,"config":1589},"Get Started",{"href":1590,"dataGaName":1591,"dataGaLocation":1578},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1593,"mobileIcon":1597,"desktopIcon":1599},{"text":1594,"config":1595},"Learn more about GitLab Duo",{"href":1235,"dataGaName":1596,"dataGaLocation":1578},"gitlab duo",{"altText":1580,"config":1598},{"src":1582,"dataGaName":1583,"dataGaLocation":1578},{"altText":1580,"config":1600},{"src":1586,"dataGaName":1583,"dataGaLocation":1578},{"button":1602,"mobileIcon":1607,"desktopIcon":1609},{"text":1603,"config":1604},"/switch",{"href":1605,"dataGaName":1606,"dataGaLocation":1578},"#contact","switch",{"altText":1580,"config":1608},{"src":1582,"dataGaName":1583,"dataGaLocation":1578},{"altText":1580,"config":1610},{"src":1611,"dataGaName":1583,"dataGaLocation":1578},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1613,"mobileIcon":1618,"desktopIcon":1620},{"text":1614,"config":1615},"Back to pricing",{"href":1348,"dataGaName":1616,"dataGaLocation":1578,"icon":1617},"back to pricing","GoBack",{"altText":1580,"config":1619},{"src":1582,"dataGaName":1583,"dataGaLocation":1578},{"altText":1580,"config":1621},{"src":1586,"dataGaName":1583,"dataGaLocation":1578},{"title":1623,"titleMobile":1624,"button":1625,"config":1630},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":1241,"config":1626},{"href":1627,"dataGaName":1628,"dataGaLocation":1629},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1631,"disabled":1178},"release",{"data":1633},{"text":1634,"source":1635,"edit":1641,"contribute":1646,"config":1651,"items":1656,"minimal":1865},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1636,"config":1637},"View page source",{"href":1638,"dataGaName":1639,"dataGaLocation":1640},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1642,"config":1643},"Edit this page",{"href":1644,"dataGaName":1645,"dataGaLocation":1640},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1647,"config":1648},"Please contribute",{"href":1649,"dataGaName":1650,"dataGaLocation":1640},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1652,"facebook":1653,"youtube":1654,"linkedin":1655},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1657,1704,1757,1801,1833],{"title":1346,"links":1658,"subMenu":1673},[1659,1663,1668],{"text":1660,"config":1661},"View plans",{"href":1348,"dataGaName":1662,"dataGaLocation":1640},"view plans",{"text":1664,"config":1665},"Why Premium?",{"href":1666,"dataGaName":1667,"dataGaLocation":1640},"/pricing/premium/","why premium",{"text":1669,"config":1670},"Why Ultimate?",{"href":1671,"dataGaName":1672,"dataGaLocation":1640},"/pricing/ultimate/","why ultimate",[1674],{"title":1675,"links":1676},"Contact Us",[1677,1680,1682,1684,1689,1694,1699],{"text":1678,"config":1679},"Contact sales",{"href":1530,"dataGaName":1209,"dataGaLocation":1640},{"text":1533,"config":1681},{"href":1535,"dataGaName":1536,"dataGaLocation":1640},{"text":1538,"config":1683},{"href":1540,"dataGaName":1541,"dataGaLocation":1640},{"text":1685,"config":1686},"Status",{"href":1687,"dataGaName":1688,"dataGaLocation":1640},"https://status.gitlab.com/","status",{"text":1690,"config":1691},"Terms of use",{"href":1692,"dataGaName":1693,"dataGaLocation":1640},"/terms/","terms of use",{"text":1695,"config":1696},"Privacy statement",{"href":1697,"dataGaName":1698,"dataGaLocation":1640},"/privacy/","privacy statement",{"text":1700,"config":1701},"Cookie preferences",{"dataGaName":1702,"dataGaLocation":1640,"id":1703,"isOneTrustButton":286},"cookie preferences","ot-sdk-btn",{"title":1246,"links":1705,"subMenu":1714},[1706,1710],{"text":1707,"config":1708},"DevSecOps platform",{"href":1228,"dataGaName":1709,"dataGaLocation":1640},"devsecops platform",{"text":1711,"config":1712},"AI-Assisted Development",{"href":1235,"dataGaName":1713,"dataGaLocation":1640},"ai-assisted development",[1715],{"title":1716,"links":1717},"Topics",[1718,1723,1727,1732,1737,1742,1747,1752],{"text":1719,"config":1720},"CICD",{"href":1721,"dataGaName":1722,"dataGaLocation":1640},"/topics/ci-cd/","cicd",{"text":1191,"config":1724},{"href":1725,"dataGaName":1726,"dataGaLocation":1640},"/topics/gitops/","gitops",{"text":1728,"config":1729},"DevOps",{"href":1730,"dataGaName":1731,"dataGaLocation":1640},"/topics/devops/","devops",{"text":1733,"config":1734},"Version Control",{"href":1735,"dataGaName":1736,"dataGaLocation":1640},"/topics/version-control/","version control",{"text":1738,"config":1739},"DevSecOps",{"href":1740,"dataGaName":1741,"dataGaLocation":1640},"/topics/devsecops/","devsecops",{"text":1743,"config":1744},"Cloud Native",{"href":1745,"dataGaName":1746,"dataGaLocation":1640},"/topics/cloud-native/","cloud native",{"text":1748,"config":1749},"AI for Coding",{"href":1750,"dataGaName":1751,"dataGaLocation":1640},"/topics/devops/ai-for-coding/","ai for coding",{"text":1753,"config":1754},"Agentic AI",{"href":1755,"dataGaName":1756,"dataGaLocation":1640},"/topics/agentic-ai/","agentic ai",{"title":1758,"links":1759},"Solutions",[1760,1762,1764,1769,1773,1776,1780,1783,1785,1788,1791,1796],{"text":1290,"config":1761},{"href":1285,"dataGaName":1290,"dataGaLocation":1640},{"text":1279,"config":1763},{"href":1262,"dataGaName":1263,"dataGaLocation":1640},{"text":1765,"config":1766},"Agile development",{"href":1767,"dataGaName":1768,"dataGaLocation":1640},"/solutions/agile-delivery/","agile delivery",{"text":1770,"config":1771},"SCM",{"href":1275,"dataGaName":1772,"dataGaLocation":1640},"source code management",{"text":1719,"config":1774},{"href":1268,"dataGaName":1775,"dataGaLocation":1640},"continuous integration & delivery",{"text":1777,"config":1778},"Value stream management",{"href":1318,"dataGaName":1779,"dataGaLocation":1640},"value stream management",{"text":1191,"config":1781},{"href":1782,"dataGaName":1726,"dataGaLocation":1640},"/solutions/gitops/",{"text":1328,"config":1784},{"href":1331,"dataGaName":1332,"dataGaLocation":1640},{"text":1786,"config":1787},"Small business",{"href":1337,"dataGaName":1338,"dataGaLocation":1640},{"text":1789,"config":1790},"Public sector",{"href":1343,"dataGaName":1344,"dataGaLocation":1640},{"text":1792,"config":1793},"Education",{"href":1794,"dataGaName":1795,"dataGaLocation":1640},"/solutions/education/","education",{"text":1797,"config":1798},"Financial services",{"href":1799,"dataGaName":1800,"dataGaLocation":1640},"/solutions/finance/","financial services",{"title":1351,"links":1802},[1803,1805,1807,1809,1812,1814,1817,1819,1821,1823,1825,1827,1829,1831],{"text":1364,"config":1804},{"href":1366,"dataGaName":1367,"dataGaLocation":1640},{"text":1369,"config":1806},{"href":1371,"dataGaName":1372,"dataGaLocation":1640},{"text":1374,"config":1808},{"href":1376,"dataGaName":1377,"dataGaLocation":1640},{"text":1379,"config":1810},{"href":1381,"dataGaName":1811,"dataGaLocation":1640},"docs",{"text":1402,"config":1813},{"href":1404,"dataGaName":1405,"dataGaLocation":1640},{"text":1815,"config":1816},"What's new",{"href":1462,"dataGaName":1463,"dataGaLocation":1640},{"text":1397,"config":1818},{"href":1399,"dataGaName":1400,"dataGaLocation":1640},{"text":1416,"config":1820},{"href":1418,"dataGaName":1419,"dataGaLocation":1640},{"text":1424,"config":1822},{"href":1426,"dataGaName":1427,"dataGaLocation":1640},{"text":1429,"config":1824},{"href":1431,"dataGaName":1432,"dataGaLocation":1640},{"text":1434,"config":1826},{"href":1436,"dataGaName":1437,"dataGaLocation":1640},{"text":1439,"config":1828},{"href":1441,"dataGaName":1442,"dataGaLocation":1640},{"text":1444,"config":1830},{"href":1446,"dataGaName":1447,"dataGaLocation":1640},{"text":1449,"config":1832},{"href":1451,"dataGaName":1452,"dataGaLocation":1640},{"title":1465,"links":1834},[1835,1837,1839,1841,1843,1845,1849,1854,1856,1858,1860],{"text":1473,"config":1836},{"href":1475,"dataGaName":1467,"dataGaLocation":1640},{"text":1478,"config":1838},{"href":1480,"dataGaName":1481,"dataGaLocation":1640},{"text":1486,"config":1840},{"href":1488,"dataGaName":1489,"dataGaLocation":1640},{"text":1491,"config":1842},{"href":1493,"dataGaName":1494,"dataGaLocation":1640},{"text":1496,"config":1844},{"href":1498,"dataGaName":1499,"dataGaLocation":1640},{"text":1846,"config":1847},"Sustainability",{"href":1848,"dataGaName":1846,"dataGaLocation":1640},"/sustainability/",{"text":1850,"config":1851},"Diversity, inclusion and belonging (DIB)",{"href":1852,"dataGaName":1853,"dataGaLocation":1640},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1501,"config":1855},{"href":1503,"dataGaName":1504,"dataGaLocation":1640},{"text":1511,"config":1857},{"href":1513,"dataGaName":1514,"dataGaLocation":1640},{"text":1516,"config":1859},{"href":1518,"dataGaName":1519,"dataGaLocation":1640},{"text":1861,"config":1862},"Modern Slavery Transparency Statement",{"href":1863,"dataGaName":1864,"dataGaLocation":1640},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1866},[1867,1870,1873],{"text":1868,"config":1869},"Terms",{"href":1692,"dataGaName":1693,"dataGaLocation":1640},{"text":1871,"config":1872},"Cookies",{"dataGaName":1702,"dataGaLocation":1640,"id":1703,"isOneTrustButton":286},{"text":1874,"config":1875},"Privacy",{"href":1697,"dataGaName":1698,"dataGaLocation":1640},[1877],{"id":1878,"title":1879,"body":1177,"config":1880,"content":1882,"description":1177,"extension":1886,"meta":1887,"navigation":286,"path":1888,"seo":1889,"stem":1890,"__hash__":1891},"blogAuthors/en-us/blog/authors/david-oregan.yml","David Oregan",{"template":1881},"BlogAuthor",{"name":7,"config":1883},{"headshot":1884,"ctfId":1885},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659853/Blog/Author%20Headshots/oregand-headshot.png","oregand","yml",{},"/en-us/blog/authors/david-oregan",{},"en-us/blog/authors/david-oregan","CX5gLc3Gs5FrmvpMNVkBtC5zRi3vj8l3wJGnW0iSa6Y",[1893,1901,1909],{"title":1894,"description":1895,"heroImage":1896,"category":1173,"date":1897,"authors":1898,"slug":1900,"externalUrl":1177},"CEO Shadow Takeaways from Jacie","Recap of my experience in the CEO Shadow Program.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664102/Blog/Hero%20Images/gitlab-values-cover.png","2021-05-18",[1899],"Jacie Bandur","ceo-shadow-recap",{"title":1902,"description":1903,"heroImage":1904,"category":1173,"date":1905,"authors":1906,"slug":1908,"externalUrl":1177},"Why I love contributing to GitLab","Making small meaningful changes is what it's all about.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679501/Blog/Hero%20Images/new-feature.png","2021-05-11",[1907],"Austin Regnery","why-i-love-contributing-to-gitlab",{"title":1910,"description":1911,"heroImage":1912,"category":1173,"date":1905,"authors":1913,"slug":1915,"externalUrl":1177},"Placebo Lines on the Pipeline Graph","Have you noticed the connecting lines missing on your pipelines lately? Here's why","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679507/Blog/Hero%20Images/ci-cd.png",[1914],"Sam Beckham","placebo-lines-on-the-pipeline-graph",{"promotions":1917},[1918,1932,1944,1956],{"id":1919,"categories":1920,"header":1922,"text":1923,"button":1924,"image":1929},"ai-modernization",[1921],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1925,"config":1926},"Get your AI maturity score",{"href":1927,"dataGaName":1928,"dataGaLocation":1405},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1930},{"src":1931},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1933,"categories":1934,"header":1936,"text":1923,"button":1937,"image":1941},"devops-modernization",[1935,1741],"product","Are you just managing tools or shipping innovation?",{"text":1938,"config":1939},"Get your DevOps maturity score",{"href":1940,"dataGaName":1928,"dataGaLocation":1405},"/assessments/devops-modernization-assessment/",{"config":1942},{"src":1943},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1945,"categories":1946,"header":1948,"text":1923,"button":1949,"image":1953},"security-modernization",[1947],"security","Are you trading speed for security?",{"text":1950,"config":1951},"Get your security maturity score",{"href":1952,"dataGaName":1928,"dataGaLocation":1405},"/assessments/security-modernization-assessment/",{"config":1954},{"src":1955},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1957,"paths":1958,"header":1961,"text":1962,"button":1963,"image":1968},"github-azure-migration",[1959,1960],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1964,"config":1965},"See how GitLab compares to GitHub",{"href":1966,"dataGaName":1967,"dataGaLocation":1405},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1969},{"src":1943},{"header":1971,"blurb":1972,"button":1973,"secondaryButton":1978},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1974,"config":1975},"Get your free trial",{"href":1976,"dataGaName":1204,"dataGaLocation":1977},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1678,"config":1979},{"href":1530,"dataGaName":1209,"dataGaLocation":1977},1786803747357]