# RetailMeNot

At ZMG, we know tech no longer simply drives culture in today's hyper-connected world, tech is culture. Understanding and embracing tech has become essential to how we live, how we work, how we have fun, how we shop, how we learn, and finally how we connect with world around us. - Medium

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## RetailMeNot GraphQL Federation

DevFeed: [RetailMeNot GraphQL Federation](<https://devfeed.tech/articles/retailmenot-graphql-federation-20365.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/retailmenot-graphql-federation-3bb36dac5aaa?source=rss----d6bb34696ef5---4>)

Author: Kartik Kumar Gujarati

Published: 2021-10-08T15:01:45Z

Content type: article

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [GraphQL](<https://devfeed.tech/topics/graphql.md>), [Back end](<https://devfeed.tech/topics/backend.md>), [Graphs](<https://devfeed.tech/topics/graphs.md>), [Android](<https://devfeed.tech/topics/android.md>), [iOS](<https://devfeed.tech/topics/ios.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [browser](<https://devfeed.tech/tags/browser.md>), [engineering](<https://devfeed.tech/tags/engineering.md>), [extension](<https://devfeed.tech/tags/extension.md>), [graphql](<https://devfeed.tech/tags/graphql.md>), [graphql-federation](<https://devfeed.tech/tags/graphql-federation.md>), [ios](<https://devfeed.tech/tags/ios.md>), [mobile](<https://devfeed.tech/tags/mobile.md>), [rest-api](<https://devfeed.tech/tags/rest-api.md>), [rest-apis](<https://devfeed.tech/tags/rest-apis.md>), [retailmenot](<https://devfeed.tech/tags/retailmenot.md>), [web](<https://devfeed.tech/tags/web.md>), [ziff-davis](<https://devfeed.tech/tags/ziff-davis.md>)

### AI overview

This article describes how RetailMeNot addressed REST API versioning, over-fetching, and under-fetching by adopting GraphQL and transitioning from a GraphQL monolith toward GraphQL Federation. It covers the company's application and backend rebuild across Android, iOS, web, and browser extension experiences.

### Source excerpt

Did you ever have to maintain multiple versions of a REST API because the change you needed to make would break existing clients? Does your native app have to call multiple REST endpoints to get all the data it needs? This blog post is about how we addressed these common problems using GraphQL and our transition to GraphQL Federation at RetailMeNot. RetailMeNot, part of Ziff Media, Inc, makes everyday life more affordable for shoppers. We are a leading savings destination providing online and in-store coupons and cashback offers to our users. Today, we serve millions of monthly active users from our desktop, mobile web, native (iOS & Android) apps, and browser extension (Deal Finder™) experiences. For the last 10 years, RetailMeNot's engineering teams have built several highly performant, scalable, and efficient systems to bring savings data to our users through our experiences. And like many companies, RetailMeNot used REST APIs to serve the data. However, as the company and the systems grew, we started to experience problems like versioning, over-fetching, and under-fetching with REST APIs. For more details on the classic problems that arise from REST services and how GraphQL solves them, see this blog post. For an introduction to GraphQL, see this blog post. How it started: A Monolithic Graph In 2019, we took a step back to rethink where we are headed in terms of our tech stack and how to best serve future experiences. We decided to rewrite our native Android and iOS apps and the backend that supports them. In addition to this, we also built a brand new browser extension (Deal Finder™) and re-wrote several parts of our core website. As we started to rebuild our native apps, we wanted to solve the above problems we faced with REST APIs. GraphQL seemed like a great solution for this. Enter GraphQL. In our first iteration with GraphQL, we built a GraphQL monolith. Monolith Graph The GraphQL Monolith at RetailMeNot was a single GraphQL Server used by our Native Andro

## Decreasing Applitools Android Boilerplate with Kotlin and JUnit

DevFeed: [Decreasing Applitools Android Boilerplate with Kotlin and JUnit](<https://devfeed.tech/articles/decreasing-applitools-android-boilerplate-with-kotlin-and-junit-20360.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/decreasing-applitools-android-boilerplate-with-kotlin-and-junit-46c61b5e10ce?source=rss----d6bb34696ef5---4>)

Author: Ben Boral

Published: 2019-11-15T17:46:53Z

Content type: tutorial

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [Boilerplate](<https://devfeed.tech/topics/boilerplate.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [SDKs](<https://devfeed.tech/topics/sdks.md>), [App](<https://devfeed.tech/topics/app.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [applitools](<https://devfeed.tech/tags/applitools.md>), [boilerplate](<https://devfeed.tech/tags/boilerplate.md>), [code](<https://devfeed.tech/tags/code.md>), [espresso](<https://devfeed.tech/tags/espresso.md>), [junit](<https://devfeed.tech/tags/junit.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [testing](<https://devfeed.tech/tags/testing.md>)

### AI overview

This tutorial shows how to reduce boilerplate in Applitools visual regression tests for Android by using Kotlin and JUnit. It describes encapsulating repeated setup and cleanup in a helper and JUnit rule so the test code is more concise and easier to maintain.

### Source excerpt

Background At RetailMeNot, we are excited by the promise of automating visual regression tests with Applitools. In this post, I'll show how to make writing Applitools tests for Android a cinch. We'll start with the official integration guide recommendations and then use JUnit and Kotlin features to make our tests concise and maintainable. This post assumes the reader is familiar with Applitools visual testing. Our Starting Point: lots of boilerplate code Applitools's official integration guide for Espresso recommends a test that looks approximately like the below code block. I'll explain each line of this snippet later in the article. But for now, notice the excessive setup code and cleanup code that's getting in the way of our actual test code. This boilerplate would need to be copied for every test. https://medium.com/media/c042e70c7b2c423afde35fc101bc6e31/hrefThe Solution: a much simpler test We can reduce the boilerplate to achieve the following test. By stripping away the setup and cleanup as much as possible, we are left with the kernel of the test. In doing so, the purpose of the test is much easier to comprehend. ApplitoolsHelper, on line 2, has encapsulated the setup and cleanup. This will make long-term maintenance easier, because when the Applitools APIs change, we'll only need to update them in the one location. https://medium.com/media/de1efe74c1f65542057b061fd3b4ad35/hrefThe Required Steps to Run an Applitools Test Before diving into the helper code that enables our concise test, let's review the steps involved in an Applitools visual test: val eyes = Eyes() eyes.apiKey = "YOUR_API_KEY" eyes.appName = "YOUR_APP_NAME" We must initialize the Applitools SDK and set our API key and app name. This is going to be the same for every test in our suite. We will extract this code into a JUnit test rule. eyes.open("TEST_NAME"); This starts the Applitools test session. This must be called with a unique test name for each test. We will use a lambda expression, expl

## Treat Testing Pain with a Healthy Dose of Test Strategy

DevFeed: [Treat Testing Pain with a Healthy Dose of Test Strategy](<https://devfeed.tech/articles/treat-testing-pain-with-a-healthy-dose-of-test-strategy-20366.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/treat-testing-pain-with-a-healthy-dose-of-test-strategy-43285deaad95?source=rss----d6bb34696ef5---4>)

Author: Jeff Benton

Published: 2019-10-22T16:12:57Z

Content type: tutorial

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [Unit testing](<https://devfeed.tech/topics/unit-testing.md>), [test-coverage](<https://devfeed.tech/topics/test-coverage.md>)

Tags: [coverage](<https://devfeed.tech/tags/coverage.md>), [diagnose](<https://devfeed.tech/tags/diagnose.md>), [flaky](<https://devfeed.tech/tags/flaky.md>), [integration](<https://devfeed.tech/tags/integration.md>), [test-coverage](<https://devfeed.tech/tags/test-coverage.md>), [testing](<https://devfeed.tech/tags/testing.md>), [unit-testing](<https://devfeed.tech/tags/unit-testing.md>)

### AI overview

The article presents test strategy as a low-cost way for engineering teams to diagnose testing problems and create a treatment plan. It discusses missing unit or integration tests, flaky or slow tests, maintainability issues, and test coverage pursued without clear value.

### Source excerpt

We live in a day and age where consumers cannot access medication for their ailment because of cost. We are aware of the anecdotes related to delaying treatment. In the same way, some engineering teams are stuck with projects which are in an unhealthy testing state. The team goes on sprint after sprint with the situation getting worse, not better. In this article, I will introduce a low-cost tool to enable you to diagnose your situation and put together a treatment plan. Testing pain It's a sad situation, but I think we've all been in the place where testing on our project is a pain. "belchonock" © 123RF.com It's a project where no one took the time to set up unit testing. Or the unit test framework exists and no one bothered to add unit tests. There are unit tests, but no integration tests. Or there is no support for the types of integration tests you want to write. The tests are flaky. They take too long. The tests are difficult to maintain or understand. The tests don't provide value and were added to hit a random test coverage number. After all the automated tests pass, you still have this nagging doubt about releasing the latest version to the public. The pain points I have called out above are not exhaustive. We can relate to these pain points, but why don't we fix them? We know ignoring a medical problem is not a good idea. It's not a good idea to ignore your testing pain. But choosing to tackle your testing problems can seem like a daunting task. A tool that I have found helpful to start dealing with my testing pain is to develop a test strategy. "Dejan Bozic" © 123RF.com Develop your Test Strategy A strategy is "A plan of action or policy designed to achieve a long-term or overall aim." (Definition of strategy in English. https://www.lexico.com/en/definition/strategy) A test strategy is a plan of action or policy designed to achieve a long-term testing aim. To develop a test strategy, start answering the following questions. What are the testing pain points

## Code Review Communication Tips for Reviewing Others' Code

DevFeed: [Code Review Communication Tips for Reviewing Others' Code](<https://devfeed.tech/articles/better-code-review-part-3-20357.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/better-code-review-part-3-4efb568885?source=rss----d6bb34696ef5---4>)

Author: Molly King

Published: 2019-01-18T22:35:25Z

Content type: opinion

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [Code review](<https://devfeed.tech/topics/code-review.md>)

Tags: [code-review](<https://devfeed.tech/tags/code-review.md>)

### AI overview

The article offers advice for communicating constructively when reviewing other developers' code. It recommends using inclusive language, asking "what" rather than "why," avoiding minimizing words such as "just" and "simply," and reconsidering emoji used to defuse tense comments.

### Source excerpt

Reviewing code Happy new year! The beginning of the year is a great time to reflect on our strengths, our accomplishments, and our areas of opportunity. Perhaps you've decided that code reviews are one of your areas of opportunity. Wonderful! I'm so glad you're here. I highly recommend checking out parts 1 and 2 of this series, as code review is a two-way street. Now that you're caught up, let's move onto part 3: reviewing others' code. What follows are a few tips and tricks that I've learned and (tried to) put into practice myself. Language mattersBeing condescending makes you look like a jerk and teaches the developer nothing What you say in code review matters, and so does how you say it. It's important to be clear and conscientious when giving feedback, positive or negative. One of the first tips I've learned when it comes to language is to use "we", not "you". "You need to do it this way" comes across like a demand, "we need to do it this way" is a reinforcement of team standards. It's a small thing really, but can yield positive results. Ask what, not why. People are more open to negative feedback in the form of a "what" than that of a "why". Rephrasing questions to ask "what are the benefits of x over y" instead of "why did you choose x?" forces you as the asker to clarify what you really want to know, and gives the responder a straightforward, non-judgmental question to answer. Avoid using "just" or "simply". What seems simple to you might be less intuitive to others -- there's no reason to imply that there's something wrong if a solution isn't obvious to them. The reality is that "just" and "simply" are filler words that don't add value to your comment, so you can leave them out without losing anything. Lastly, emoji. This may be a hot take but I don't think emoji belong in code reviews. If you're adding a smiley face to a comment to try and defuse tension it might cause, you should probably reword your comment. Or better yet, deliver it in person! As I ment

## Better Code Review: Part Two

DevFeed: [Better Code Review: Part Two](<https://devfeed.tech/articles/better-code-review-part-two-20359.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/better-code-review-part-two-92f17ee42c56?source=rss----d6bb34696ef5---4>)

Author: Molly King

Published: 2018-12-13T03:03:08Z

Content type: tutorial

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [Code review](<https://devfeed.tech/topics/code-review.md>), [Pull Request](<https://devfeed.tech/topics/pull-request.md>)

Tags: [code-review](<https://devfeed.tech/tags/code-review.md>), [code-reviews](<https://devfeed.tech/tags/code-reviews.md>), [pull-request](<https://devfeed.tech/tags/pull-request.md>), [skills](<https://devfeed.tech/tags/skills.md>), [software-development](<https://devfeed.tech/tags/software-development.md>)

### AI overview

Part two of a code review series offers advice for developers whose pull requests are being reviewed, including separating personal identity from code and responding constructively to criticism.

### Source excerpt

Being Reviewed Putting your code up for peer review can be a scary proposition. You've artfully crafted this code over multiple hours and cups of coffee. Your precious, perfect baby is about to be exposed to the big, dark, scary world and torn to pieces by your coworkers. Okay, maybe I'm overstating things a bit. But code reviews can be scary, especially if you're new to them. Few people truly relish in the idea of being criticized, but that's what we do in code review: invite criticism. So what can we do to come out of this process unscathed? If you've read part one of this series then hopefully you're already engaging in self-review before opening your pull request (PR). This will help you screen out obvious errors and save your reviewers' time for more nuanced issues. Once the self-review is over and the PR is open, I've got a few more tips for you to survive being reviewed. The first thing to keep in mind is that you are not your code. It's easy to get your ego tied up in your work, but to survive critique you have to take your ego out of the equation. Great code can be written by inexperienced developers and buggy code can be written by highly regarded, experienced developers. Reviewers will find issues with the code you write, and that has no effect on how good you are at your job. When you conflate your ego and your code you get defensive in response to criticism, and that's just not productive. If you can remind yourself to focus on the critique as it pertains to the code and not as a criticism of your skills as a developer, you'll free yourself up to use the skills you know you have to fix the issues your reviewers have found. If I know someone's going to be picky about my code, I'll go to them directly when I open the PR and talk through their criticisms to avoid an avalanche of comments. -- Jazmine, Software Engineer, RMN A common issue people bring up with code reviews is that they can take too long when the reviewer and reviewee go back and forth in a lo

## Better Code Review: Part One

DevFeed: [Better Code Review: Part One](<https://devfeed.tech/articles/better-code-review-part-one-20358.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/better-code-review-part-one-ae3d4ff0494d?source=rss----d6bb34696ef5---4>)

Author: Molly King

Published: 2018-11-26T17:15:14Z

Content type: tutorial

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [Code review](<https://devfeed.tech/topics/code-review.md>), [Software Engineering](<https://devfeed.tech/topics/software-engineering.md>), [Pull Request](<https://devfeed.tech/topics/pull-request.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [bugs](<https://devfeed.tech/tags/bugs.md>), [code-comments](<https://devfeed.tech/tags/code-comments.md>), [code-review](<https://devfeed.tech/tags/code-review.md>), [pull-request](<https://devfeed.tech/tags/pull-request.md>), [review](<https://devfeed.tech/tags/review.md>), [software-development](<https://devfeed.tech/tags/software-development.md>), [software-engineering](<https://devfeed.tech/tags/software-engineering.md>), [tips](<https://devfeed.tech/tags/tips.md>)

### AI overview

This first article in a three-part series presents self-review as preparation for code review. It recommends running, reading, and documenting code before opening a pull request, arguing that this can catch bugs earlier and support more productive technical discussions.

### Source excerpt

Self-Review Code reviews are an integral part of software engineering, and unless you work alone, are likely to be a regular part of your work life in building software products. Code reviews can occasionally be contentious, and about as fun as a root canal, but they don't have to be! Over the course of this three-part blog series, I will present some tips from my experience to help you review code and for your code to be reviewed in a more productive and less onerous way. First, by putting your code through a form of self-review before having it reviewed by others, you can catch bugs earlier and set yourself up for more successful technical discussions. Microsoft conducted an internal study on code review in 2013. Their aim was to find out why we do code reviews, what the most frequent outcomes are, and how we can conduct reviews more effectively. While most of those surveyed listed finding bugs as their main motivation for code review, in practice only 14% of code comments centered around code defects. The main outcomes found in the study were knowledge transfer, increased team awareness, and finding alternative solutions to problems. Given this information, how can we as reviewers and reviewees change our approach to help bolster those outcomes? The code review process does not begin when you open a pull request (PR). It begins when you start writing code that you intend to merge to a shared codebase. There is a level of due diligence that we are obligated to perform before opening that PR to ensure the best process for everyone involved. I believe by engaging in a few steps of self-review before opening a PR, we can all produce better, more robust code. I propose that there are three steps to self-review: Run it Read it Document it Run it This may sound obvious, but run your code. Even in the case of a simple String change, always run your code. Crashing code that goes to code review creates unnecessary churn and wastes developer and QE time. Very well-written c

## Mentoring a Code2College Intern in Modern Web Development

DevFeed: [Mentoring a Code2College Intern in Modern Web Development](<https://devfeed.tech/articles/mentoring-angela-20363.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/mentoring-angela-18ac3d6a766f?source=rss----d6bb34696ef5---4>)

Author: Steve Swanson

Published: 2018-10-19T16:43:25Z

Content type: opinion

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [modern web development](<https://devfeed.tech/topics/modern-web-development.md>), [Front end](<https://devfeed.tech/topics/frontend.md>), [Python](<https://devfeed.tech/topics/python.md>)

Tags: [frontend](<https://devfeed.tech/tags/frontend.md>), [internship](<https://devfeed.tech/tags/internship.md>), [internships](<https://devfeed.tech/tags/internships.md>), [mentoring](<https://devfeed.tech/tags/mentoring.md>), [mentorship](<https://devfeed.tech/tags/mentorship.md>), [modern-web-development](<https://devfeed.tech/tags/modern-web-development.md>), [organization](<https://devfeed.tech/tags/organization.md>), [python](<https://devfeed.tech/tags/python.md>), [software-development](<https://devfeed.tech/tags/software-development.md>)

### AI overview

The author describes discovering a lasting interest in teaching and mentoring Angela, a 16-year-old Code2College intern, in modern web development. The article introduces Angela's limited frontend experience, existing Python coursework, and Code2College's role in providing practical technology experience to disadvantaged students.

### Source excerpt

I can't say that I was always fond of teaching. My first introduction to it was also my introduction to presenting. Many years ago, a small company I worked for held an annual conference on how to develop and work on its software platform. Having brought all the staff together, the CEO declared that everyone was expected to present. I still remember the shocked looks of horror on my coworkers' faces, myself included. I wasn't particularly social, and I was perfectly content to have a lovely 1 on 1 relationship with my computer and no one else. Teach? To a crowd? The heck you say. But as the years passed I discovered I really loved teaching. It became something that I incorporated into nearly every job I've had since then. So when Kevin Haggard, the manager of Labs here at RMN, asked me to take on the task of mentoring a bright-eyed 16-year-old Code2College intern in the ways of modern web development, I was genuinely excited. I myself was a new hire, barely a month in, and I was hurriedly getting up to speed on the web technologies the company used. In a way, I think this intern and I were in the same boat. Angela was 16 and had very little experience working with any Frontend technologies aside from Code2College's after-school programs. She wasn't completely new to coding however, as she took classes in Python in high school. I wasn't sure what to expect. Would she be able to pick up enough in one summer for this internship to have mattered? Code2College is a non-profit organization that helps disadvantaged students (based on race, gender or income) break into the tech industry. They get the opportunity to have practical experience working with technical professionals who volunteer their time and knowledge, whether that's afternoon college prep courses, weekend workshops or in this case a summer internship with a company. Matt Stephenson, the founder of Code2College, used a word to describe the young adults who are in his program. Hungry. That word most definitely

## Down the Swift associated type rabbit hole

DevFeed: [Down the Swift associated type rabbit hole](<https://devfeed.tech/articles/down-the-swift-associated-type-rabbit-hole-20361.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/down-the-swift-associated-type-rabbit-hole-1f41ee6ceaf4?source=rss----d6bb34696ef5---4>)

Author: Adam Chalmers

Published: 2017-11-01T17:18:03Z

Content type: tutorial

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [Programming](<https://devfeed.tech/topics/programming.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>)

Tags: [array](<https://devfeed.tech/tags/array.md>), [arrays](<https://devfeed.tech/tags/arrays.md>), [associatedtype](<https://devfeed.tech/tags/associatedtype.md>), [computer-science](<https://devfeed.tech/tags/computer-science.md>), [generics](<https://devfeed.tech/tags/generics.md>), [languages](<https://devfeed.tech/tags/languages.md>), [memory](<https://devfeed.tech/tags/memory.md>), [programming](<https://devfeed.tech/tags/programming.md>), [programming-languages](<https://devfeed.tech/tags/programming-languages.md>), [swift](<https://devfeed.tech/tags/swift.md>), [types](<https://devfeed.tech/tags/types.md>)

### AI overview

This tutorial explains a Swift programming problem involving associated types, generic constraints, and where clauses. It works toward a function that combines two Arrays or ArraySlices while avoiding duplicate elements and keeping the inputs and output the same type. It also explains how ArraySlice views can avoid allocating additional memory.

### Source excerpt

If you want to make Swift programmer shudder, just whisper the words "associated types." They're one of the few Swift language typing features you're unlikely to find in other programming languages, so they can take some getting used to. Last week I tried to write a seemingly simple function, and ended up spending most of my day diving down the associated type rabbit hole. This post is going to explain how I (eventually) wrote the "simple" function, and hopefully teach you about associated types, generic constraints and "where clauses" along the way! What's the goal? I wanted a function that would: Take in two Arrays (or ArraySlices), base and newElems as parameters, and return a new array The output array should be made by adding each element of newElems to base, but only if it wasn't already in base All input and output array should be the same type T Note: in Swift, getting a subrange of an array returns an ArraySlice instead of another array. ArraySlices are views into part of the original array -- they're basically just two pointers into the start and end of the array subsection. They can be really helpful!Imagine you had an array with 2 billion elements, and wanted to examine the subarray from elements 5 to 2 billion. Without ArraySlices, examining that subarray would require allocating another 1.9 billion-length array, which would be a waste of space and time. Instead, we can just make an ArraySlice that tracks where the subarray starts and ends, without allocating any more memory. Hell yeah.Wrestling with type signatures ArraySlices are great. There's just one downside: ArraySlice is a different type to Array -- and remember, our function should take either type. So if you write a function like this: https://medium.com/media/c1502a3275e60376a082465bfdd57bb1/href Then Swift won't let you pass an ArraySlice into it. Sure, we can just convert our ArraySlices to Arrays first, but that's no fun. Instead, let's see if there's some protocol that both Array and ArrayS

## Feature-oriented APIs

DevFeed: [Feature-oriented APIs](<https://devfeed.tech/articles/feature-oriented-apis-20362.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/feature-oriented-apis-f0010d140d3a?source=rss----d6bb34696ef5---4>)

Author: Nathan Petryk

Published: 2017-11-01T15:31:01Z

Content type: tutorial

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [Clojure](<https://devfeed.tech/topics/clojure.md>), [API](<https://devfeed.tech/topics/api.md>), [Code](<https://devfeed.tech/topics/code.md>), [version](<https://devfeed.tech/topics/version.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [apis](<https://devfeed.tech/tags/apis.md>), [clojure](<https://devfeed.tech/tags/clojure.md>), [code](<https://devfeed.tech/tags/code.md>), [feature-flagging](<https://devfeed.tech/tags/feature-flagging.md>), [mobile-app-development](<https://devfeed.tech/tags/mobile-app-development.md>), [versioning](<https://devfeed.tech/tags/versioning.md>)

### AI overview

This article explains how RetailMeNot's Mobile API team evolved a Clojure versioned macro for feature-oriented API development. The approach adds feature rollout support and a feature-flagging system while addressing the limitations of linear, version-based code annotations.

### Source excerpt

In my last post -- Minimally Invasive API Versioning -- I talked about how the Mobile API team at RetailMeNot handles versioning our Clojure APIs using a macro called versioned. This macro alone worked great for over a year, but we needed more. In this post I will cover how we evolved it to help ease our feature rollout process, and how we gained a super-easy feature flagging system basically for free. To recap, the versioned macro introduces a convenient syntax for annotating source code with version-specific information -- things like "this line was added in version 3" or "this line was removed in version 7." We call these annotations version-qualifiers. Initially we had several. some were "binary", like added, removed, only, which let the developer specify code that should or should not exist for a specific application version; and others, like changed, lets the developer specify alternative implementations based on the application version. https://medium.com/media/9c51608aa7d9e2240fdbdcc10742c8d5/href We call these qualifiers collectively linear version-qualifiers, because their functionality is based on the linearity of versions: something like "added in version 2"makes no sense without the assumption that V1 precedes V2, which precedes V3, etc. Like I said, this reasoning got us very far, but it has one major drawback: we typically ship multiple features per version, and when we do encountering this version-specific code would often leave developers wondering, "Why was this change made? Which feature was it a part of?". Furthermore, say a feature slipped and we needed to move it to a later version, we found it difficult to go back through the code base to identify and edit those places only related to that feature. The fundamental problem is that when we annotate code with linear version-qualifiers we imbue that code with version-specific information. Stated another way, these kinds of annotations only let a developer look at the code and answer the question, "Wh

## Minimally Invasive API Versioning

DevFeed: [Minimally Invasive API Versioning](<https://devfeed.tech/articles/minimally-invasive-api-versioning-20364.md>)

Original publisher: [Read original article](<https://engineering.ziffmedia.com/minimally-invasive-api-versioning-de5d85ea96d7?source=rss----d6bb34696ef5---4>)

Author: Nathan Petryk

Published: 2017-10-18T15:31:01Z

Content type: article

Language: en

Sources: [RetailMeNot](<https://devfeed.tech/sources/retailmenot.md>)

Topics: [API](<https://devfeed.tech/topics/api.md>), [Clojure](<https://devfeed.tech/topics/clojure.md>), [Mobile](<https://devfeed.tech/topics/mobile.md>), [function](<https://devfeed.tech/topics/function.md>), [Code](<https://devfeed.tech/topics/code.md>), [JSON](<https://devfeed.tech/topics/json.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [clojure](<https://devfeed.tech/tags/clojure.md>), [code](<https://devfeed.tech/tags/code.md>), [function](<https://devfeed.tech/tags/function.md>), [json](<https://devfeed.tech/tags/json.md>), [mobile](<https://devfeed.tech/tags/mobile.md>), [mobile-app-development](<https://devfeed.tech/tags/mobile-app-development.md>), [programming](<https://devfeed.tech/tags/programming.md>), [versioning](<https://devfeed.tech/tags/versioning.md>)

### AI overview

This article describes how RetailMeNot used Clojure to support old mobile API and app versions. It introduces an OfferCard function that returns a JSON map, then discusses copy-and-modify and call-and-mutate approaches for evolving the function while maintaining compatibility.

### Source excerpt

One of the challenges in developing an API for mobile apps is that there is not both a pleasant and reliable way of forcing them to upgrade. This means that in some cases your API needs to support apps that are several years old. The mobile API for RetailMeNot is no exception. This post walks through one of the ways that we've leveraged Clojure to make supporting old API versions, and thus old app versions, significantly easier. First, I will introduce you to a function that builds a portion of our response. https://medium.com/media/93494e2cb8cdc53206a5fdb83ec5e0f8/href This is a simple function that builds the meat of an "offer card." The function is called "OfferCard"; it has three arguments -- "image," "title" and "description" -- and it returns a JSON map with its arguments embedded in it at certain locations. The OfferCard is ubiquitous in our app, and many attributes have been added and removed over time to support changes to the mobile apps over time. Two traditional ways for iterating on a function like this exist: The first way is what I'll call copy-and-modify. This involves simply copying the source code, picking a new name for the function and then making whatever changes are necessary to fulfill your requirements (and, of course, making sure the caller picks the correct version to call): https://medium.com/media/072cb308f9cf0cdac75663fef1cd1fff/href You're probably allergic to copy-pasted code, and rightly so; copy-pasted code, while not always a bad thing, may subtly change over time, and in general just creates another chunk of code that must be maintained. The alternative is for a new, second function to call the old function, and then mutate its return value to fulfill the requirements. I'll call this the call-and-mutate method. https://medium.com/media/bd0884d2eb4b390cce0b3ae0c43b2fbb/href This technique also has some tradeoffs. One nice aspect is that modifications to the original OfferCard function will automatically be incorporated in the OfferCar