Flight at TweetDeck

Flight is a new JavaScript framework conjured up by the folks at Twitter (big shout out to @danwrong and the rest of the @flight team). At TweetDeck we have had the opportunity to work with a pre-release version of Flight over the past few months and have now shifted all new development to Flight.

When I first heard about Flight, I thought it was a brilliant idea. A simple framework done right. The agonistic nature of modules really appealed to me, as did the event-driven architecture. Having now used it on a large application I can say with certainty that it did not disappoint and I'd thoroughly recommend taking a good look.

What I want to talk about here is our experience with Flight at TweetDeck, mainly around our approach in converting TweetDeck to Flight, as well as how we've organised our data and UI components.

TweetDeck: before Flight

TweetDeck has been around for nearly two years as a JavaScript application (one of the largest in the Chrome App Store) and has already undergone two architectural changes. At first, modules were built as straightforward namespaced javascript objects. Understanding that this was perhaps not the best long-term approach, the team switched to a class-based approach and ran the two side-by-side. 

For small applications, either one of these techniques can be quite effective in the short term, but over time they become hard to maintain and harder to refactor, even at scale. For large applications it requires serious rigour to stop things from getting rapidly out of control.

Deep-linking between modules is a big factor in this. TD.vo.Column.get() might make sense in the context of an instance of TD.vo.Column, but try finding every single reference to a method called 'get' in your codebase and you'll quickly understand why refactoring it could be a serious challenge. This is especially true when the instances get[a] assigned to other identifiers, creating references like column.get, col.get, etc.

TweetDeck's modules had become interdependent to the point that we recently found it impossible to create a dependency tree. The spaghetti code monster had reared its ugly head.

TweetDeck: after Flight

To be honest, the codebase is much the same as it was. There certainly isn't any sense trying to rebuild tens of thousands of lines of code for the sake of it. 

We've created a new directory in our script folder in which all flight components, tests and libraries, sit. The hope is that at some point our flight/app directory will drive the entire app, but that's a long way off.

Luckily, Flight makes it very easy to bolt new components in on top of an existing structure.

Whenever a method would have referenced another namespaced method, it now fires an event, instantly allowing us to stop worrying about refactoring deeply-linked methods. It's a lovely feeling, removing all those old namespaced references. For example: 

where we make so many assumptions about which objects have been instantiated and which methods they expose. We then replace them with event triggers and listeners that assume nothing about the rest of the application:

In fact, our main worry when designing Flight components is sensibly named events.

Event names

I'm not sure we've got our event-naming nailed as yet. In fact, our naming conventions seem to be widely disagreed upon within our small team. Despite that, we seem to be managing pretty well.

We followed the basic naming conventions used on twitter.com and added a few of our own. We have five core types of event:

ui data request
A request from the UI for data. E.g.: uiNeedsTwitterProfile, uiNeedsRelationship

ui user action
An action performed by the user. E.g.: uiFollowAction, uiBlockAction

ui request
A request by the UI for the UI to do something. E.g.: uiShowColumnOptions, uiRemoveColumn, uiCloseModal

ui moment
An interesting moment which is the result of a ui request. Some requests have multiple interesting moments: the start and end of an animation, or the steps within it. "ui" is followed by the name of the component, then the action E.g.: uiShowingColumnOptions, uiColumnOptionsShown, uiColumnOptionsHidden

data
An event containing data. "data" is usually followed by the name of the component triggering the event. Generally data components only trigger a single data event. E.g.: dataTwitterProfile, dataRelationship

You can see this in action by adding a listener for these events to the document in Chrome's JavaScript console. e.g.:

Then go and look at someone's profile, or try this:

Our conventions are still in flux and as a result, we have a number of events which don't fit this model. Luckily, renaming them is an easy process.

Mentioning that, I'm reminded again of one of the great things about Flight: ease of refactoring. One piece of advice I can offer is to not worry too much about getting everything right the first time around.

We spent quite some time at the outset considering how data components would behave, how UI components would talk to them, how big or small components should be, and where we should use mixins instead of components. 

When it came down to it, we realised we needn't have bothered. It's desperately easy to alter a component to be a mixin, or the other way around. It's simple to change the way a component works internally because nothing else cares. It's dead simple to break up a data component into lots of little components because nothing is talking to it directly. 

Another reason you shouldn’t worry about it is because Flight actually seems to promote good code. It’s quite hard to write a huge, meandering component. It's much easier (and much more pleasing) to create a host of tiny little components, each of them performing their own job perfectly.

Event ownership

In the absence of a call stack, we need to make sure that a particular event is one we actually want to listen to. There could be lots of data events being fired, all with the same name but with data we're not interested in.

We've tried to manage this by attaching identifying data with each request which is then attached to the data response.

For example, we currently have two components, search and compose, which use Twitter's typeahead search. Our typeahead data module sends out events like this:

The dropdown that sends the request for suggestions will need to check that the query, datasources and dropdownId all match its request before doing anything with the suggestions provided.

Testing

We've built a test framework for Flight with Jasmine. You can see some example Jasmine tests in the library itself, but that's not the whole story. There are a few things you'll definitely need to implement if you want to make your life easier.

First, we (Twitter) extended Jasmine to provide two additional define methods, defineComponent and defineMixin, which set-up the component/mixin for you and provide access to the component and its prototype within tests. This allows you to interrogate attributes and invoke methods directly.

Second, we utilised Jasmine-jQuery, another extension for Jasmine which provides the ability to test jQuery objects and, more importantly, DOM events.

We then patched the Jasmine-jQuery extension to provide us with better events features.

Whatever test framework you use, it's essential that it is able to test which events were fired, what data was passed with them and which DOM element they were fired upon. It's also useful to check how many times the event was fired. We've seen some annoying bugs as a result of events being fired twice, or in a circular event chain.

Without this, testing Flight components is largely pointless as the events are the interface between components, i.e. the thing that needs testing most.

I'm working on a fork of Flight including our Jasmine wrappers and extensions which I’ll open up as and when it’s available.

The future of Flight in TweetDeck

We have got no doubts that we've picked the right framework for the job. However, we still have a lot of big challenges to overcome. Our core data layer is still firmly entrenched in old-style code and is going to continue to be for some time to come. Producing a plan that allows us to keep that going side-by-side with Flight without duplicating code or confusing responsibilities is not a simple task.

In the meantime, every new feature we build is built with Flight. We refactor old modules only when required, instead creating Flight wrappers around old data components to provide additional functionality.

Once we identify that a significant proportion of an old module's functionality exists in Flight wrapper components, that would be an appropriate time to move the entire functionality of the component into Flight.

We're trying to ensure that any deep-linked references to old components exist solely in our data modules. The UI should be blissfully unaware that the TD namespace ever existed.

The future of Flight

I see Flight components as providing great plug-and-play modules. jQuery's plugin library was one of the big reasons for its success and it would be awesome to see something similar happen with Flight. Although most data components will be unique to your application, UI components could easily be shared between apps. 

Flight is massively extensible - ideas such as data-binding would seem to fit it well, suggesting the possibility of a growing library of extensions. I'd love to see a big, community-led extensions and plugins library.

Why not go and get involved?

 

Posted by Tom Hamshere (@tbrd)
Front-end Engineer, TweetDeck

User Specific Search Filters

We’ve updated our column filters and search functionality in our Web and Chrome apps with a new section of “User” filters. Along with this we’ve reorganised the column edit and search builder interfaces so that the content filters are now collected together in a “Content” section and the alerting options are together in “Alert” - collectively providing the most powerful suite of filters and search operators we’ve ever shipped.

Clicking on edit button at the top of each column now shows the new filter interface with the three sections. Using the search box, top right, to perform a search also shows the new “Content” and “Users” sections.


Clicking on the “Users” section opens the panel to show two drop down menus. The first one, “By”, allows you to limit the search (or filter the column) by either all users (the default), a specific user, yourself, verified users, or by members of a list.

For example, if you wanted an auto-updating column of all images and videos posted by verified users about the Oscars then simply do a search for the “oscars”, choose to show only Tweets with any media (from the Content section) and select “By verified users” in the Users section.


Choosing to search by members of a list is also a particularly powerful method of filtering search to just the results you require. For example, if you wanted photos and videos from the Oscars from within a list of your favorite film industry journalists, you would search for “oscars”, select “Tweets with any media” in the Content section, choose “By members of list...” in the Users section then enter the name of the list in the text below, in this case Storyful/oscars.


Also in this release is the ability to embed a search or list column from your TweetDeck onto your website. Simply click on the column edit button in the top right and select the share button, which opens a prefilled configure widgets page on twitter.com.


Posted by Ramón Argüello (@monchote), James Whittaker (@jmwhittaker) and Cennydd Bowles (@cennydd)
Front-end Engineering & Design, TweetDeck

An update on TweetDeck

Update - April 19, 12:55pm PDT
TweetDeck AIR, TweetDeck for Android and TweetDeck for iPhone will be removed from their respective app stores and will stop functioning on May 7. Our Facebook integration will also stop on May 7.

---

TweetDeck is the most powerful Twitter tool for tracking real-time conversations. Its flexibility and customizable layout let you keep up with what’s happening on Twitter, across multiple topics and accounts, in real time. To continue to offer a great product that addresses your unique needs, we’re going to focus our development efforts on our modern, web-based versions of TweetDeck. To that end, we are discontinuing support for our older apps: TweetDeck AIR, TweetDeck for Android and TweetDeck for iPhone. They will be removed from their respective app stores in early May and will stop functioning shortly thereafter [see update]. We’ll also discontinue support for our Facebook integration.

Over the past 18 months, we’ve been focused on building a fast and feature-rich web application for modern browsers, and a Chrome app, which offers some unique features like notifications. We’ve recently introduced many enhancements to these apps –– a new look and feel, tools like search term autocomplete and search filters to help you find what you’re looking for more quickly, and automatically-updating Tweet streams so you immediately see the most recent Tweets. Our weekly web releases have been possible because we’ve nearly doubled the size of the TweetDeck team over the past six months (and we’re still hiring).

In many ways, doubling down on the TweetDeck web experience and discontinuing our app support is a reflection of where our TweetDeck power-users are going. Over the past few years, we’ve seen a steady trend towards people using TweetDeck on their computers and Twitter on their mobile devices. This trend coincides with an increased investment in Twitter for iPhone and Twitter for Android –– adding photo filters and other editing capabilities, revamping user profiles and enhancing search. That said, we know this applies to most of our users –– not all of them. And for those of you who are inconvenienced by this shift, our sincere apologies.

Additionally, TweetDeck AIR, TweetDeck for Android and TweetDeck for iPhone rely on v1.0 of Twitter’s API, which we are retiring starting this month. Leading up to that retirement, Twitter’s platform team will be performing occasional tests that will affect applications that rely on API v1.0. Over the next two months users of TweetDeck AIR, TweetDeck for Android and TweetDeck for iPhone may experience some outages with those apps before they are removed from their respective app stores in early May.

We think these web and Chrome apps provide the best TweetDeck experience yet, and that they are the apps in which you’ll want to see us add new capabilities first, followed closely by our Mac and PC apps.

From the whole TweetDeck team, we’re excited about what the future holds. We hope you are too.

Wider Columns, bigger and smaller fonts, and faster keyboard scrolling

We just released a handful of new features for the web and Chrome versions of TweetDeck:

Wide column setting - You can now select wide columns, in addition to the previous options: narrow and medium.

New font sizes - We’ve added two more font sizes, so you can now choose among five different options: smallest, small, medium, large or largest. These new font sizes, in conjunction with the new column width options, provide more flexibility.

Spacebar scrolls down a page of Tweets - If you use arrow keys to navigate around your columns (and even if you don’t!), you may be happy to know that you can now press the spacebar to scroll down one page of Tweets in the currently selected column. This makes scrolling back in time even easier. You can also use the Page Up and Page Down buttons (if you have them) to scroll up and down.

Actions when clicking on notifications - Now the pop-up notifications are more interactive so that you can quickly jump to performing actions on the notified Tweet.

We also enabled infinite scroll in the temporary pop-up columns and made a number of bug fixes, such as making the sign-in and image-upload error messages more informative, ensuring that lists you delete no longer appear in TweetDeck, and fixing an issue with scheduled updates.

Simply refresh or restart your browser to get these new features.

 

Column Filters: Find the content you’re looking for

Today we’re releasing a powerful set of column filters for the TweetDeck web and Chrome apps. These allow you to show or exclude specific words and phrases from a TweetDeck column –– especially useful when you want to focus on a particular element of a column. You can also choose to view only Tweets that contain media (images and/or video). This turns any of your existing columns into a media column, making it very easy to scan content and find what you’re looking for.

To access the filters, click on the edit button at the top right of any column. From here, the edit panel slides down and the filters are shown as below.

Screen_shot_2013-02-14_at_17

Here’s a bit more information on each of the four new filters:

Showing - click on the drop down menu to choose to show: all Tweets (default), Tweets with images, Tweets with videos, Tweets with any media (images + videos) or Tweets with links

matching - only show Tweets that contain the word(s) entered in the text field

excluding - only show Tweets that do not contain the words entered in the text field

retweets - choose whether to include or exclude retweets from the column

For example, choosing to only show Tweets that contain media makes scanning for a particular image or video much faster and easier. 

Screen_shot_2013-02-14_at_18

This new filtering functionality is available now for the TweetDeck web and Chrome apps. To update, simply refresh/restart your browser.

Today’s release, as well as our recent release of content filters for search columns, is part of our ongoing efforts to bring the features and capabilities of our AIR app to TweetDeck web (web.tweetdeck.com). We’ve pushed regular updates each of the last 24 weeks, squashing bugs and introducing oft-requested functionality, such as real-time updating of Tweets in columns, keyboard shortcuts & navigation, search improvements including typeahead and people search, a new interface and the options to change font size and column width, a more extensive quick actions menu on each Tweet, performance upgrades, full profile header images and more. 

Keep checking our blog and follow @TweetDeck to stay up-to-date on what’s new in TweetDeck. 

 

 

 

 

Content Filters and Social Proof

The latest release for the TweetDeck Chrome app introduces content filters, which will improve new and existing search columns. These column-specific filters are are synced, so they will be applied to your TweetDeck wherever you open them. 

Now when you type something in the search box, the Tweets results window contains three new filters each designed to individually or collectively focus your search results. 

In this example, we’ve searched for information on the recent Formula 1 pre-season testing which took place in Jerez, Spain. By searching for Tweets which contain both the words [F1] and [Jerez] we get a decent result set  — but using the filters delivers something more informative. 

Screen_shot_2013-02-05_at_20

To return a set of Tweets which give a greater picture of the events of the day, we can use the “Containing” filter to only return Tweets that contain media (images and video). Simply click on the first drop-down box and choose the appropriate element. 

Screen_shot_2013-02-05_at_20

The global nature of [F1] is obvious in that a lot of the search results are in different languages. If we only want Tweets we can read then we can further distill the search using the second filter to return only Tweets in our favoured language, in this case English.  

Screen_shot_2013-02-05_at_20

So from our wide search on [F1] and [Jerez] we’ve been able to filter it down to a media-rich result set of Tweets which contains photos or videos direct from the track, in the language of our choosing. We were also able to exclude retweets to reduce duplicates. From here we can add this search+filters as a TweetDeck column which automatically updates when new matching Tweets occur.

Screen_shot_2013-02-05_at_20

And this feature is not restricted to new searches. You can apply these filters to any of your existing search columns by clicking on the column edit button. A small “FILTERS ACTIVE” message appears at the top of any search column where filters have been applied. Simply click on this to quickly open the column edit menu.

The other important update this week is the addition of what we call "social proof" to user profiles. Social proof indicates some of the people you follow who also follow that account. This in turn gives you a sense of whether you’d find this account interesting, and should also follow.  

Screen_shot_2013-02-05_at_19

Where applicable, the social proof banner appears just above the action buttons on the bottom of the profile pop-up window.

If you're using our TweetDeck Chrome app please restart your browser to get this update. The web and desktop apps will be updated shortly.

Action and Navigation all from the Keyboard

This week's Web and Chrome update is for lovers of keyboard shortcuts everywhere. We wanted to offer shortcuts for all the different actions you can do on a Tweet — but to do that we first needed to provide a method of selecting the Tweet in question. And we wanted more: to provide a way to navigate across and up and down your columns using only the keyboard. 

Now you can do both simply by using the arrow keys. Left and right arrow keys navigate across your columns (and you can still use 1-9 to jump to a specific column); up and down arrow keys move up and down the column currently selected. The selected Tweet is highlighted with a different background colour as illustrated below:

Screen_shot_2013-01-31_at_08

Since you're now able to select an individual Tweet (by highlighting it using the arrow keys) we have a new set of shortcuts which enable you to perform Tweet-specific actions such as replying, retweeting, favoriting, DMing, as well as giving you a detail view and even a quick view of the Tweet owner’s profile.

The full list of keyboards shortcuts is available by pressing the "?" key.

Xxscreen_shot_2013-01-31_at_08

The combination of these shortcuts makes TweetDeck usage even more efficient. For example, to quickly reply to  a Tweet, use the arrow keys to navigate to it and then press "R", type your response and hit Cmd+Return (Mac) or Ctrl+Enter (PC) to send — all without taking your fingers off the keyboard.

Also, as you're navigating around, press "A" to jump straight into the Add Column menu or "S" for the search box; start typing to enter a search term. Finally, if you want to close a pop-up window, just press the Escape key and you're back to your TweetDeck columns.

Simply refresh the Web app (web.tweetdeck.com) to get this latest update or restart your browser if you're using the TweetDeck Chrome app.

A More Accommodating TweetDeck and Keyboard Column Jumping

An important function for TweetDeck is to display large numbers of Tweets in a big window, usually your entire display. However, we recognize some users also enjoy using TweetDeck as a background application on a single desktop as well.
 
That’s why we’re updating TweetDeck to support a 2-column mode that gives you all of the functionality you need in a smaller space. Now you can drag the window width down to two columns, and the application interface will adapt as needed. We hope this change makes it easier for you to use TweetDeck alongside other apps in your workflow, and we’ll continue to explore ways to make this even more efficient. 

Today’s update also includes new keyboard shortcuts. Now you can jump from one column to the next by pressing the corresponding column number. For example, press "8" to move the display to show column 8. This works for the first 9 columns, which are generally the most used columns. Also pressing "0" will move the display to show the far right column, a handy shortcut for those with a large number of columns.

Grab the new update by refreshing your browser if you’re using the web app or restarting your Chrome browser if you’re using the Chrome app.

Typeahead and People Search

The latest version of TweetDeck Chrome (released today) contains some significant improvements to the search box area of the app. It’s now extremely easy to find someone you’re looking for, and you’ll see suggestions of similar search terms, making topic searches more effective.

Here’s a runthrough of how it works. Click in the search box and a new dropdown box instantly appears containing your previous searches. Click on a previous search to re-run it. (You can clear the search history by clicking on the “Clear history” link at the bottom.)  

As you type each character into the search box, two things happen in real time:

1. A related search is run. This effectively tries to autocomplete your search term, potentially saving you from having to type the whole word or phrase. Search results will be displayed in the top half of the search dropdown.
2. A user search is run, and this displays user accounts whose names contain the search term in the bottom of the box.

Screen_shot_2012-12-18_at_15

If one of the suggested search terms matches what you were searching for, then clicking on that term updates the search dropdown with Tweets that match that chosen search term. From here you can interact with the Tweets in the expected way or add the search results as a live updating column to your TweetDeck.

Screen_shot_2012-12-18_at_16

You can also click on the Users button at the top and swap to a list of those user accounts which match the search term i.e. the user account name or profile contains the search term.

Screen_shot_2012-12-18_at_16

With the list of matching accounts, you can either click on the account name to close the search dropdown and show the pop-up profile panel or click on the user account dropdown button where the usual account actions can be performed such as following, add to list, send DM etc.

Today we launch the Typeahead and People Search update for the Chrome TweetDeck app and will gradually roll it out to the Web, PC and Mac versions over the coming weeks. Please restart your Chrome browser to get the updated version.

 


Posted by Tom Hamshere (@tbrd), Sol Plant (@lostplan)
Front-End Engineers, TweetDeck

Embed This Tweet...from TweetDeck

With the latest version of TweetDeck Web and Chrome released today you can now embed a Tweet directly from your TweetDeck into your website or blog. Here’s how it works:

Click on the … icon (More actions) on the Tweet you want to embed. A dropdown menu appears with all the available actions you can do on that tweet, there is a new option in here to “Embed this Tweet”.

Screen_shot_2012-12-11_at_15
Click on this option and the “Embed this Tweet” window will appear. Here you have the code which is used to embed the Tweet and a preview of what the embedded Tweet will look like.
Screen_shot_2012-12-11_at_15
Click on the code in the top box and it will highlight. Copy that code snippet and paste it into the code of your website or blog. And it will look like this:

As we’ve recently discussed, we spend a lot of time improving TweetDeck for a large consumption of Tweets, as this is one of the core uses of the product. We're also thinking about how we can help you bring more signal to all the Tweets you consume with curation features like embedding Tweets.


Posted by Ramón Argüello (@monchote)
Front-End Engineer, TweetDeck