Mathias Quinterohttps://quintero.ioenSat, 5 Mar 2022 18:01:47 +0000Sat, 5 Mar 2022 18:01:47 +0000250https://quintero.io/blog/GraphaelloSwiftUI + GraphQL = 😍🚀🙌I love combining GraphQL with SwiftUI to make rich, clean, and data-driven applications. In this article, I want to share my setup + tooling so that more people can explore GraphQL. And by the end, we will even have a small prototype with reusable views and working pagination.https://quintero.io/blog/GraphaelloWed, 6 Jan 2021 00:00:00 +0000SwiftUI + GraphQL = 😍🚀🙌

Hi there! Today I want to take some time and show everyone a little passion project of mine: combining GraphQL with SwiftUI to make rich, clean, and data-driven applications. We will be taking a look at how to use GraphQL, the tooling that I have developed to integrate GraphQL with SwiftUI and create a small prototype with reusable views and working pagination. There's a lot of ground to cover, so let's start.

Alright, Story-Time. So in 2019, I took an internship at Facebook in the AR Publishing Team. We focused on how content-creators (i.e. Instagram influencers, hard-core social media teams, etc.) could create their own AR effects and deliver them to all of Facebook's Platforms (Facebook, Messenger, Instagram). The idea was to break ground and create YouTube for AR. Kinda. In that team, we mainly worked with a web Stack. Which at Facebook means PHP and JavaScript. Client-Server communication wasn't anything new to me, but this was my first contact with GraphQL and, in particular, the JS framework Relay.

And that's when I became a GraphQL junkie. I. Mean. It. I'm a junkie. So without further ado, let me evangelize about GraphQL for a min.

Let's talk about GraphQL

As mobile devs, we usually work with REST APIs. And believe me, REST is awesome! The concept of resources that you either read (GET), update (PUT) or create (POST) is simple enough that it can be used by almost anyone. That's what's so appealing about REST. Everybody knows how to use it. And if you don't, I'm sure some blog post out there will explain it to you in less than 5 mins. But in the scope of ever-larger public APIs, REST starts showing it's downsides.

Building a Social Media App with REST

Let's imagine for a minute that we're the iOS devs that have to build the Facebook App. There's already a REST server. We just need to contact the server and layout the data. For this example, we want to write the PostView: a card that appears when the user is looking at a Post. The way this happens with REST is that when the user navigates to the Post, the App will make a GET request to fetch the information for that Post.

Consider, for instance, that we received the following JSON response from the REST server:

{
    "id" : 42,
    "author" : {
        "id" : 1337,
        "firstname" : "Frank",
        "lastname" : "Young",
        "friendsCount" : 437,
        "mutualFriends" : 22
    },
    "group" : {
        "name" : "We Love Daschunds",
        "memberCount" : 2530
    },
    "text" : "This hot doggo getting a bath",
    "media" : [
        "https://..."
    ],
    "createdAt" : "...",
    "analyticsTrackingId" : "...",
    "moneySpentOnPromotion" : 0
}

As we start building our view we can see that we could read a lot of the data that we want to display, like author.firstname, text, and media. However, there's a lot of data in the response that we don't actually need, like author.friendsCount or analyticsTrackingId. This phenomenon we have where we fetch data only to then immediately throw it away is called Over-fetching. When your user is on a mobile connection it could mean much longer load times and a bigger hit to their data usage. And as the complexity of the server grows, in practice so does the amount of data that is over-fetched.

Later, as we finish implementing our view, we notice we didn't receive any data regarding the comments or likes. But we still want to display that. So we have to make another request to receive the comments. As you might have guessed, this is called Under-fetching: where we have to trigger subsequent follow-up requests to the server to make up for the missing data in the first response. This leads to added complexity in your app, added data usage.

I suppose that this story sounds very familiar to a lot of mobile devs. And the problem is actually quite simple to see: the model chosen by the server developers does not match the exact model that the client developers want to display. This is the limitation of REST. It is resource-based. Therefore you always have to think in terms of resources. Your responses are supposed to contain the information of that specific resource and only that resource.

One possible solution to these problems is to use GraphQL. But what is it? GraphQL actually two different things:

  1. A Query Language (that's what the QL stands for...)
  2. A Server Runtime that can respond to those queries.

The Query Language

Much like SQL, GraphQL is a Query Language that looks like a weird combination of JSON and Swift. Since it's a query language, it makes the client specify what data it wants. This might sound like extra work for us, the client developers, but what it means in practice is that we can ask for as much or as little information as we need at the moment. The best way of understanding GraphQL is by looking at it with the PostView case from before. We can send the following request:

query {
    We even pass arguments in this Swifty mannerpost(id: 42) {
        text
        author {
            firstname
            lastname
        }
        media
    }
}

and receive as a response:

{
    "data" : {
        "text" : "This hot doggo getting a bath",
        "author" : {
            "firstname" : "Frank",
            "lastname" : "Young"
        },
        "media" : [
            "https://..."
        ]
    }
}

So what's going on here. Well, we basically write this pseudo JSON with all the values removed. And we will receive the value for every key that we list in our query. If we want more data, we just list more keys in our query:

query {
    post(id: 42) {
        text
        author {
            firstname
            lastname
        }
        Add a fieldgroup {
            name
        }
        media
    }
}

which would result in the following JSON:

{
    "data" : {
        "text" : "This hot doggo getting a bath",
        "author" : {
            "firstname" : "Frank",
            "lastname" : "Young"
        },
        Get it in the response"group" : {
            "name" : "We Love Daschunds"
        },
        "media" : [
            "https://..."
        ]
    }
}

What does the "Graph" mean?

An integral part of understanding GraphQL is that it has an object-oriented type system that can be used for communication. This means that we deal with object types (like classes) in a graph. These objects have properties and connections to other objects. In our example, a connection would be how we can go from a Post to the author. So you can consider accessing this as traversing edges in a graph. Pretty cool, right?

But the big plus point we get from this type-system is that we know the exact types of every value that could possibly be returned by the server. We know the shapes of objects, the nullability, and if the server developers included it, we even get documentation. Ok, I'm done nerding out about GraphQL, this is supposed to be a SwiftUI post, so let's talk about Relay.

What's Relay?

Relay is a set of tools, that enable using GraphQL from React. But the main selling point of the combination of Relay + React is that the declarative nature of GraphQL and React work together seamlessly. With Relay, we benefit from the type-safety that GraphQL gives us + for most apps it removes the need for state management patterns like MVC, MVVM, or Redux.

The idea is that UI components can declare their Queries (or Fragments) from GraphQL inline. No state management required. This is the kind of tool that you can only really see the benefit of when you're using it, so if you're interested, please do give it a try. My point is that I tried Relay while at Facebook, and an idea just popped into my head. If SwiftUI is kinda like the React for Swift, could we build Relay for SwiftUI?

Relay for SwiftUI?

So that's what I sought out to build. And I call it Graphaello. It's an open source tool that will let you use GraphQL from within your SwiftUI code. Just like Relay!

How does it work? Well, it's kind of like a weird overengineered pre-processor that reads your SwiftUI code and generates everything you need from there. But that's not the important part, because my main concern with Graphaello was the development flow and experience. So how about we explore Graphaello together with an example?

Building a Movies App using Graphaello

In this example, we will be creating a simple App to browse popular movies. We will be covering how to:

  1. Set up Graphaello with an Xcode Project
  2. Perform queries
  3. Create reusable views using fragments
  4. Use connection-based pagination

For this example, we will be using a GraphQL Wrapper for The Movie Database that I have provided publicly over here. We can ask this API for information regarding movies. For example, we could ask for info on the movie with the ID MDoxMg== like this:

query {
    movies {
        movie(id: "MDoxMg==") {
            title
        }
    }
}

which will return:

{
  "data": {
    "movies": {
      "movie": {
        "title" : "Finding Nemo"
      }
    }
  }
}

If you open the API in a browser you'll see a live Web IDE called GraphQL Playground. It allows us to experiment with GraphQL, run queries, and view the documentation. Please, feel free to check it out, and try a couple of queries while you're there.

Note: In the interest of time, I will not be explaining the concepts of SwiftUI. If you're looking for some introductory reading to SwiftUI I'm happy to recommend Paul Hudson's articles on SwiftUI.

Set Up Graphaello

To set up a project with Graphaello we first need an Xcode project project. This time, let's create a SwiftUI iOS project. Open Xcode and click File > New > Project. Create an iOS Application and make sure you choose SwiftUI. I also recommend the SwiftUI App Life Cycle.

Now we need to install Graphaello on our machine. The easiest way to install it is by using homebrew. So if you have homebrew already installed you can run the following on your terminal:

brew tap nerdsupremacist/tap
brew install graphaello

Now that you have Graphaello installed on your machine, we can continue by integrating it into our App. Please close Xcode completely and in a terminal navigate to the folder containing your project and run:

graphaello init

This command is setting the project up so that Graphaello can work properly. Now we need to tell it which GraphQL API we want to use. So in the same terminal also run:

graphaello add --apiName TMDB https://tmdb.apps.quintero.io

This command registered our API with the name TMDB. That's it, Graphaello is set up. You may now close the terminal. You can now open your project in Xcode. The rest of this tutorial will take place there.

Query some Data

Before we write our actual app, let's make sure this works. So let's write a View that will tell us the name of a Movie. We start by writing the UI:

struct Test: View {
    var title: String
    
    var body: some View {
        Text(title)
    }
}

And to fetch data from GraphQL we simply have to tell it where to get title from. For that, we use the @GraphQL property wrapper:

struct Test: View {
    This tells Graphaello how to load title@GraphQL(TMDB.movies.movie.title)
    var title: String

    var body: some View {
        Text(title)
    }
}

What is happening here? Let's break that down:

  • @GraphQL: signals to Graphaello that this property should be filled from GraphQL
  • TMDB tells Graphaello that it should fetch this value from the TMDB API we added earlier
  • movies.movie.title is the path starting from the Query that it should follow.

Now it's time to use this view. Make sure that your project builds (⌘ + B). To render our view, we first need an instance of the TMDB client in our App. Some testing will show us that TMDB now has a function called test that returns a View. And it expects a parameter named id. Interesting, right? Let's give it a try. As for id let's use MDoxMg== for now and see what happens:

@main
struct MoviesExampleApp: App {
    Add an instance of the clientlet api = TMDB()

    var body: some Scene {
        WindowGroup {
            The type TMDB now has a test methodapi.test(id: "MDoxMg==")
        }
    }
}

If you run the project now, you should see this:

So what happened there? Graphaello saw our Test struct that was using the GraphQL property wrapper. It type-checked the value of title, created a GraphQL query for our View, and added a function to TMDB that can display it. All of it is taken care of. If we wanted to query more data we simply add more properties, like for example the overview:

struct Test: View {
    @GraphQL(TMDB.movies.movie.title)
    var title: String

    Just like that, you're fetching more data@GraphQL(TMDB.movies.movie.overview)
    var overview // Swift can infer the type ;)

    var body: some View {
        VStack {
            Text(title).bold()
            Text(overview)
        }
        .padding()
    }
}

If you run the app again, you'll see the extra information delivered:

That's pretty neat, right? So far, we have basically only written UI code. Since GraphQL is a declarative language it fits right into the properties of our views. Easy! Let's take it up a notch.

Reusing Views

Sometimes we want to build views that we can reuse across our App. To create a reusable View, instead of specifying the path starting from the query, we start with the GraphQL type with the information we want to use. For example, we could create a MovieCell that displays the data from a Movie. So naturally, we will use the Movie Type:

struct MovieCell: View {
    @GraphQL(TMDB.We start by specifying the type the data belongs toMovie.title)
    var title
    
    @GraphQL(TMDB.We start by specifying the type the data belongs toMovie.overview)
    var overview

    var body: some View {
        VStack {
            Text(title).bold()
            Text(overview).lineLimit(3)
        }
    }
}

Let's say we want to display two movies side by side (i.e.: my favorite movies Star Wars and Finding Nemo). Well, we can ask for both using a query. This time, however, instead of writing down every field we want to fetch, we tell Graphaello to give us the information we need to render MovieCell. We can do this by asking for the movie like before, but without a field, and as a type we will use MovieCell.Movie (a.k.a. the Movie that MovieCell needs).

struct Test: View {
    @GraphQL(TMDB.movies.movie(id: .value("MDoxMQ==")))
    var starWars: Ask for the Movie needed by the cellMovieCell.Movie

    @GraphQL(TMDB.movies.movie(We can hardcode parameters tooid: .value("MDoxMg==")))
    var findingNemo: MovieCell.Movie

    var body: some View {
        HStack(spacing: 32) {
            Render MovieCell with the MovieMovieCell(movie: starWars)

            MovieCell(movie: findingNemo)
        }
        .padding()
    }
}

@main
struct MoviesExampleApp: App {
    let api = TMDB()

    var body: some Scene {
        WindowGroup {
            We no longer need to pass an idapi.test()
        }
    }
}

The code above will render the following:

This reusability of MovieCell means that MovieCell can change the data it's displaying, and the changes are propagated to all the parents. Our Test View doesn't care about the specifics of what MovieCell needs. It just cares that it needs a movie.

Pagination

Ok, I can imagine that now you must feel like this is really dull. Just showing two movies side by side? Let's show an entire list. And while we're at it, let's have pagination and infinite scrolling... Ok, let's go! The TMDB API supports pagination for movies.trending. Let's try it out with that. Graphaello comes out of the box with a Pagination construct called Paging. Paging is an ObservableObject that provides you the features you need to use paging in your app. For now, we can use it to fetch trending:

struct Test: View {
    @GraphQL(TMDB.movies.trending)
    var trending: Use Paging to support PaginationPaging<MovieCell.Movie>

    var body: some View {
        NavigationView {
            List(Access the values directly using .valuestrending.values, id: \.title) { movie in
                MovieCell(movie: movie)
            }
            .navigationTitle("Trending")
        }
    }
}

Let's try and run it, to see what that looks like!

Right now, if we wanted to fetch the next page, we'd just call trending.loadMore(). But since the use case of infinite scrolling is very common: Graphaello also comes with a PagingView that implements that for us. So we're going to replace our List with a PagingView:

struct Test: View {
    @GraphQL(TMDB.movies.trending)
    var trending: Paging<MovieCell.Movie>

    var body: some View {
        NavigationView {
            PagingView implements infinite scrollingPagingView(trending) { movie in
                MovieCell(movie: movie)
            }
            .navigationTitle("Trending")
        }
    }
}

And done! We can now scroll through the trending movies forever.

Let's make it pretty!

Text is kinda boring. So the next step would be to load some images. For that, we will add a Kingfisher as a dependency, to be able to display images from the internet. So we'll go on File > Swift Packages > Add Package Dependency. There we can enter:

https://github.com/onevcat/Kingfisher.git

With Kingfisher added, let's try to display the poster for our Movie. In our MovieCell we'll query for the poster URL using poster. Then we can use KFImage to display the image from that URL:

struct MovieCell: View {
    @GraphQL(TMDB.Movie.title)
    var title: String

    @GraphQL(TMDB.Movie.poster(size: .value(.w154)))
    var poster: We specify that we expect to read a URLURL?

    var body: some View {
        VStack {
            if let poster = poster {
                Display the image in that URLKFImage(poster)
                    .resizable()
                    .clipped()
                    .aspectRatio(0.69, contentMode: .fill)
                    .frame(width: 100)
            }

            Text(title).bold()
        }
    }
}

Ready? Let's take a look at those images:

Cool! However, most movie apps use horizontally scrolling shelves to display movies. To remake that UI, we can tell the PagingView that we want to scroll horizontally.

struct Test: View {
    @GraphQL(TMDB.movies.trending)
    var trending: Paging<MovieCell.Movie>

    var body: some View {
        NavigationView {
            Wrap it in a ScrollViewScrollView {
                PagingView(
                    trending, 
                    Set the mode to horizontalmode: .horizontal
                ) { movie in
                    MovieCell(movie: movie)
                }
            }
            .navigationTitle("Trending")
        }
    }
}

Ok. Looking good! Next up, I'd suggest a few UI improvements. This is the part when we get to have some good old-fashioned Paul Hudson style SwiftUI fun. First, in MovieCell let's add rounded corners to the image. Oh! And let's also cast a shadow. We also want all cells to look uniform, so let's set the width of the cell to a fixed value, and truncate the title to fix in only one line. This will lead to all the cells being aligned nicely next to each other.

struct MovieCell: View {
    @GraphQL(TMDB.Movie.title)
    var title: String

    @GraphQL(TMDB.Movie.poster(size: .value(.w154)))
    var poster: URL?

    var body: some View {
        VStack {
            if let poster = poster {
                KFImage(poster)
                    .resizable()
                    .clipped()
                    .aspectRatio(0.69, contentMode: .fill)
                    .frame(width: 100)
                    Add some rounded corners.cornerRadius(10)
                    Add a shadow.shadow(radius: 5)
            }

            Text(title).bold()Limit the number of lines.lineLimit(1)
        }
        Fix the size of the cell.frame(width: 150)
    }
}

As for our Test view, I'd suggest spacing the cells apart by a bit. And we should also add some padding to the content of the PagingView so that the first cell isn't directly touching the leading edge.

struct Test: View {
    @GraphQL(TMDB.movies.trending)
    var trending: Paging<MovieCell.Movie>

    var body: some View {
        NavigationView {
            ScrollView {
                PagingView(
                    trending, 
                    mode: .horizontal(
                        spacing: 4, 
                        Add some padding to the edges of the screenpadding: .horizontal, 
                        by: 16
                    )
                ) { movie in
                    MovieCell(movie: movie)
                }
            }
            .navigationTitle("Trending")
        }
    }
}

Finally, how about adding some more shelves to our App? Thankfully, this can be done with some simple copy and paste. We can add shelves for topRated, nowPlaying, and popular by copying the code for trending and adding some headlines to each shelf.

struct Test: View {
    @GraphQL(TMDB.movies.trending)
    var trending: Paging<MovieCell.Movie>

    @GraphQL(TMDB.movies.topRated)
    Load more moviesvar topRated: Paging<MovieCell.Movie>

    @GraphQL(TMDB.movies.nowPlaying)
    Load more moviesvar nowPlaying: Paging<MovieCell.Movie>

    @GraphQL(TMDB.movies.popular)
    Load more moviesvar popular: Paging<MovieCell.Movie>

    var body: some View {
        NavigationView {
            ScrollView {
                VStack(alignment: .leading) {
                    Add a new headlineText("Trending")
                        .font(.headline)
                        .fontWeight(.heavy)
                        .padding(.horizontal, 16)
                    
                    PagingView(
                        trending, 
                        mode: .horizontal(
                            spacing: 4, 
                            padding: .horizontal, 
                            by: 16
                        )
                    ) { movie in
                        MovieCell(movie: movie)
                    }

                    Repeat...
                }
            }
            .navigationTitle("Movies")
        }
    }
}

And then we can take a second to admire our pretty new app:

Note: I've noticed that this shelve UI can be laggy sometimes. I'm looking into it.

Conclusion

So there we are. Let's recap what we accomplished. We learned about the drawbacks that come with REST and how GraphQL can save us a lot of networking as well as pain during development. After that, we discussed how the declarative nature of GraphQL lends itself to creating beautiful data-driven UIs. The truth is that a declarative query language and a declarative UI framework is a match made in heaven. And we took a deep dive into Graphaello and learned how to use GraphQL from SwiftUI without exiting Xcode (or writing any GraphQL, really). We experimented with reusing views and pagination. And saw an approach to structuring a SwiftUI App that uses a GraphQL API.

I really hope you enjoyed this tutorial and that you'll consider using GraphQL (and maybe even Graphaello) for more apps in the future. If you have any questions about GraphQL, SwiftUI, or Graphaello, please contact me either via GitHub issues or Twitter.

Further Reading

Here's some useful links you might want to take a look at to explore this topic more:

Graphaello: If you like it, I'd really appreciate a star ⭐️

GraphQL: Read up more on GraphQL

Relay: Relay JS framework which inspired this workflow

Paul Hudson's articles on SwiftUI: Great resource for getting started with SwiftUI

TMDB GraphQL Wrapper: Source Code of the example API we used for this article

]]>
https://quintero.io/blog/KintsugiKintsugi: The Art of the Anti-PatternThe japanese art style of Kintsugi revolves around repairing broken pottery by embracing its flaws and making them even more beautiful than before. Perhaps we can apply this same technique to Anti-Patternshttps://quintero.io/blog/KintsugiThu, 31 Jan 2019 00:00:00 +0000Kintsugi: The Art of the Anti-Pattern

So! I’ve been thinking! I know; big surprise there… But most blog posts I read around software tend to revolve around two things:

  • Management: What are we doing wrong and what can we do right?
  • Engineering: Here’s this cool concept using new tools you could apply!

And I deeply admire those who write about these topics. However, I rarely see people talk about how we can turn around software that has gone wrong. We often talk about what made them go in a bad direction, what patterns turned out to be anti-patterns, and what we should avoid in the future. But when it comes to what to do with these running systems, the answer appears to be a unanimous:

Re-write and slowly phase the old system out

Or what I will be calling: the Take-Out-The-Trash-Method.

Let’s talk about Kintsugi

So there’s this thing called Kintsugi. It’s a Japanese art style where instead of throwing out broken pottery, it is put back together and carefully repaired. Joint by lacquer mixed with gold to make them beautiful.

Out of a defective plate, we can now make art.

And we can interpret and discuss a lot about their philosophy:

  • Have we made something beautiful by not only embracing its flaws, but also by putting them in the foreground and platting them with gold? Attracting more looks than before?
  • Or are we simply admiring the craftmansship of taking something broken and putting it back to use? More elegant than before.
  • Or perhaps we just want stories? The one of how it got broken. The one of how we repaired it. The one where we wrote a blog post about it. So Meta

Ok, I’m getting off track here. My point is that these are all aspects that make Kintsugi not only special and beautiful, but an appropriate way of treating broken software as well. Boom! Stuck the landing!

The Art of the Anti-Pattern

Or maybe I should call them “Arti-Patterns”.

No. I shouldn’t. I really really shouldn't.

Anyways, an Anti-Pattern is basically a design pattern turned bad. Like its evil twin in a soap opera. It’s when a reoccurring solution to a reoccurring problem ends up creating more problems, adding tech-debt and ultimately being very, and I mean very counterproductive. Engineers, Professors and even Students love Anti-Patterns. They love talking badly about them. Almost as if they’re above them. Even me (especially me):

But they mostly just love coming up with them, later noticing what they’ve done and re-writing everything to avoid their previous mistake. And this often works. Usually our mistakes are relatively small and a refactor here and there can fix everything. Until the next refactor, that is.

However, what happens when you’re in too deep and trying to keep, up above in your head, instead of going under? Sorry, I’ve lapsed into song lyrics, there. What I mean is that sometimes a big refactor is not an option anymore. There’s way too many moving parts and no escape from tech-debt. What can we do?

Let’s Kintsugi the Sh*t out of it!

Start embracing what makes your system yours and fix it up, not by removing all its flaws but by working around them and bathing them in gold!

I know it sounds weird; I’m basically suggesting what we call a Lava Flow, but hear me out!

Let our solution around the anti-pattern be a thing of beauty. Everyone will look at your elegant solution, and never even consider the anti-pattern it’s working around. Let’s hit it with some examples:

The God Class

The God Class is a self explanatory problem. You created a class that appears to be responsible for everything. We can no longer navigate it. It is simply too much at once.

And most people who encounter this solve this by:

  • Split responsibilities into multiple new classes. Tend towards single responsability per class.
  • Rewrite API to accomodate changes

However, the larger your code base or other limitations on the side, this is rendered impossible. So here’s the Kintsugi solution; Modularize, but keep the God Class:

  • Find out what the responsibilities are
  • For each responsability create an Interface and match the signature of the God Class
  • Write Component X that implements that Interface with the code from the God Class
  • Inject Component to God Class
  • Let God Class delegate it’s job to the Component

This may sound complicated, but it’s much simpler in code. Given this ugly implementation of a God Class in Kotlin:

data class GodClass(val foo: String) {

  fun bar(baz: Int): Boolean {
    // complicated logic using foo
  }
  
  // more complicated functions that don't really have anything to do with each other
  
}

We can start by splitting it. We recognize the Bar method and the foo variable belong to the same responsibility. So we create a Bar interface for it.

interface Bar {
  val foo: String
  fun bar(baz: Int): Boolean
}

And the component encapsulating the implementation that was previously in the God Class:

data class BarComponent(val foo: String) : Bar {

  fun bar(baz: Int): Boolean {
    // complicated logic using foo
  }

}

And finally make the God Class delegate all its Bar responsabilities to the Component:

data class GodClass(val bar: Bar) : Bar by bar {
  
  // Rest of the code that should also be refactored this way
  
}

And voila! We have turned a god class into a modular component based solution that is easier to navigate, and all without changing the API or the rest of the system. Or basically we’ve turned our God Class anti-pattern into a Facade Pattern.

Constant interface

Most people will think this isn’t quite an Anti-Pattern. But it’s one of the most common ones. The idea is that you put all your constants in an Interface’s definition to be able to namespace them, and have more context about what you’re accessing without injecting.

The problem is that this Interface is now part of the implementation. And most would argue that constants belong in configuration objects and exported as part of the API.

But instead of dealing with injecting configurations and making sure you pass the correct one’s: we can embrace the constant interface, and just decouple the definition from the values.

Let’s see what I’m talking about. Here’s an example of us using the Constant Interface Anti-Pattern in Swift (with enums instead of protocols)

enum Constants {
  static let padding = 20
  static let height = 100
}

class Builder {

  func element() -> Element {
    return Element(padding: Constants.padding, height: Constants.height)
  }
  
}

This builder is accessing the constants through the name space. If we want to remove these implementation details we can introduce a generic type that contains our Constants. And we can continue with the exact same code as before. Let’s begin by defining a protocol:

protocol BuilderConstants {
  static var padding: Int { get }
  static var height: Int { get }
}

And we introduce a generic type with the same name to our builder:

class Builder<Constants: BuilderConstants> {

  func element() -> Element {
    return Element(padding: Constants.padding, height: Constants.height)
  }
  
}

And now you can define your actual Constants:

enum StandardConstants: BuilderConstants {
  static let padding = 20
  static let height = 100
}

But now, you might say: you’re still including which constants you’re using right into the Builders signature. This isn’t much better. Well that’s where type erasure comes to the rescue. With type erasure we can refer to our builder without extra generic information getting in our way.

We start by encapsulating the builder’s api into a protocol:

protocol BuilderProtocol {
  func element() -> Element
}

And we create a wrapper class that erases the generic constraints:

class AnyBuilder: BuilderProtocol { 

  let _element: () -> Element
  
  init<Builder: Builder>(_ builder:  Builder) {
    _element = builder.element
  }
  
  func element() -> Element {
    return _element()
  }
  
}

And we can now always refer to AnyBuilder as the new builder:

let builder = AnyBuilder(Builder<StandardConstants>())

TADA! We have successfully removed what makes this Anti-Pattern an Anti-Pattern.

Object orgy

Granted. I’ve only included this particular one because I find the name so amusing. Yeah. I’m a child. But Object Orgies are a frustrating and problematic issue in many code bases. They’re called this way because everything has access to everything. Anything can be changed from anywhere. Systems like this tend to be very chaotic. Not only because it can be very unclear where what is going on, but our types give no guide or indications about how to approach problems.

Consider the following class modeling a Book:

class Book {
  var title: String?
  var author: String?
  var isbn: String?
}

In this code anything can read and write any properties of the Book. Refactoring this can be problematic since the flow of the application heavily depends on being able to change these properties at any time. But how could we introduce some extra safety without completely rewriting the flow of the system?

An answer might be adding extra safety by writing a wrapper with a Phantom-Type.

But what’s a Phantom-Type, anyways? A Phantom-Type is a generic parameter that is not directly used, but instead serves as an type safe indicator of how we can deal with the object. And we can even regulate how we read and write properties of an object using these types.

So let’s start by a creating a simple wrapper. We’ll call it Safe.

class Safe<Value, Rights> {
  private let value: Value
  
  init(value: Value) {
    self.value = value
  }
}

Safe has a generic parameter for the object that it’s wrapping and a parameter determining the read and write rights we have on it. Let’s put it to the test!

We can start by creating a protocol signaling that we can read the title of the book:

protocol ReadTitle { }

And we can say that when the Rights conform to ReadTitle, our Safe implementation will expose the title as a read only property:

extension Safe where Value == Book, Rights: ReadTitle {

  var title: String? {
    return value.title
  }
  
}

Well that was easy. Now let’s do it with Writing to Title:

protocol WriteTitle: ReadTitle { }

extension Safe where Value == Book, Rights: WriteTitle {
  
  var title: String? {
    get {
      return value.title
    }
    set {
      value.title = newValue
    }
  }

}

enum TitleRights: WriteTitle { }

let book: Safe<Book, TitleRights> = Safe(value: Book())

book.title // works
book.title = "Don Quixote" // also works
book.author // doesn't work

And Presto! You can now slowly make sure that instances of code that use Book, can only read and write what they’re supposed to and you can think twice before a method wants to read and write every property.

Now of course this technique is very powerful and can be used in very elegant systems. You can read more about it in Sebastian Sellmair’s post on the topic.

So? What’s the point of all of this?

Mainly? To say that not everything is black and white. Rewriting a system might be the cleanest solution for many. And it’s clearly a lot more fun. However, sometimes we can take pride in writing clean solutions around not that clean codebases and feel proud we made something better.

Of course, most of my solutions here are not ground breaking or even perfect. But it goes to show that every piece of code can be rescued and maybe even turned into art.

P.S.: Here’s a cute cat or whatever

]]>
https://quintero.io/blog/FizzBuzzFizzBuzz: How To Overengineer the Coding InterviewIf you’re ever looking for a job as a Developer, you will without a doubt encounter the “Coding Interview”. That terrifying moment when someone tells you a problem you haven’t heard of since your second semester of college and expects you to solve it quickly and correctly without autocomplete, Stack Overflow or a compiler.https://quintero.io/blog/FizzBuzzFri, 4 Aug 2017 00:00:00 +0000FizzBuzz: How To Overengineer the Coding Interview

If you’re ever looking for a job as a Developer, you will without a doubt encounter the “Coding Interview”.

That terrifying moment when someone tells you a problem you haven’t heard of since your second semester of college and expects you to solve it quickly and correctly without autocomplete, Stack Overflow or a compiler.

Scaaary… I know.

But the main problem with the Coding Interview are not the conditions in which you have to work, or the judgment of your peers or any of that which we associate with stress, rejection and failure during an interview.

Stolen/Borrowed from @The Practical Developer

It’s that since we are getting basic problems, we tend to offer basic solutions that are dirty, complex and built to only work for these exact use cases.

And I would argue that in order to truly assess how good an engineer someone is, you’d have to see how good they can overengineer their solution to a problem.

Because, if you’re not already solving convoluted imaginary issues regarding reusability, maintenance, and scale in your head; are you even solving the problem? Am I right?

So please join me as I do exactly that! For fun! (Yes, I’m that bored.)

FizzBuzz

So let’s take a look at one of the most simple problems: “FizzBuzz”. The idea goes as follows: if a number is divisible by 3 then you print out “Fizz”, if it’s divisible by 5 “Buzz”, if it’s divisible by both: you guessed it “FizzBuzz”. If none of these apply simply print out the number.

So a basic game would go:

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16

Most programmers faced with this problem will write something along the lines of this (in Java of course):

for (int i = 1; i <= n; i++) {
    String output = "";
    if (i % 3 == 0) output += "Fizz";
    if (i % 5 == 0) output += "Buzz";
    if (output == "") output += i;
    System.out.println(output);
}

But let’s say you’re like me and hate Java. Well, I personally have a moral objection against loops and decided to use a functional programming language instead.

So from now on, I will be using OCaml: a French functional programming language, known for being Haskell’s less famous but more charming cousin.

Modeling our Problem

Since we’re going to be overengineering this problem, we won’t directly work with the rules of FizzBuzz until the very end. For now, we will be dealing with an abstract set of rules that can be fed to a magic function that will tell us the output.

What rules?

Imagine a rule as an if statement in the Java code above. The rules will tell our program what to write given which numbers. We will define them in the Form of Tuples of Conditions and Strings.

If a condition is met we will append the string to the output of the function. For example, a Rule in FizzBuzz would be:

let rule = (fun n -> n % 3 = 0), "Fizz";;

Which translates to if the input is divisible by 3 append “Fizz” to the output.

Got it? Ok. Here we go!

Implementation Time!

First! Since I don’t want to import any modules into my code I will implement two quite common functions: map and reduce.

let rec reduce l f a = match l with
    | x::xs -> reduce xs f (f a x)
    | [] -> a;;

let rec map l f = match l with
    | x::xs -> (f x)::(map xs f)
    | [] -> [];;

Next! We have to think about that last empty String check.

Since we are working with abstract rules, we don’t know if one of them wants to output an empty String. So we can’t rely on empty String meaning no rule applied. Therefore it would be best to abstract this case as an Optional instead. Which is already defined in OCaml as:

type 'a optional = Some of 'a | None

Now to correctly deal with Optionals we will need the following functions:

1. Elvis Operator:

let ($) a b = match a with
    | Some(a) -> a
    | None -> b;;

This function simply checks if a is defined. If that’s the case it returns a. Otherwise, it will return the default value b.

Note: The Elvis Operator is usually written with (?:). However because of OCaml’s constraints on infix operators using (?:) is not possible. So I decided to use ($). Just because!

2. Map on Optional:

let mapOptional i f = match i with
    | Some(i) -> Some(f i)
    | None -> None;;

This will pass the value of i to f if it’s present and otherwise return None.

3. Concatenating a String on top of an Optional String:

let (^?) a b = (mapOptional a (fun a -> a ^ b)) $ b;;

This last one has a very simple purpose. If a has a value return ab. Otherwise output b.

Now that we have the optionals out of the way, we can start writing our magic function.

Let’s start with a helping function:

let helper a n (f, s) =
    if (f n) then
        Some(a ^? s)         
    else
        a;;

Which will check for the condition f on n and if it’s met return the accumulator a concatenated with the String s. Otherwise only a.

And now we can call it:

let output n r f =
    (reduce r
        (fun a x -> helper a n x)
    None) $ (f n);;

We will reduce all the rules r using our helper: starting with a None value and collect all the Strings. If no conditions are met the result will be None. If this is the case we will return the default value given by calling f on n. (In the case of fizzbuzz f will be converting the integer n into a String.)

And that’s all we need. Now we only have to feed these functions the right inputs.

For that let’s start by being able to generate a range of numbers:

let rec range a b =
    if a < b then
        a::(range (a + 1) b)
    else
        [b];;

And being able to calculate the mod of an integer a given a base b (since it’s not defined in OCaml):

let rec (%) a b =
    if a < b then
        a
    else
        (a - b) % b;;

Now we need the rules we will feed our function:

let rules = map [3, "Fizz"; 5, "Buzz"] (fun (a, b) ->
    (fun n -> n % a = 0), b
);;

And finally we define the function fizzbuzz which will output all the results until n:

let fizzbuzz n =
    map (range 1 n) (fun x -> output x rules string_of_int);;

And we’re done!

If you call fizzbuzz with 15 you will get the output:

["1"; "2"; "Fizz"; "4"; "Buzz"; "Fizz"; "7"; "8"; "Fizz"; "Buzz"; "11"; "Fizz"; "13"; "14"; "FizzBuzz"]

So? What have we learned?

Well, not much. There aren’t any lessons about style or system design here.

Some of you would hire me after reading this. Others (the majority, quite frankly) would probably want to kill me for even daring to write code like that. But I will say this:

You have a much better-informed opinion about how I code based on that than from a little Java snippet anyone can write. And is that not more useful than any “Coding Interview”?

So I will leave you with this. If you’re ever interviewing someone. Maybe, just ask them to overengineer their solution, and see what’s really going on under the hood.

You might be surprised…

]]>