Categories
Programming

Frindcare, some improvements

After getting to a working level with Friendcare, my web app to track friending and defriending on Facebook, I was still doing some tweaks. Some of the tweaks is to improve functionality, some of them to fix some broken behaviour by the services I use (especially Facebook). This is a little summary of what I have learned in this short time.

Changes

Heroku

The very day of my last blogpost, when I actually had others sign up as well, Heroku had a few hour long outage. That was quite unfortunate, and it was annoying to see the “Application Error” page, which pretty much hides what really happened. In real production environment probably I would have to run things on multiple independent platforms so if the platform itself is the one that crashes, the site could be just switched over. This time I’m just taking it simple, make a personalized maintenance page, which I can turn on in this case, or when I’ll really need some maintenance time. Also, played around Google Web Fonts, so can have the good old school Press Start 2P on this one.

Friendcare is offline for maintenance
Friendcare maintenance screen

It would be nice if in case of trouble I could use a web interface to trigger maintenance mode. Might build a service for that, though now that I think of it, that will have to be hosted outside of Heroku. Also, later might do an application error page as well, just in case. Might even choose a mascot for that. Though probably not.

Fonts

Besides the error page, I was playing around with other fonts for the main interface as well. In the end the current one is Crimson Text, which should be quite readable even with very different font size. It is mostly good, though it doesn’t play completely well with Twitter Bootstrap, the button texts for example are not totally well aligned vertically. Might have to look around the fonts a little bit more.

Friendcare header layout
Tweaked layout, and it actually already has results

Facebook

Facebook has so many weird things going on, that I can barely wrap my head around it. One of my impression, which probably shouldn’t surprise me, that they are most likely not using their own APIs, otherwise it wouldn’t have such huge bugs in it. Another impression is, that somehow they manage make everything almost good, but in some way completely bad.

Graph API reliability

Since the entire site relies on regularly polling the user’s friend list, getting that list consistently is a must. Somehow the Graph API occasionally misses some friends: they don’t appear in the list and I mistakenly assume as lost connections. An hour later, when polling again they are back in the list, so they show up as friendship gain. That doesn’t work very well. This happens a lot, so I had some algorithms in place for that and sometimes had to manually clean up the database (which I really shouldn’t do if it can be avoided).

FQL

I can also use the Facebook Query Language to get the information I want. It is quite straightforward, they even have the expression among their examples:

SELECT uid2 FROM friend WHERE uid1=me()

This is pretty fast as well, maybe half the time of the Graph API request. There’s one problem, though: it returns wrong results. Not entirely wrong, just wrong enough. The list I receive seem to have a bunch of invalid user IDs, such that it doesn’t belong to anyone. They just don’t exists, but I still receive them. So while Graph API suffered from false negatives, FQL suffers from false positives. Fortunately there seems to be a workaround, in the form of a deeper query such that

SELECT name, uid FROM user WHERE uid in (SELECT uid2 FROM friend WHERE uid1=me())

Here I will actually throw away the ‘name’ part, but at least I know that the IDs that I receive do belong to actual people. So far this seems to be the most reliable, though it takes as much time as the Graph API request, or maybe a bit more.

In the end, currently I query both the Graph and FQL in sequence, compare the results, note if they differ (for debugging purposes) and use the FQL result since that seems to be more reliable. Will check back later to this part, when I have more information to go on.

Offline access

Offline access is pretty important for this kind of service, because it’s not that useful if we can only check the results when the user comes to the page. Unfortunately, the ‘offline_access’ permission has just been removed. Instead the access token lives for 60 days, after which one has to get a new one by logging the user in again. I’m not saying it’s unreasonable, maybe even better since I don’t have to ask for any extended permission over the ones that are granted to every app automatically, but have to keep in mind. It might complicate things. Also reminds me that other apps that I’m using with Facebook (e.g. ifttt) will have some problem because of this thus I will have problem with this. Better check with them.

Send message prompt dialog

I kinda understood when they have removed the ability to send message to others on the user’s behalf without their interaction, that’s such a tempting spam delivery system for most, I presume. On the other hand, for a long time at least they had (or I seem to remember they had) a send dialog, where I could prompt a user to send a message to someone else: they write the actual message and they click send. On the other hand, the current Send Dialog has a required parameter ‘link’, this it is no longer possible to send “just a message”. This must be a relatively new chance, since the dialog’s page describes it as:

The Send Dialog lets people to send content to specific friends.

Fair enough, that’s exactly how does it work. On the other hand, just one level up, the Dialogs Overview says this:

The Send Dialog allows a user to send a Facebook Message to one or more of their friends.

Content vs. message, subtle but crucial difference. Thus in my app I cannot have a “send message to this user” button, unless I attach some kind of link to the message. Now this feels really spammy to me.

Overall

It is good to add a few more features, because I can use it better as well, and I learned a lot too. Might add a proper dashboard, a deregister option, notification to email or (if I can figure out how) Facebook message, stats, better layout. Or whatever suggestion I receive.

Finally, the most important thing that it works. In the last week I found two people who defriended me for whatever reason, and I wouldn’t have known about otherwise. They were not close ones, so not going to pursue them, but it could have been otherwise, so at least it’s good to know.

Categories
Programming

Friendcare, satisfying a curiosity

Quite often I find services I’m using inadequate. Something is missing, or not working the way I hope, I wish it could be changed. In a fraction of the cases it can actually be changed, and an even smaller fraction I go and change it myself.

This time it was bugging me that while I am always aware if I have new contact established on Facebook (or colloquially “friended someone”), but there’s just no way to know if someone cut ties (“defriended”) me. In some ways that knowledge is just as important, since the first means I succeeded in being interesting to another person in some way, the second means I was actually annoyance – not just being ignored and never talked to but people took the effort to never hear about me again. Recently quite a few people did that to me, or at least it’s only now that I try to find them for this or that but I can’t. I never want to be caught off-guard like this again, so I made Friendcare.

Friendcare interfacing

It was mostly an exercise in web app building, since if it was only for me, I could have just set up a script on my server that monitors things. It’s more fun as well. First I started it a long time ago, tried to work on it and rewrote from scratch a couple of times until getting here.

What does it do?

In this one the site just gets the user’s friendlist (a list of IDs) from Facebook and compares it with the last known friendlist. If there are new IDs, they are considered friend gains, if there are missing ones, those are friend losses.

Actually it got pretty complicated logic (for my usual thinking) inside because of the asynchronous management of good NodeJS apps, had to think a lot about what information is available at what step and what time of the usage. It also didn’t help that I haven’t really planed the user experience (UX) first, just started to code. Some of the things are surely pretty terribly done because of premature optimization and scaling I was doing while only havng a single user of the site. All in all, it’s an absolutely horrendous mess in the inside that still seems to implement a suitably close approximation of what I wanted. Surly will need some refractoring sooner rather than later.

The parts

It’s amazing how many different parts I need to use to make one complete site work, a total web-tech-soup. Everything is in a library or in an external service. It’s good and bad – good because other people did the heavy lifting for me already, bad because every one of them needs a non-trivial effort to learn and all of them different. Nevertheless, trying to keep things minimal. At the moment it’s NodeJS on Heroku, with MongoDB and using Heroku Scheduler to trigger the update service. The other modules and parts are:

Everyauth

Without Everyauth nothing would work, it handles the Facebook authentication on the backend. Also, it gave me ideas how the site can be extended to multiple services / multiple social networks.

Fbgraph

There are so many interfaces to talk to Facebook, and the heroku-nodejs app I started off from uses one of them as well. That just seems to be too specialized for an example app, not in functionality but in implementation. Instead I found myself another library, fbgraph, and so far so good. If I really wanted to, I could even easier interface just the Graph API, but no need to do that at the moment.

Mongoose

I choose Mongoose/MongoDB to store the associated data, well, basically because MongoLab had the largest free database offering of all the databases I have checked. So far so good. I like the schemaless database, though already run into problems when I was updating wrong fields in the dataset I was surprised that the results didn’t show up at the right place. I guess that’s a danger I can live with at the moment. Will have to learn more about it, how to back things up, how to maintain it well, and about mongoose and it’s schemas.

Underscore

The core functionality is basically taking the difference of two sets, and in general there is quite a bit of set manipulation, so Underscore works very well, I used for a couple of other parts as well (reduce, groupBy), and it works well. The whole thing feels like it should be part of the base library.

Twitter Bootstrap

While risking that I’ll look exactly the same as many others, Bootstrap does give some good-looking results with moderate effort. Will have to do some tweaking because I know so little about making good UIs, but it’s a start.

EJS

Used EJS for templating, and it’s great. Fast, flexible, and it’s not too bad that I have to fill in most of the HTML manually. I will know more about the structure of the client facing  side of the page more than I would otherwise.

Lessons learned

There are things that went well and not so well.

  • Maybe the most important: Facebook is unreliable. Sometimes I got missing people in the list that appear in the next update again. This happened when using Graph API, will have to see if FQL is any better. From my experience: not, it just has different problems.
  • For a while I started to write in Coffeescript, but then I just spent too much time trying to figure out how to get the right things, so went back to Javascript, at least until I learn that and can move up again to that higher level.
  • From the app’s point of view, some simplification needed. Too many middleware and helpers, this I quite often not sure about what is the state of my data, what variables were available and what are not.
  • Forums are not always helpful, quite often people have really dumb answers to questions, so have to figure things out myself.
  • Too many successful libraries mean that the library-soup will inevitably cause problems, and people start writing new libraries that connect and unify the old ones: mongoose & backbone, mongodb & everyauth, so much magic (ie. behind the scenes stuff) happens.
  • I still like to make logos and facicons, though I’m sure they are terrible, it makes good playtime in Inkscape and Gimp. Might have to change the colours, it does remind me of a strange toilet logo…
Friendcare logo

Aftermath

In the end, I’m solving a very narrow problem at the moment, a problem that so rarely arises, that I don’t even know if it will happen again. But if it does happen, without this I wouldn’t know about it, so still worth it.

Might extend it later to count Twitter followers, Google+ circles, Github watch/fork, whatnot… But that’s later when I see how does this work, I care much less about those than my “friends” because of the symmetricity of it .

The good thing is that currently it works well enough that I kinda got this off my chest and can back to making a FUSE module for Ge.tt, a group based location sharing mobile app, an app to connect my Goodreads to-read list and bookstore databases,  adding Open Graph and Rich Objects to Octopress, getting out an update for WatchDoc, or even check out the games I just got from HumbleBundle. But will come back to this, will have to make it better (it’s a compulsion).

Finally, if you the site, let me know your suggestions, I’m eager to learn. The source is up on Github.