Photo by Javier Allegue Barros on Unsplash

Build Better Software By Going Farther Together

TL;DR: Growing up in an immigrant community in the New York Metro area, you never think the unique, random, and crazy experiences you have in such a setting could have a direct impact on your career in tech, until it does. And I've learned many lessons, and here's one of them. If you get out of your own way, you along with your team, will accomplish great things.

Growing up, my family was quite plugged into a faith community that comprised mostly of people who were at the time recent immigrants to the United States from Egypt. We were the beginnings of the Coptic Orthodox community in America. Most of the non-liturgical music generated by the community was geared towards the ears and culture of those who immigrated here. I was part of a different generation, born in the USA, but very much Egyptian. It was very difficult to relate to some of the art and music that had been imported and shared with us.

By the time I got to high school, I had different ambitions than my peers. While most kids were out there being kids, I had felt a deep responsibility to help create art that we could connect with. After a few attempts, my work was often dismissed as dissenting, and non-adherent to our traditions. My team of musicians and I stayed persistent, despite doors (sometimes literally) being closed in our faces. While there was an initial rejection by community leaders, our work was getting recognition. The youth of the New York/New Jersey metro area started to know and enjoy our music.

Making A Record

In college I had a new vision: an album. My hope was that it would be an album that would embody the values and essence of our traditions, while connecting them with the creation of something original that our generation could resonate with. I wanted to send a message that even though a ton of art and music was handed to us, that we could be empowered to become creators of art and music, ourselves!

I found an excellent team of like-minded individuals. We sought funding, and eventually partnered with a local church who liked our idea. They offered to bankroll an album, in exchange for inventory. This did mean however, that I did not have complete creative control over the outcome. (dun.dun.dunnnnn!)

While most of our ideas were welcomed, quite a few were met with concern. I was often asked to hold back, edit, or even omit, for the sake of not rocking the boat too much. I had to make a choice, was I going to "compromise" on our vision, or was I going to trust this collaboration with an outside partner? This partner was older, a lot more experienced, and had a perspective that was a lot broader than my own. He knew intimately the ins-and-outs of our community, across multiple generations. He obviously believed in me enough to work with me, but seemed to restrict what we were trying to create for reasons I couldn't understand at the time.

There were moments I really wanted to lead and just create, yet felt like I had to be a team player, and there were a lot of reluctant compromises.

Unexpected Outcomes

We powered through, and the record was produced. The end result surprised me, and was beyond what I could have imagined: two sold-out printings, and an east coast tour that lasted four years. In 2001, I even got a phone call from office of the Ambassador from Egypt to the United States. On behalf of His Excellency, the office invited us to perform at a gathering of dignitaries and officials from all over the world, at an event honoring the music of Egypt. It was pretty incredible and completely unexpected!

But aside from all this "big stuff" that I'm mentioning, it was the people-impact that mattered most to me. We met and received letters from youth all around the world, with stories about how our work had impacted them, or encouraged others to follow suit and create music of their own.

I am convinced that had it been all up to me, and my direction alone, we would not have had the impact we experienced. We would have had total creative freedom, but we may have never reached such broad audience. I was satisfied, although there was less “getting my way” and more “getting out of my own way”.

Ok, great. You may be reading this, and thinking "what on earth does this have to do with building software?" and my answer is: "Everything."

"Don't Throw The $necessary Out With The $unnecessary"

As a hot-headed 21 year old, although I was committed to achieve something for my community, there was a blurred line between the overall desired outcome and the means to achieving that outcome. Art is highly personal. Making the art is as much of a goal as the outcome. If there was a particular song that was going to be cut from the record, or a direction that needed editing, I didn't always handle it gracefully. I nearly quit the project until my mentor told me, "don't throw the baby out with the bathwater". I had no idea what he was talking about. Once it was explained to me, I thought that was the weirdest metaphor ever.

But if you replace baby and bathwater, with the necessary/unnecessary thing of your choosing, the lesson starts to take shape. I was given a choice, if I stayed in this partnership, would the vision still be achieved? As I looked around, and saw how much freedom we actually had, was I willing to throw the whole project out the window because of 1 or 2 cut songs? I eventually decided to trust, and to refocus my attention on the goal, and preserve the relationship through the details. Had I disengaged, or quit, I would have missed out on something huge. The proverbial baby would have been lost.

That piece of advice kept me in the game, but the actual lesson I needed to learn was one that has to do with the importance of "us" over "me". It's the fact that if I'm working on something with a group of people, it's more important for us to be aligned than for each of us to do things their own way.

But, I'm an Artist and I Cannot Be Stifled!

They say that building software is an art. And there are a ton of similarities between those who make art, and those who write software. Unlike the building of a car or a house, where there are clear specifications for how each part comes together, building software retains the imprint of the developer. Even with strict team standards, the developer's personal style finds its way into the code. By looking at a piece of code, I can usually tell who on my team wrote it. It's why we say that we "write" software as opposed to "assemble" or "manufacture" it.

Unless you're one of the unicorns of 1-2 person teams, who get acquired by multi-billion dollar corporations, it usually requires more than 1 or 2 engineers to create something that can see the light of day. Our VP of Engineering has a saying, "Software is a people endeavor". We build software together. "Together" would mean, a group of people who have spent various durations of time (from months to decades) perfecting their craft, each with their own sense of "the right way" to do something.

When Being Skilled Isn't Enough

Looking back at the production of that record, yes I had the musical expertise, but our partner had a much deeper understanding of the community we were serving. As a musician who was mostly American, I wanted the album to be much more progressive than it was shaping up to be. I wanted to take more creative risks, but the brakes kept getting put on. I wasn't taking into consideration what my mentor was prioritizing, and that was the needs of the "customer". The community I was making music for wasn't necessarily interested in the risks I was trying to make nor would it have benefitted them much. He reminded me of the needs of our audience, and his user-centered perspective helped pave a way for this new thing to take root and land on listening ears. Luckily, I had wonderful, and much-wiser team members who reminded me of this.

And we find similar predicaments in engineering teams today. We want to build on the latest and greatest tech. We want to take technical risks or work on things because it is a more cutting-edge way of doing things. Maybe we want to upgrade a major version of a library that would cost several weeks of development on our roadmap. While these may be great ideas in isolation, we may not always be able to tie these changes to features that directly benefit the business. Sometimes, we as engineers need to be edited to keep our work focused on the goals we are trying to achieve.

So yes, I can now appreciate the lessons learned by these fierce negotiations of my past. I see now, that we were able to create something that was familiar enough to be mostly* accepted, however different enough to challenge, inspire, and spark conversations among communities in our diaspora. Smart and talented people can accomplish some amazing things, but only if they're aligned. Make no mistake, getting alignment is challenging.

* Actually, we got banned in one of the dioceses. I received a letter from a well-respected Bishop, telling me that our music was not allowed in any of the churches in his geography. While that may seem like a setback, at the time it reminded me that we didn't keep it too safe. 

Letting Go: Side-Effects May Include...

Getting on the same page as a group, requires individuals to give up a degree of control. This is required when building software as a team. Usually, letting-go is usually met with the acceptance that comes with being a professional. But software engineering often attracts people who put so much of themselves into their work. Because of this, letting-go can be met in with the following emotional responses:

  • Frustration: Often times, including myself, I've witnessed engineers be frustrated when a particular course of action, or even a pull request, is not approved, or requires changes that would move the outcome in a completely different direction. You think to yourself, "would the Sistine Chapel been what it was today had Michaelangelo been ruled by a committee?" Righteous indignation takes over, or maybe it's the blow against one's ego that can happen when work is challenged in its current state. Been there? I know I have.
  • Apathy: Tables aren't flipped, but hands are up in the air. (And I don't mean this celebratory emoji 🙌.) Apathy leads to detaching from both the work and the goal. While the impact of this is not immediate as the previous item, it does make teams vulnerable to morale being slowly chipped away. This will have long-term and debilitating effects.
  • Acceptance: There are others, however, who can remain detached enough from their work, but see it as part of a collective, and will welcome changes and advice, because ultimately, there's a shared trust in the team, and a strong commitment to what the team is trying to achieve.

But Don't Follow Blindly

We have to be aligned to make great things happen. And alignment means letting go. That's not to say that blood doesn't get spilled, or tears won't flow. That should happen with a team of experienced individuals, however, there's a mutual respect and striving for what's best, collectively. And this sort of refinement by an engineer and their peers, can lead to some great outcomes. (I'm not advocating for decisions by consensus, but that's another blog entry.)

As engineers who work on teams, we have to constantly manage an important balance. It's one between what each of us brings based on our individual experiences, convictions, and baggage, with the roles we're assigned, with the goals of the organizations we work for. Now there's absolutely a place to draw some hard lines, and offer non-negotiables, when you see a particular course of action is going to put the big goal at risk. Those should be rare occurrences. Be sure you understand the difference between risks to the goal, vs. risks to the way you want to do things.

But There Is Hope: Some Helpful Tips

Having trouble letting-go? Like my experience with making music, and my experiences in the present: here are some strategies that help me do just that:

  • Focus on the goal: The shared goal you and your team have, should be one that you really believe in. If you're not on board with the goal, you may want to reconsider your employment situation. But let's assume you're still on board with what your team is trying to achieve. Having a larger goal that drives you is extremely important for satisfaction in one's career. That goal has to sit a step beyond how you write code. Commit to a goal and it will  help you entertain other possibilities of achieving it. This will make it possible to let go and try things a different way.
  • Make it about the work: Don't take things personally! It's not about you, and most of the time, your team isn't focused on you, it's about the work. By having the discipline to not take things personally, you allow your team to challenge you, and then it builds trust that allows you to challenge your team. Because collectively you care about the same thing, the work.
  • Get a hobby: Ok, so your team has a norm of doing very strict test-driven development. (I've been on such a team, before.) The engineering lead wants to see the tests written out before a single line of code is written. What a drag, right? You love building software by running and gunning it. So do that! Just don't do it at work. By having interests and outlets outside of what you're doing at work, allows you to get go of things that may be very personal to how you work, because you have other areas in life where you get to do these things. You can let go of the small stuff, so you and your team can work better together to achieve the big stuff!

Parting Words

Decades later, I barely remember the things I argued about while making that album. I value the music we made and the things we achieved so much more than what we had to lose. I tell this to all my fellow engineers out there who find themselves sometimes frustrated.  In the constant negotiation and struggle, we hope to make each other become better engineers and help refine our individual an collective crafts. By staying committed to a bigger picture, we give ourselves a better chance to achieving the things we want to. And it goes back to an old proverb that has come across my path time and time again: alone, we can move quickly, but together, we can go far.


Book Review: SQL Antipatterns

SQL is an interesting yet temperamental tool in the programmer's kit. You can use it to find amazing insights in your data, but you can watch a poorly formed query grind your application to a halt. SQL Anitpatterns wants to help you avoid the latter by identifying common pitfalls when designing and using databases.

The book identifies twenty-four antipatterns and breaks each down in the same formula -- an objective one is trying to achieve, the antipattern typically used as a solution, how to spot this antipattern, the legitimate uses of the antipattern, and alternative solutions. The author introduces each antipattern with a brief example scenario followed by a summary of the objective people are typically trying to achieve.

Next, examples of the antipattern are given with an explanation of why you would not want to do this. Even with examples, the author provides other ways to recognize the antipattern; most of these are questions you are likely to ask or hear colleagues ask. If you hear or ask "How do I do X", that would be a good opportunity to pull this book off the shelf, give it a quick skim, and possibly avoid a pitfall.

However, the author recognizes there are legitimate uses of each antipattern and presents them before the solutions to avoid it. This allows you to decide if this is a pitfall to avoid or a necessary evil in your application. Finally, the appropriate solutions are presented with attention given to how the solutions might differ between database vendors.

Easy to read and digest, this is the worthy reference book to add to your shelf. As you extend or update a database and related application code, you will find yourself reaching for it to reduce the likelihood of being paged at night by a misbehaving database.


Type Safe REST Client with Kotlin and Retrofit2

This article was originally posted on Will's Blog.

If you regularly work with REST endpoints you're probably used to a lot of tedium. Between carefully constructing the parameters, encoding data in just the right format, efficiently sending the requests, parsing the results and handling errors at every step along the way; there is a lot of room to make mistakes.

For simple APIs, it often makes sense to manually format the request and send it out. Checking a status code, and maybe mapping results to an object aren't that big a deal for a simple API. But what if there are 20 different endpoints? Or you need to manage authorization headers? Eventually, it makes sense to start looking for a wrapper library, or maybe making your own wrapper layer.

That's what this post is about.

For JVM developers, pairing Kotlin, Retrofit2 and Gson make it easy to bang out a type-safe client wrapper.

Let us jump right into the code:

// Create data classes for serializing inputs and outputs.
data class Results<out T>(
    val next: String?,
    val previous: String?,
    val results: List<T>
)

data class CryptoQuote (
    val ask_price: Double,
    val bid_price: Double,
    val mark_price: Double,
    val high_price: Double,
    val low_price: Double,
    val open_price: Double,
    val symbol: String,
    val id: String,
    val volume: Double
)

// Bounds, Intervals, and Spans are enum types.
data class Historical (
    val data_points: List<DataPoint>,
    val bounds: Bounds,
    val interval: Intervals,
    val span: Spans,
    val symbol: String,
    val id: String,
    val open_price: Double?,
    val open_time: Date?,
    val previous_close_price: Double?,
    val previous_close_time: Date?
) {
  // Nested data object used by Historical
  data class DataPoint(
      val begins_at: Date,
      val open_price: Double,
      val close_price: Double,
      val high_price: Double,
      val low_price: Double,
      val volume: Double,
      val session: String,
      val interpolated: Boolean
  )
}

// Define interface using Retrofit annotations and data objects.
interface RobinhoodCryptoQuotesApi {
  /**
   * @param ids comma separated list of ids
   */
  @GET(marketdata/forex/quotes/)
  fun getQuoteIds(
    @Query(ids) ids: String
  ): Call<Results<CryptoQuote>>

  /**
   * @param symbols comma separated list of symbols
   */
  @GET(marketdata/forex/quotes/)
  fun getQuoteSymbols(
    @Query(symbols) symbols: String
  ): Call<Results<CryptoQuote>>

  /**
   * @param symbol id or symbol for a pairing.
   */
  @GET(marketdata/forex/quotes/{symbol}/)
  fun getQuote(
    @Path(symbol) symbol: String
  ): Call<CryptoQuote>

  
  @GET("marketdata/forex/historicals/{id-pair}/")
  fun getHistoricals(
      @Path("id-pair") idPair: String,
      @Query("bounds") bounds: Bounds,
      @Query("spans") spans: Spans,
      @Query("interval") interval: Intervals
  ): Call<Historical>
}

This is a complete listing of the Robinhood market data endpoints. If you aren't familiar with Kotlin, this code is essentially declaring an interface and some POJOs. By sprinkling in some special annotations used by Retrofit2, it can be converted into a concrete object for accessing the endpoints. Errors are even handled by the Call objects which wrap your results.

To go from endpoint definition to concrete object we need to invoke the Retrofit2 builder. While the HttpClient doesn't really support anything besides OkHttp, there are hooks to adapt the serialization and call adapter layers. Here you can see I configure OkHttp to insert a token header, and add Gson and Enum adapters for serialization.

  // Inject the authentication header.
  private class TokenInterceptor(private val token: String) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
      val newRequest = chain.request().newBuilder()
          .addHeader("Authorization", "Token $token")
          .build()
      return chain.proceed(newRequest)
    }
  }

  // Build a token aware HttpClient
  val tokenHttpClient = OkHttpClient.Builder()
      .addInterceptor(TokenInterceptor("my-token"))
      .build()

  // Build the api
  val api = Retrofit.Builder()
      .addConverterFactory(GsonConverterFactory.create())
      .addConverterFactory(EnumRetrofitConverterFactory())
      .baseUrl("https://api.robinhood.com/")
      .client(tokenHttpClient)
      .build()
      .create(RobinhoodCryptoQuotesApi::class.java)

  // Make a request 
  val response = api.getHistoricals(
      idPair = "3d961844-d360-45fc-989b-f6fca761d511",
      spans = Spans.DAY,
      bounds = Bounds.TWENTY_FOUR_SEVEN,
      interval = Intervals.DAY
  ).execute()

  // Print out some data  
  for(data in response!!.body()!!.data_points) {
    println(data.high_price)
  }

And that's all! In the final code, there was some additional work to make an OAuthTokenInterceptor, but all of that complexity is constrained to the constructor. Defining the endpoints is a matter of typing out the data classes for serialization, naming your methods, and applying the Retrofit2 annotations.

All in all, Retrofit is a very concise way to define a client library in a type-safe way. The code described in this article can be found on GitHub.


Book Review: Agile Retrospectives

Agile Retrospectives: Making Good Teams Great*cough* *cough* Goodness... It's a bit dusty around here. Nearly a year of silence will do that. One of the goals our team had last year was to blog more. This effort failed. But, why did it fail? How do we determine what went wrong and what actions to take to ensure we do better going forward? There happens to be a handy tool in the agile / scrum toolkit known as the "retrospective". A mini retrospective of what happened with our blogging might look like this.

What did we do well? While we did not generate much content, the content we did generate was something the writer was passionate about. What could we have done better? We could have encouraged the team to write about anything. It does not need to be a long, involved post. Just write about something that interested you. How can we improve things going forward? Have someone leading by example and being a resource to cajole ask people to provide more content in addition to theirs.

This is a simple example from my own mind. Things become more complex when trying to ask these questions from an entire team. The most invaluable resource I have found for learning how to lead retrospectives is Agile Retrospectives: Making Good Teams Great. This is typically one of the books I regularly gift to co-workers.

The book is only 142 pages long but contains a wealth of information and tools to use. It is organized into three sections. First, three chapters are dedicated to explaining how to prepare to lead a retrospective, how to tailor it to your team, and the actual process of the retrospective meeting. The next five chapters outline various activities you could use for each step of the meeting. The final two chapters provide guidance on how to take all these ideas and apply them to lead retrospectives.

The best advice I have for consuming this book is to really absorb the first three chapters and final two chapters. Much of the advice there will help immensely in leading a retrospective and many other meetings. Skim the next five chapters; find a few activities your team might connect best with and start using those. Revisit these chapters every so often to find new activities to keep your retrospectives fresh.

Even if you are not in charge of leading retrospectives or other agile meetings, the advice carries over to leading or participating in other meetings. Also, the retrospective process is a useful tool outside of software development. You can have a retrospective about anything -- your recent home renovation project, your car buying experience, your vacation plans. There are few titles I gush over and push onto people. This is one of them, a title I firmly believe should be on every developer's shelf.


Adventures in Two Factor Authentication

Off we go!

Another hack week was upon us, and I had a definite idea in mind. I wanted to add two factor authentication to our web application. Having enabled it on web sites I use regularly, I was curious to see how difficult it was to implement and learn about the best practices associated with it. A bare bones implementation turned out to be remarkably trivial.

Our application runs on PHP, and it took minimal Google-fu to determine the RobThree/TwoFactorAuth library was the best option to try first -- well maintained, great documentation. One quick

composer require RobThree/TwoFactorAuth

to pull the library in, and it was right into setting it up. First hurdle reached! Our authentication code needed some tender loving refactoring to be able to support having two factor authentication enabled for your login or not. Ah... the satisfaction of being able to clean code up including squashing a bug that has long irritated you...

Once the authentication code was cleaned up, actually adding two factor authentication was trivial. It took more time to refactor our existing code than it did to use the library to generate the shared secret, display the QR code for scanning, and verify the entered token against the shared secret.

Which thirds to invite to the party?

By default, the PHP library reaches out to an external Google service to generate the QR code. However, you can use a local library to generate it if security of sending the shared secret over the wire is a concern. Hrm... Should I be concerned about that? Should I use an external third party service for generating QR codes, or should I compose in another third party library into our application?

Did a bit of research and found no compelling argument either way. Thinking it through, let's say I use an external third party and send the shared secret to them. What is the attack surface? They could sniff and record the secret, but they get no other details. How would they tie it back and use it with an actual username? They would need access to our database or server to make that association. If they have that, the game is already up, and they likely don't care or need the secret anyway.

What other drawbacks might there be then? There are two that spring to mind. First is the need to make an HTTP request to the service to get the QR code back. You are now dependent on the service being up and the network being fast and stable between you and the service. Second is the (likely) closed nature of the service; you have no way of vetting the code to make sure there are no shenanigans behind the curtain.

Given all of that, I stuck with the default Google service. Google knows just a little bit about keeping a service up and running, and their QR code service has likely been battle tested as much if not more than any other third party library I could use locally. However, the RobThree documentation provides an easy example of using a local library should the need or desire to switch arise.

Drifting away...

It was demo day; time to practice before presenting my work to the rest of the team! I'll just plug in my username and password... Type in the token from my device, and... Wait... Why am I not logged in? What did I break with my last commit?! All my work is for naught! I'm a frauuuud!

OK... OK... calm down... There must be a logical explanation. What would make a token work yesterday but not today? This is a time based protocol... My phone is setup to automatically keep my time correct. Let's check the time on my server... AHA! My local vagrant instance is not running any time synchronization and has decided to drift away by about an hour. One quick NTP query to fix that, and... We're back in business! Whew... Crisis averted; demo proceeds without issue.

I've learned an important lesson about TOTP. Make sure your server is automatically keeping the time correct!

Dude... Where's my phone?

If you are like me, you have used two factor authentication on other sites and have come across "recovery codes". These are meant to be written down and stored offline; if you were to ever lose the device that generated the token for the site, you could enter one of these codes to complete authentication and establish the shared secret on a new device. While I had an idea in mind of how this could be implemented, I wanted to see if there were any established best practices people follow. How many codes should be generated? How should you generate each code? What is the best way to securely store them?

After some digging, I found... nothing. I've seen sites provide anywhere from five to ten codes with the codes varying in length. I have yet to implement this feature but am leaning to at least generating five codes. However I end up generating them, I will store them exactly like passwords -- as encrypted salted hashes.

I need more...

One other flow I have encountered with other two factor enabled sites is the need to input multiple tokens if the server seems to think your token is out of sync. Again, I could find no information on best practices. How many tries should you give the user before entering this flow? How many tokens should you ask for? Does this really add any security value? For now, I am unlikely to implement this flow. While some big names use it, I'm not seeing much benefit from this flow versus just allowing the user to keep entering a single token.

That's all folks!

The RobThree library made it easy to add two factor authentication to our application. Follow the examples in the documentation, and you'll be up and running in no time. However, there seem to be no best practices (none I could easily surface at least) around the items like recovery codes and "out of sync... give us more than one token to proceed". Did I miss anything? Have any best practices from your own implementations? Sound off in the comments and let me know.


Staatus: Exploring the Slack API

Back in April, Slack released a cool new feature that allows you to set a status message on your account. Some of the examples they provide are:

  • In a meeting
  • Commuting
  • Out sick
  • Vacationing
  • Working remotely

"This is awesome!," I thought. "Now I can do what did on AIM in 1997!"

Slack did sprinkle this status in various places in the UI, but it's still a pain to go searching for it, especially if you haven't chatted with a person in a while. Plus, there doesn't seem to be an easy way to see a compiled status for a group (e.g. @engineering-team).

Enter: Staatus

I built Staatus on a PHP framework called Silex. It's a microframework based on Symfony that provides the guts for building simple single-file apps. Here's an example:

require_once __DIR__.'/../vendor/autoload.php';

$app = new Silex\Application();

$app->get('/hello/{name}', function($name) use($app) {
    return 'Hello '.$app->escape($name);
});

$app->run();

Staatus allows you to see a compiled status of an individual, a particular team, or everyone in a channel. The code is over on our Github.

I have to hand it to the devs at Slack. The API was super-easy to work with. I made use of these REST commands:

With that, I was able to display both status emojis/messages, but also a blue diamond if the person is online:

The Code

Coding this up was very straightforward. I'd say the only quirk I ran into is that the calls take too long, and Slack does not like that. If your plugin doesn't return within a few seconds, you get an error message. My plugin is hosted on Heroku, so between the lag of Heroku waking up instances and the time it takes to run all the API calls (which can amount to many, especially when Staatus is run against a team name), I needed to figure out a way to return a delayed response. Normally, in a single-threaded language like PHP, that's not easy. Most frameworks follow a very "serial" manner of generating a response:

  1. A request comes in (possibly with parameters).
  2. A response is generated.
  3. The response is returned and the request dies.

So if step 2 was taking too long, how was I going to work around Slack's request time limits? The answer comes in Silex's $app->finish() method. It is documented as:

A finish application middleware allows you to execute tasks after the Response has been sent to the client (like sending emails or logging)

Here's how I used it:

$process = function(Request $request) use($app) {

// first, validate token
 $token = $request->get('token');
 if (empty($token) || $token !== VERIFY_TOKEN) {
 $app->abort(403, "Invalid token.");
 }

$response = [
 'response_type' => 'ephemeral',
 'text' => 'Gathering staatus...'];

// just return; the rest of the processing will happen in finish()

return $app->json($response);
};

$app->get('/', $process); // for testing
$app->post('/', $process);

$app->finish(function (Request $request, Response $response) use($app) {
...
}

As you can see, my $process method returns immediately and I do the rest of the processing in a finish() method. This allows me to take as long as I'd like (give or take) to return a response back to Slack using a one-time response URL they provide. (Technically, you can't take as long as you'd like to respond. Slack has a hard limit of "up to 5 times within 30 minutes"):

$response = [
 'response_type' => 'ephemeral',
 'text' => $text];

$client2 = new Client(['base_uri' => $responseUrl]);
 $response2 = $client2->post('', [
 'json' => $response,
 'verify' => false
 ]);

And that's all, folks. So, go ahead and download Staatus, deploy it on Heroku, and you'll be partying like it's 1997 all over again. BOOYAH!


Traackr :hearts: Instagram

As we continue to support the influencer marketing programs of our clients, we have found it imperative to consume and dig as much as we can out of influencer content created on Instagram. Adding to the consumption of post captions and metrics for engagement reports, Traackr also gives users the ability to harvest the photo tags on influencer posts and make them searchable !!! :)  

Ready? Check it out.
Let’s look at the Traackr profile of the most decorated olympian in history:

Michael Phelps' Traackr influencer profile.

Now, let’s find a post that has photo tags on it.   Oh look...here’s a good one (they seem to be having a lot of fun eh?):

Michael Phelps' instagram post viewed from his Traackr influencer profile.

Now let’s search for one of those tags. I like @casamigos too… read my mind :wink:wink:  Voilà!

Searching photo tags through Traackr.

But … I thought keyword queries only matched the actual content of the post. All I see is ‘Boys will be boys!!! #meldman’. How did you do it?”  

Well… here’s an oversimplified explanation of how it works.

Making photo tags searchable at Traackr.

So, at step (1) we get the post from Instagram’s public API. At step (2), we store it in our search engine and at step (3) we query for “@casamigos”.  And yea...you guessed it! The real magic happens at step (2).

When we’re indexing content, we append the photo tags to a secret field that keyword queries are executed against. But what we surface in the UI is a field that contains the original post “Boys will be boys!!! #meldman”.

Since you’re such a curious cat, here’s an excerpt of what the record looks like in our search engine:

{
  "_type": "post",
  "_source": {
    "postUrl": "http:\/\/instagram.com\/p\/BTIKhMygox-",
    "rootDomain": "instagram",
    "author": "m_phelps00",  
    "postContent": "Boys will be boys!!! #meldman @randegerber @makenagbc @jjd7007 @stuttsydlc @casamigos @romanstutts",
    "postDisplay": "Boys will be boys!!! #meldman"
  }
}

Hint: See the difference between postContent and postDisplay?

So why do we do this?

We want to do more than just track Instagram content to compute the metrics that allow us to analyze an influencer’s reach and resonance. We believe that with Instagram’s ever growing outreach and business impact, the more value we derive from its content, the more meaningful will be the insights we provide to organizations that invest in the practice of influencer marketing.

As it pertains to this particular feature, our customers are able to get more insights on brand mentions by using our platform to match mentions on photo tags and get further analytics and reports on them :)


Great Scott! HackWeek 5/1 Recap

Prologue

It’s 6am on a Thursday morning, and I’m realizing the feature I had built last night to demonstrate Vue.js’s double-binding capabilities has regressed due to some code-reorganization I decided to do last-minute.  I thought I had done a good thing, but I ignored my sensibilities to quit while I was ahead and just do that “one last thing”.

So I put on a pot of coffee, and I spent the next few hours not only fixing what I had broken, (in order to make sure my demo doesn’t fall flat on its face in front of my esteemed colleagues), but I also tried to strategize the best way to communicate the week-long and tearful journey towards carving out a path to refactoring an important yet 3-year old feature on our app, in a way that employs the best that VueJS has to offer without throwing the jQuery baby out with the bathwater, all in 360 seconds. Why? because it’s our Hack Week Demo Day!

Hack Weeks @ Traackr

Once a quarter, we take a collective pause from roadmap-focused development, and carve out an entire week for the engineering team to work on projects of their own. What started out as a monthly hack day, we quickly realized that a single day was not enough for any of us to really flesh out let alone implement our ideas. Experimentation needs time and iteration if it would materialize into something solid; we needed more than a day to experiment, fail, retry, and repeat!  So, we decided to have our hacks less frequently but for a much longer period of time, and thus Quarterly Hackathon was born.

The 5/1 Hackweek Recap

This particular Hack Week arrived shortly after we completed a project that the entire Engineering team had been working on for the good part of 6 months. The project was a set of tremendous improvements and new functionality added to the Analytics Suite of the Traackr App, altogether has been named Integrated Influencer Intelligence (or I3).

The temptation after such a sizable release, is to use this unstructured time to make all those small improvements to what we just released vs. spending the time looking at new problems with fresh eyes. This time around, most of the team spent time on fairy new ideas, with some folks improving on existing ones.  By the time the week ended we a whole collection of demos and proof of concepts ranging from: Devops dashboards, to Slack integrations, to enhancements to security, just to name a few.  But like most Hack Weeks at Traackr, it was a great time to shift gears, recharge, and inspire new ideas not just for our team, but for the company as a whole.

So, without further ado, let’s dig into some of the Traackr team’s Hack Week projects, in the gallery below:

Our 5/1 Hackweek Projects Gallery

The gallery below only describes high level info on the projects.  More in-depth articles about our Hack Week is still to come!


Introducing: Enragement

Traackr is the leader in the Influencer Management space. Our platform is an enterprise system of record to manage, expand, validate, and scale an influencer marketing program. Though there are others that try to copy us, we feel we do it best. That's why we are excited to announce an upcoming feature: Engagement. Our customers will now be able to accurately measure engagement with influencers.

But we didn't want to stop there. Let's face it, once we release this feature, there will be others not far behind with similar functionality. So we are already busy working on the NEXT NEXT big thing in influencer management.

Introducing the NEXT NEXT big thing that NO ONE else is offering: Enragement. What is enragement? It is the perfect feature in these highly polarized times. Our “secret sauce” is an algorithm that measures not only how ENGAGED an audience is with a tweet, but how ENRAGED the author is.

Interestingly, they are two sides of the same coin – symbiotic concepts that feed off of one another. The more ENRAGED an author is, the more ENGAGED their audience becomes.

Take this series of tweets, for example. On the heels of a difficult meeting with Angela Merkel and a congressional hearing about investigations into Russian election-tampering, the POTUS sent out these tweets:

Our enragement algorithm kicked in and gave these tweets an enragement index of “TTF” (“Through the Roof”). Within hours, the tweets had thousands of replies, retweets, and favorites. Imagine if these tweets were about your product. That's money in the bank. YUGE!

How do we do it? Well, there's only so much we can divulge about our secret sauce. This diagram provides an overview of the non-confidential aspects of the algorithm:

Running any text through our algorithm will measure its rage score through a proprietary combination of:

  • bad grammar (a sign of anger)
  • overuse of CAPS
  • repeated characters (especially exclamation points)
  • cursing
  • a selection of low-brow emojis (e.g. “poo”)

That's all we can share for now. If you'd like to see a demo of how your influencer marketing programs can utilize our special algorithm to craft the perfect tweets for maximum enragement, please call our sales team today.

HAPPY APRIL FOOLS' DAY!


Setting up your Mac

Setting up your Mac