XING Devblog

Make the web a safer place

Banner for old browser campaign
This is the banner users of Internet Explorer 6-8 will see.

In 2012 we had a very close look at our numbers. How many users were visiting our platform via the IE6 browser? Time and time again I went to the responsible Product guy until we finally hit the magic mark of 1%. 1% of our users performed an upsell via the IE6 browser. That was the point when we stopped supporting IE6. No more hacks were built for this old browser, meaning that developers and testers could spend their time on better software instead of looking for workarounds for the browser’s flaws.

In 2013 we also stopped supporting IE7.

No support for IE8 on XING

Honestly? Every front-end guy here at XING has been keen to ditch IE8 for quite some time now. If you asking a front-end guy, he’ll tell you to get rid of IE8 as soon as possible. Using jQuery you can’t update to the newest version because the jQuery guys dropped their support for IE8 as of version 2.

→ Read more…


Posted by Piet Brauer

Filed under iOS

The Art of Continuous Delivery

This is an Article of the series Building the XING iOS Universal App:

  1. How to Redesign a 150,000+ LOC Code Base by @vimacs
  2. Auto Layout in Cells – Don’t! by @stefanmunz
  3. Auto Layout Cells without Auto Layout – Do! by @gskbyte
  4. The Art of Continuous Delivery by @pietbrauer

 

Requirements

When planning the real implementation of the universal app, we and other teams had one simple requirement: the app should remain releasable throughout the project so important features can be launched.

Despite this being a simple requirement, it was by no means simple to accomplish and not all that common. Sure, everyone builds features and releases new versions. But reworking the basic structure of how we do things while still releasing every 2 weeks is a completely different story.

Before I dig into what we released and how we accomplished it, I’d like to explain our current release process:

  • Features are developed by the domain team (e.g. feed or communities); they don’t just develop the iOS part, but also the Web front end and back end.
  • Every second Friday we have a code freeze where every library and domain app is tagged and released via CocoaPods
  • Our QA starts with release testing on Mondays and Tuesdays
  • After QA finishes verifying the app, it enters into our internal pre-release phase, meaning that every XING employee receives our ready-to-ship version on his or her personal device to test for a period of 2 weeks
  • If no major bugs occur, the app is shipped to the App Store

What we released

As I said earlier, we had a couple of features to launch in time throughout the universal project. As the project took about 6 months, there was quite a long list of features that needed to be implemented. But it wasn’t just features that were implemented; we also had an initial plan to ship every universalised part of the app on its own to get some early feedback. Although we had 12 release trains throughout the course of the project, I will talk a bit more about my favourite 6.

What is a Release Train?

If you’re unfamiliar with the term I’ll give you a brief introduction of our interpretation of this term. A release train is as simple as a regular train: it departs at certain intervals and people hop on board to take it.
With this image in mind it’s easy to get into our style of working. We define the dates on which the train departs over the following 3 months (every 2 weeks) and communicate it to the domain teams. They decide when they want to board which train with which feature set.
As the train departs regularly it doesn’t come with much pressure as teams can just take the next train if they don’t make it on time.
With each release train we freeze our code and build a beta which is taken into final testing. If this is successful, we build an App Store version and submit it.

Release Train 1 (v4.16.0 or 26.01.2015)

In the first release train we shipped the universalised Jobs section of our app. It was still using Auto Layout which, at that time, was the latest and greatest we had just introduced to our app.
Additionally, the Jobs detail view is one of the more difficult sections of our app. Job postings can have plain text, HTML or PDF descriptions so there are a lot of different components playing into that release.

Release Train 2 (v4.17.0 or 25.02.2015)

The second release train within the project was about reworking the Jobs section to manually frame layout and components. It also contained all of the universal changes made to the Groups section and our new Feed. Getting these out as early as possible was crucial as we caught some initial crashes.
We also gained some insights into the performance of our new-born stacked components. Despite the Jobs section not being the initial view when you open the app, it has a fair amount of traffic. We had a few crashes in this section that were introduced with the new universal components which we were able to fix.

Release Train 3 (v4.18.0 or 10.03.2015)

This was one of the most important releases for our app. We released our new “Content Publisher Pages”. As this is one of the most important topics for XING right now, it was very important for the domain team not to wait an additional 3 months until this feature went live.

It also proved to be one of the most difficult releases. As the Content team already used a lot of the new components, we just invented and made a lot of changes to our UI library from the last release. But these changes weren’t ready to be released yet (which we didn’t know beforehand), meaning that we were faced with 2 problems:

  1. The domain team was using the master branch of our UI library
  2. Other parts of the app still used the most recently released version of our UI library

Between these versions we made a huge number of changes and basically had two ways of resolving the feature difference between the two versions:

  1. Update all of the other parts of the app to the new version of our UI library or
  2. Copy all of the new classes and components to the content repository

We quickly decided to play Victor Frankenstein and create a monster. So we copied all the new classes, changed the class prefix and constant prefixes from `XNG` to `XNGContent` and kept doing that until the module would compile again. We had to change all the prefixes because otherwise the app would no longer compile and we would have been faced with duplicate symbols.
Our Frankenstein project turned out to be a huge success and we made it onto the release train with a minor delay of just a few hours. The following Monday we began reverting the changes to get rid of our monster and start sharing components again.

Release Train 4 (v4.19.1 or 13.04.2015)

After the last big feature went out into the wild, an even more important bug appeared: one of our core libraries used for our networking calls had a security bug.

We spoke to our security team and immediate action was necessary. Having all the released versions from the last release made us able to ship a hot fix without slowing down the domain teams.

While we were updating AFNetworking to an already patched version, all of the other developers were able to focus on finalising the universal project, which was only 2 weeks away. Having released versions of our libraries not only gave developers the advantage of being able to continue developing, it also instilled us and our QA team with confidence that no crucial changes or bugs had made it into this release.

Release Train 5 (v5.0.0 or 27.04.2015)

This is the final release of our universal app. As our major sections Feed, Content, Groups and Jobs were already out there, we had a lot of confidence in this major release.

I can only imagine a situation of such a big release without having versions already shipped as being one of the most stressful things that can happen to software developers.

To be honest this was one of the quietest releases the Framework group ever saw. At the time of writing this article there is already a new version in pre-release and one currently code frozen. Shipping regularly really helped us a lot.

How we worked

I already walked you through our release schedule and releases. But now I’d like to guide you through the implementation process. We started out on our Prototyping Days with a simple git branch named `universal`. This branch lived there until we finally deleted it in March this year. As we thought about how to approach the universal app from a version control level, we basically had 2 options:

  • Release a library to our internal CocoaPods repository every time we made a change or
  • Have long-living branches lying around until there was a code freeze and release a new version then

We opted for the second option and it turned out to be the best option we could have taken. So here is how we did it during the development time:
After a code freeze you would create a new branch called universal in the according repository and push it to our internal GitHub instance. While developing you commit to your feature branch. After you finish that, you perform a pull request onto the universal branch.

This way we accumulated all of the changes during the 2-week time span and released a new version on the day of the code freeze.
This approach has several upsides:

  • The master branch is always releasable if a hot fix has to be implemented
  • People can make mistakes that don’t affect other developers on their feature branches

However, one of the main downsides is that you have to reference several pods in your `Podfile` to branches. This looks ugly and also does not perform very well on installing as it downloads the whole history for a pod every time.
When faced with the biweekly code freeze we would go through our main `Podfile` and write down all the pods containing changes since the most recently released version. Each pod has a `CHANGELOG` and we would consult it to decide which version number to pick. We highly encourage semantic versioning in our library pods. For feature pods such as Jobs we use the usual versioning system.

Lessons learned (or tl;dr)

After all of these explanations it’s time to provide some lessons learned.

Interim releases really helped us catch a lot of bugs and crashes early on. This made us very confident when submitting the final version to our beloved App Store.

Thanks to our versioning system we were able to apply hot fixes in between releases, which helped in responding to urgent cases, e.g. the AFNetworking bug.

In the initial phase of our scaling process we decided to opt for a biweekly release train. Although the release train concept may sound like waterfall project management with fixed deadlines for developers, it turned out to be highly successful within our Agile environment.
Having a biweekly release train with stakeholder communication forced us to freeze our modules and code. If we hadn’t had the release train I’m fairly sure we would have procrastinated and just made one big release out of it.

But we also faced some downsides. Long-living branches are harder to merge, especially when they contain big changes and since merging back from master is tedious. We also aimed too high as our initial goal was to release after each section is done. We managed to do this about half of the time, but ended up missing important sections like conversations and contacts. This was mainly because we also made some visual changes in between, e.g. the new main menu, which weren’t due for release at that time because they were planned for the big 5.0 release.

Despite that, I’m very happy with the outcome and proud of the team as we stuck to the schedule. This makes us confident that we’ll be able to continue making big changes to the app in the future, too.


Posted by Jose Alcalá-Correa

Filed under iOS

Auto Layout Cells without Auto Layout – Do!

This is an Article of the series Building the XING iOS Universal App:

  1. How to Redesign a 150,000+ LOC Code Base by @vimacs
  2. Auto Layout in Cells – Don’t! by @stefanmunz
  3. Auto Layout Cells without Auto Layout – Do! by @gskbyte
  4. The Art of Continuous Delivery by @pietbrauer

Introduction / UX Principles

When designing the principles of our Universal App, we worked with our UX/VD teams to propose a common pattern for use in the whole application called Components. A component is a view made up of one or more simpler views like labels, images or buttons which are always displayed using the same distribution. We use a vertical stack of full-width component views to build all of the cells in our app, taking advantage of being able to reuse existing components from our library.

component

A typical component view showcasing content view, paddings and an accessory view

As soon as we knew how the component views would be used and displayed, it immediately became obvious that we needed – also for convenience – a cell that would lay out components automatically. This is how we discovered a new pattern and began developing our XNGStackedCell.

stacked_cell

A stacked cell with three components

XNGComponentView is a UIView subclass that serves as a base class for all other components. It contains a contentView just like UICollectionViewCells where all subviews should be contained. There is also support for accessory views like badges and a disclosure indicator. XNGStackedCell is our subclass of UICollectionViewCell that lays out components vertically and takes care of their displayed content.

As Stefan wrote in our previous article, after initially attempting to implement our cells using Auto Layout, we decided to switch back to a frame-based layout. The main reasons behind this were the easier feasibility of independently showing and hiding views and improved performance.

We will explain our component architecture and implementation details in the following sections, with the last point providing a simple example.

Layout and Size Calculation

Our first requirement was that components should be able to calculate their height automatically once they know their width and their subviews are configured. Instead of retrieving a XNGComponentView‘s height via an extra method, we ask for it using the -sizeThatFits: method. XNGComponentViews must always set the height of their contentView at the very end of -layoutSubviews so that the height of the component itself can be computed. The implementation of the base class automatically takes paddings into account.

Having components always stacked vertically makes the -layoutSubviews method of the XNGStackedCell relatively simple, thus removing the need for it to be overridden by subclasses.

In all our cases, one cell represents one single entity of information. This makes the configuration interface for every cell exactly the same, and XNGStackedCell subclasses only have to override the -setModel: method. Subclasses only have to configure the subviews inside their components within this method: setting text to labels, images to image views, making them hidden or visible, etc.

Another requirement we had was that cells could have a different number of components which could also have different sizes. In order to calculate the sizes for cells, we decided to use the prototype cells approach: for every cell class we have a cell that is outside of the UICollectionView that we configure and lay out just to measure the cell size of every cell in our view controller. While this approach involves rendering every cell twice (for size measuring and actual rendering), we chose this way of measuring cells for the following reasons:

– We don’t need any special code just to make size measurements because both layout and size calculation are done inside -layoutSubviews, which allows us to write code just once.
– Size calculation code can be written just once in the base XNGStackedComponentCell and doesn’t need to be reimplemented in every subclass.
– It’s easy to optimise should the size calculation become expensive.
– We don’t need to adapt our code to make it work flawlessly with the new estimatedSize property on UICollectionViewFlowLayout in iOS 8.

To request the size of a cell for a given model object, we just need to call the static method +sizeForModel:constrainingWidth: on the class of the cell we want to use. As implementation is the same for all subclasses of XNGStackedCell, child classes do not need to override this method.

However, they can still do so in order to optimise the size calculation process in cases where we always have the same height for every cell belonging to a class. We have used this trick in different sections like Contacts and Visitors to my profile where every cell has the same, constant size. Apart from this, prototype cells have their isPrototypeCell property set to YES, which can be used inside -setModel: to avoid configuring expensive views that will always have the same size (like setting image URLs in UIImageViews).

Cell and Component Highlighting

Since our stacked cells could display many components, the possibility of highlighting and selecting individual components immediately became interesting. This behaviour has to fulfil three basic requirements:

– It must not interfere with the UICollectionView‘s scrolling
– It must be compatible with standard cell highlighting and selection
– By default, independent highlighting must be disabled and explicitly enabled

This behaviour can be observed in our News Feed: users can tap on any of the bodies of the cell to display them in a detail controller, but tapping on the header highlights the whole cell and shows an expanded version of the story itself, including comments.

For a component to be independently tappable, it first needs to be highlightable in order to give feedback to the user. To this end, it exposes the highlighted property, which alters the way the component is drawn onto the screen. The default implementation makes the background grey instead of white, but this can be overridden by subclasses. XNGStackedCell also overrides -setHighlighted: and sets this property on all of its components.

If a component must be independently tappable, we need to intercept the touch on the cell and highlight only the component that has been tapped, avoiding transmitting the touch to the cell. To enable this behaviour, the cell that contains an independently tappable component must be set as tappable and become its tapDelegate.

Once the tappable flag is active, we override the implementation of the touches that the component view receives and don’t deliver them to the superview. Any movement deactivates the touch detection and control returns to the collection view.

A Practical Example

The following code represents a simple stacked cell with two component views: on the top we have an XNGHeaderDefaultComponent view that contains an image view to the left and two labels positioned vertically to its right, and a simple XNGTextComponent view whose implementation will be detailed below. The text component will be tappable if the text to be displayed is too long, thus allowing the user to see the whole text in a different view.

The implementation of our simple component would be as follows. In the header file we only expose the property that we want to be able to change, in this case the text drawn on the label:

@interface XNGTextComponent : XNGComponentView

@property (nonatomic, copy) NSString *text;

@end

In the implementation file we just need to initialise an UILabel and add it to the contentView, implement the text getter and setter, and the layout method.

@implementation

// initialize private label on -initWithFrame:
// -text and -setText: operate directly on the label's text property

- (void)layoutSubviews {
    [super layoutSubviews];

    CGFloat labelWidth = self.contentView.width;
    CGFloat height = 0;
    if (self.text.length > 0) {
        self.label.width = labelWidth;
        CGSize sizeToBeFit = CGSizeMake(labelWidth, CGFLOAT_MAX);
        self.label.height = [self.label sizeThatFits:sizeToBeFit].height;
        height = self.label.bottom;
    }

    self.contentView.height = height;
}

@end

In our example cell, we just need to initialise the components we want to display by overriding -initializeComponents and -setModel: to configure them.

// headerComponent and textComponent are private properties

- (NSArray *)initializeComponents {
    _headerComponent = [[XNGHeaderDefaultComponent alloc] initWithFrame:CGRectZero];

    _textComponent = [[XNGTextComponent alloc] initWithFrame:CGRectZero];
    _textComponent.tapDelegate = self;

    return @[_headerComponent, _textComponent];
}

- (void)setModel:(id)model {
    [super setModel:model];

    XNGData *data = (XNGData *)model;

    self.headerComponent.title = data.title;
    self.headerComponent.subtitle = data.subtitle;
    if (!self.isPrototypeCell) {
        self.headerComponent.imageURL = data.imageURL;
    }

    NSString *content = data.contentText;
    if(content.length > 0) {
        self.textComponent.hidden = NO;

        if (content.length > kMaxContentLength) {
            content = [content substringToIndex:kMaxContentLength];
            content.tappable = YES;
        } else {
            content.tappable = NO;
        }
        self.textComponent.text = content;
    } else {
        self.textComponent.hidden = YES;
    }
}

- (void)didTapComponentView:(XNGComponentView *)componentView {
    if (componentView == _textComponent) {
        // invoke cell's delegate method to show full post
    }
}

Conclusion

Having a simple but solid design pattern like the stackable components helped us a lot in designing our own UI library that is easy to use, stable and flexible enough to allow us to build a complex app like the XING app. Our approach has brought us several benefits:

– A consistent look and feel throughout the whole app
– Easy extensibility, component reuse and performance tuning
– Layout and cell sizing in a single method to avoid separate height calculation, which frequently causes display glitches
– A simple and predictable interface for configuring and sizing every cell class
– One cell representing one single model object and one single method configuring a cell, which simplifies the data source code

We believe that our way of displaying and laying out cells brings a lot of stability to our code and makes our infrastructure easier to understand and easier to maintain. Even new programmers can adapt to it very quickly, because the interface of cells and components is small enough to understand with little effort, yet flexible enough to be used in every section of the app.


Posted by Stefan Munz

Filed under iOS

Auto Layout in Cells – Don’t!

This is an Article of the series Building the XING iOS Universal App:

  1. How to Redesign a 150,000+ LOC Code Base by @vimacs
  2. Auto Layout in Cells – Don’t! by @stefanmunz
  3. Auto Layout Cells without Auto Layout – Do! by @gskbyte
  4. The Art of Continuous Delivery by @pietbrauer

 

Tasked with applying a whole new design to the entire app for all iPhone and iPad devices, we naturally also took the opportunity to reconsider the best technological solutions to use, taking into consideration various constraints. Firstly, many sections of the app were originally built at a time where you could safely assume a cell width of 320 pixels, which is no longer the case. We also have a lot of variable content in our app; many elements like the number of comments on a post, for example, vary per user or over time. Not only can the number of elements (or UICollectionViewCells) in one view be dynamic, but most cells have a dynamic height as well, e.g. depending on the length of the comment a user writes. Furthermore, many cells have optional elements, e.g. a link preview that only appears if the text the user entered contains a link. We decided to go for a multi-column design for many screens on the iPad, so transforming everything to UICollectionViews was a given right from the start.

At XING we try to build our apps in a simple way based on standard technologies whenever possible; we already have a lot of business logic that can be hard enough to understand on its own. Custom technologies and solutions must therefore have a very good reason to be built and/or maintained by us. In the beginning, Auto Layout felt like the logical choice for our UICollectionViewCell subclass layouts as it is developed by Apple and promoted as the future of view layouting.

Due to the variable height of our cells and their many optional views, we found it cleaner and easier to write our views purely in code. Together with snapshot tests, our pull requests were still highly visual and easy to understand. Unfortunately, Apple’s two APIs for writing Auto Layout constraints in code each have their downsides. Either you define every constraint individually via a verbose method call, ending up with a long list of constraints that are difficult to construct a mental overview of, or you use the Visual Format Language, which, although more concise and expressive, makes it hard to refactor hardcoded view names at a later date as they appear scattered across many strings. Happily, Masonry provided us with a nice DSL that allowed us to express the exact same Auto Layout constraints in far fewer lines of code.

image_masonry

Same constraints in standard code and Masonry

The Plan

One team set to work on the project, transforming view controllers and cells to the new design using Auto Layout. They started on the Jobs section, which contains relatively simple cells. We made good progress here and were happy with the result: clean code, stable views and reasonable performance. Another team started a bit later, transforming the News Feed, i.e. the starting section of the app. They had a harder time of things as the cells in the News Feed have a lot of optional views. They each consist of a header, a footer for social interactions like commenting and liking, and a variable amount (1-15) of body elements in between.

image_feed_cells

Different Feed Cells – Same UICollectionViewCell Subclass

 

The resulting code for the News Feed was clean and well structured; the one thing we couldn’t get right was performance. No matter how we tweaked the code, the scrolling performance was way below what we were aiming for. With plans already in the pipeline for more complex feed stories, we knew we had to fix this throughout the project.

We got both implementations stable and joined forces to tackle one of our bigger sections: Groups. Both teams had developed their respective code styles, which we hoped to merge and align. Our Groups section also has fairly complex cell styles, with optional elements like attached images or link previews.

Having optional views that can be hidden inside a reusable cell is difficult to express with Auto Layout. Auto Layout basically builds up an equation system between views. Adding or removing a view like a link preview or image that sits vertically between other views means adding or removing Auto Layout constraints. This turns out to be one of Auto Layout’s more expensive operations. Doing that in one of the most time-critical methods we have in our app (`cellForItemAtIndexPath:`) proved hard to optimise. iOS 8 introduced optional constraints, but they force you to add yet more constraints, and in any case we still had to support iOS 7 for the foreseeable future.

We made another observation: cells seemed to behave differently depending on how many subviews they had. We observed many display glitches when a cell was displaying all of the possible subviews. This makes sense because of the way Auto Layout works: all views in a cell are in the same equation system since there is no way to create “Auto Layout containers” that encapsulate views and their equation system and appear as one view from the outside. So the one-big-equation system becomes harder and harder to get right in all cases the bigger it gets. This was a discouraging sign for us, especially since we wanted to be able to create more complex cells in the future.

Instead of unifying everything into a clean and consistent view code in our Groups section, we steered towards a third style that added a lot of extra constraints for edge cases. However, when fixing layout bugs, we often found we broke other layout edge cases; trial and error seemed to be the only way to progress. It became abundantly clear that this was not how we wanted to write our layout code.

The Intervention

We called all iOS developers together for an intervention to discuss possible alternatives. It was clear that Auto Layout would not work for us, but doing frame-based layouting, as we had done previously, was clearly not an option either. The result of that discussion and the ensuing months of work are our XNGComponents, quickly followed by XNGStackedCell, which are described by Jose in the next article in this series.

Summary

Do we ignore Auto Layout? Do we plan to remove it completely from our apps? Not at all. Auto Layout is a nice system, and together with Masonry is highly suited to full-screen views that are not too complex; in fact it is used in most of our full-screen views, of which there are admittedly few. Our app is instead heavily based on UICollectionViews with dynamic cells that are reused a lot, and for this Auto Layout is just not the right technology.


Posted by Vidu Pirathaparajah

Filed under iOS

How to Redesign a 150,000+ LOC Code Base

This is an Article of the series Building the XING iOS Universal App:

  1. How to Redesign a 150,000+ LOC Code Base by @vimacs
  2. Auto Layout in Cells – Don’t! by @stefanmunz
  3. Auto Layout Cells without Auto Layout – Do! by @gskbyte
  4. The Art of Continuous Delivery by @pietbrauer

 

The Beginning

It all started shortly before one of our famous Prototyping Days. At that time we had a hybrid iPad app in addition to the native iPhone app to evaluate the hybrid technology. We had the idea of building a Universal iOS app for quite some time, but it seemed such a big project, which may even need a rewrite, that we hadn’t tackled it yet. We decided to use the Prototyping Days to try and prove that we could build a Universal app in a reasonable amount of time. Three of us got together the weekend before the Prototyping Days, changed the project settings in Xcode to Universal, and let it run. We changed our Table Views to Collection Views with one custom layout. After that weekend we had a few parts of our app that worked, and a lot of things that looked bad or didn’t work at all. The following week, during the actual Prototyping Days, we spent our time designing a tailored presentation to show off the parts that were working well as one of the projects. We gave an awesome presentation and the delivery went without any major glitches. Unfortunately we didn’t win one of the prices; there were too many colleagues with bigger ideas and better execution. But the idea that this project was feasible stuck with everyone, and that’s what counted.

Scope

Of course a project of this size and complexity doesn’t just get signed off; a quite important question first needed to be answered: How long will it take? To be able to answer that question we first had to agree on a scope. This is a tough enough decision for regular projects, but for this one it was extra tough since it is one of the rare occasions where we would work across the entire app. Us engineers saw it as a great chance to refactor the code base. User Experience (UX) saw it as a chance to change the entire UX design. Our Product Manager would have loved to have different feature sets for iPad and iPhone. If we had done it all, it would have taken us more than a year. Changes of this size across all levels are very hard to apply iteratively, which is why we love small projects and working in iterations at XING. Releasing a Universal app section-by-section was not an option either, so we had to set up some constraints to achieve a reasonable scope:

  1. Minimise differences in feature set between iPhone and iPad
  2. No technical refactoring except the ones needed to support iPad
  3. No changes in the information hierarchy
  4. Use the same layout for Portrait and Landscape (iPad only)

We decided to take the existing features and information hierarchy of the iPhone app and make it presentable on iPad with as few changes as possible. There was one exception to that rule: defining patterns and reusing them throughout the app.

Patterns

The XING iOS app grew quite big over the years. In the past we developed feature by feature and section by section; once we were done with one feature/section, we would move on to the next one and not touch it again for a long time. The lessons we learnt from one feature or section were mostly only applied to subsequent ones, and seldom to existing ones, so we ended up with different implementations for similar things in our codebase. This was not just a code-level issue, but also a visual one: similar UI elements ended up looking slightly different throughout the app.

To solve this problem, we created UI patterns in preparation for this project. Patterns are building blocks defined by our designers that can be combined with other patterns to create a view. To make them easily applicable, we decided to translate the patterns 1:1 in code and create an analogous building block system there as well.

pattern_screen

Image of a Screen composed of components

Estimating

After that step we knew what we wanted to do; next was to find out where we had to apply our amazing plan. We created a status page where we listed every View Controller we have in our app. We created an issue for each one and added checkboxes for UX, Visual Design (VD) & Tech preparation. UX could be checked off once the patterns to be used in that view were added to the issue; VD once a visual of the Screen was added; and Tech once all technical tasks to “universalise” that View Controller were added to the issue. Once all the checkboxes were ticked, the ticket was ready for estimation. Since it was too much effort to prepare all 77 issues in advance, we decided to do a reference implementation and extrapolate estimates from there.

status_page

Screenshot of the project status page

Reference Implementation

For the reference implication, we had following requirements: 1. It should be an entire section. 2. It should be as small as possible since the project wasn’t officially approved yet.

We chose the Jobs section. It was the smallest section with 3 screens: Job Recommendations, Job Search and a Detail View for the job description. We prepared the tickets, estimated them and built the section in one sprint.

After the reference implementation we adjusted our original estimates to match reality and extrapolated our estimates for all other tickets based on those values. We then took the total number of story points, divided them by our average velocity (story points per sprint), added some buffer and – voilà – we had our estimate.

Management approved the project with one requirement: we had to stay releasable, i.e. continue to ship bug fixes and improvements as needed.

Execution Plan

We took the requirement of staying releasable and developed it further – we wanted to keep the effect of a big bang release, but also incrementally release the progress we made. We decided to keep obvious changes like the new icon, new navigation bar colour, new fonts and other significant design changes for the final iteration. But we also wanted to build and ship all of the major technical changes (like switching to Collection Views, adding iPad support etc.) on a section-by-section basis. That way we could test our new software design very early on and adapt as needed.

before_after_clean

 

Universalised News Feed before and after launch of version 5.0

Findings

We learnt quite a lot during this project. Following the example set by others (e.g. Artsy), we also want to share the things which didn’t go as planned. Stefan has written an article about technical decisions regarding Auto Layout we took, but had to revise mid-project. Jose follows up with a detailed article on how we solved it. And Piet shares more technical insights on how our execution plan worked out.

All in all, the intense preparation helped a lot in terms of maintaining a sense of where we were throughout the entire project. Our agile approach allowed us to adapt to the issues we encountered so that we were still able to finish the project on schedule. The project was a success and we were very happy with the end result, especially given the fact that, at launch, the app sky-rocketed from nowhere to #1 in the German iPad App Store.

 


Win tickets for the StartupWeekend Women Hamburg

Hi folks (German text see below),
as sponsor of the StartupWeekend Women in Hamburg (10-12 April, 2015), XING is giving away two developer tickets for the event. Such, two lucky coders can join for free this high-energy and inspiring event.

Developers who are interested to join, please write to

  • sweepstake@xing.com
  • no later than 7 April, 2015 (incl.)
  • mention in the subject field “StartupWeekend Women”.

On 8 April, 2015 we will then draw the two lucky winners and will inform them via an answer to their email.

During a StartupWeekend, participants can present their business ideas to the audience and then work in teams to bring them live over 54hours. While the event StartupWeekend Women has a high focus on attracting women, men are welcome as well. You don’t need to have a team yet; the teams are gathering around the ideas at the event. You can participate also if you don’t have a business idea; in that case you will help other’s idea to become reality.  You will be supported by experienced mentors and will present the result of your weekend’s work on Sunday to an amazing jury. In any case: you will meet great people and you will have a LOT of fun.

Looking forward to see you there!

HAPPY EASTER!

Startup Weekend Women

====

Als Sponsor des StartupWeekend Women in Hamburg (10-12 April, 2015), verlost XING zwei Freikarten an Entwickler, um an diesem beeindruckenden und inspirierenden Event teilnehmen zu können.

Interessierte Entwickler schreiben bitte an:

  • sweepstake@xing.com
  • spätestens bis zum 7. April, 2015 (einschließlich)
  • mit dem Betreff “StartupWeekend Women”

Am 8. April werden wir die zwei glücklichen Gewinner ziehen und informieren sie darüber als Antwort auf ihre email.

Während eines StartupWeekends, können die Teilnehmer ihre Geschäftsideen der Teilnehmerschaft vorstellen und arbeiten dann in Teams im Laufe von 54 Stunden an deren Realisierung. Das StartupWeekend Women hat einen starken Fokus auf weibliche Teilnehmerinnen, Männer sind jedoch auch sehr willkommen. Ihr müsst nicht von vornherein ein Team haben; die Teams bilden sich um die Geschäftsideen auf dem Event. Seid dabei, auch wenn ihr keine Geschäftsidee habt; in diesem Fall könnt ihr an der Realisierung der Ideen anderer beitragen. Während des Wochenendes werdet ihr von erfahrenen Mentoren unterstützt und werdet den Stand eurer Arbeit am Sonntag einer ausgezeichneten Jury vorstellen. Auf alle Fälle werdet ihr tolle Leute kennenlernen und VIEL Spaß haben.

Wir freuen uns auf euch!

FROHE OSTERN


Posted by Melissa Lang

Filed under Agile

The Job Fair: On Choosing Teams

IMG_6240

Background
Change is afoot in our business unit and one of the challenges we’re facing is finding a way to accommodate new product development with the existing teams we have.  In collaboration with the product team we decided to do a bit of a re-org and make 5 teams out of the 3 teams we currently have.

 

Inspiration: What is a Job Fair?  Why hold a Job Fair?
When the subject first came up in our leadership team weekly meeting I sent the leadership team these podcasts from the McCarthy Show:

In the podcasts, Michele and Jim McCarthy describe the motivation- numbing effect of traditional re-orgs at Microsoft, and what they did instead.  When faced with another re-org, instead of the usual sitting in endless rounds of meetings full of political battles, they organized a job fair.  If you’ve never been to a job fair, basically it is an event where companies set up brightly decorated information booths full of smiling recruiters, all trying to snap up talent.  There are job fairs at colleges and universities for new graduates as well as industry or sector specific job fairs.

The job fair the McCarthys organized took a similar format and delivered the results everyone was looking for.  As always their wisdom and approach is an inspiration to me.  There were a few key points they made that convinced us to use a job fair format for ourselves:

 

Transparency
This is one value that we share here and having a job fair would be a great way to uphold that value.  We would be transparent about the fact that new teams would be formed; what the teams would be working on; how many people each team would have; who the product owner, team lead, scrum master and ux for the team would be; how we would deal with conflicts over team choices.

During the actual job fair it was clear who was choosing which teams as their first and second choice. Some people used that information to make their team decisions — either choosing teams that had people they liked to work with, or passing on teams that had people they knew they didn’t want to work with.

We prepared a confluence page before-hand with some anticipated Q&A, and asked everyone to add any additional questions in the days leading up to the kick-off.

 

Trust
This is another core value of ours, and again the Job Fair format does a good job of supporting it.  By using this format the message we wanted to send to the people was that we believe each person knows better than we do what they want to work on and with whom they want to work.  Rather than pushing names around an org chart in a closed meeting room, we believed the group could put themselves in teams with minimal interference from us.

 

Accountability
An added benefit of being able to choose your own team is that because the choice is yours, you now are accountable to the team to make it work.  It’s not so easy now to blame the other people on the team, or your manager for putting you on a team you don’t like.

 

Efficiency
Not counting the preparation before the job fair, the kick-off for the job fair where the POs presented their projects took 2 hours.  By the end of the first day about 90% of the people had made their decision. By the next day the teams were fixed.

Product owners and team leads were available for more in depth discussions with people who wanted to find out more in order to make a decision.

 

Preparation

Our first challenge was getting agreement not only with the leadership team, but also the Product Owners as well as our HR business partner.  Getting buy-in from the POs was simple.  Our HR business partner expressed some concerns, mostly around expecting the unexpected.  In the end we decided to with our gut instinct that this would work.

Next we put together the team templates.  We included the following info:

  • Product/Project name
  • Product Owner name
  • Team Lead name
  • Scrum master name
  • UX name
  • # of devs required
  • # of QA required
  • any extra info about specialist knowledge; technology stack;
Team Template

Team Template

We prepared a confluence page with some Q&A that we thought would be asked.  One week before the fair we emailed everyone announcing the event and pointing them to the confluence page.

 

The Day
We began the day with a half hour breakfast.  Some of the product owners were relatively new and had not yet met any of the team here so we thought it would be good to start with an ice breaker.

The kick-off began with an introduction from Gemma, our VP Engineering.  She again told people why we were doing this, what our expected outcome was, and general time constraints.

PO Presentation

PO Presentation

Each product owner was given 20 minutes to present their products/projects.  Some used a PPT template that had the high level roadmap.  Some preferred to talk freestyle about what the project/product was about, what they saw the challenges being, how they liked to work, and most importantly what they didn’t know yet and needed help figuring out.  There was an opportunity for some Q&A after each product presentation.

Once all the presentations were done each person was given two post-its — one for their first choice and one for their second choice.  People were allowed to add their post-it to a team even if the number of other post-its exceeded the total.  We asked all the POs to make themselves available to answer any other questions people had about their projects.

Team Selection

Team Selection

 

Final Results
We held the fair on a Wednesday and our goal for the Job Fair was to have all the new team assignments finalized by the end of the same week.  By the end of day Wednesday all of the 1st choice post-its had been placed, and all but 2 of the 2nd choice post-its were placed as well.

The leadership team decided to do an initial processing of the results with the POs.  The majority of people got their first choice.  Before sharing the final teams with everyone the team leads spoke with the people who didn’t get their first choice and made sure they were ok with their team assignments.

 

Feedback
After the job fair we asked people to give us feedback so that we could learn what needed to be improved. Here are some of the feedbacks we received:

Great idea of trusting the developers to pick their team! Giving employees this freedom and responsibility will lead to higher motivated employees…

Nice idea having POs showing their plans/ideas and let members to make their choice based on technical preferences, etc. Looking forward to see more of this ideas

Was really nice but I would love to see more technical talk and less product talk, a balance would be great as also developers can sell what you will be doing in the project in case you change

 

Retrospective
We unfortunately didn’t do a retrospective immediately after the job fair.  After the retro we found some areas to improve on:

1) Transparency: how we decide final assignments.  what are the new roles and dependencies for filling them.  what we know/don’t know

2) PO presentations: need for preparation, need to provide similar content.  need for tech perspective as well.

3) Timing: when is a good time to decide final assignments?  when should we hold the next job fair?  how much info do we need upfront to make it meaningful?

4) Choosing teams: only have two choices or ask people to rank all the projects in terms of preference?

 

Next Steps

Our next steps are to do another session to derive some action points from the open topics in the retrospective.  Additionally I’m hoping to spread the word about this to our other offices and offer to help facilitate a job fair for whoever needs it.


Square profile images

XING moved to square profile images this week. Some parts of the platform used square images before, but they were kind of cheating as they took the rectangular image and used CSS to mask it. With the recent change, we’re going to use square image files and if a user uploads a non-square image, they are able to select the part of the image to be used.

If you build a new web app from scratch, incorporating square images is not a big deal. On the other hand, migrating an existing app from one image format to another poses some additional challenges as existing users have to be migrated and some backwards compatibility needs to be ensured. → Read more…


Posted by Kerstin Puschke

Filed under Everything else

YAPC::EU 2014

Last week, the city of Sofia, Bulgaria, played host to the 15th YAPC::EU conference all about the Perl programming language.

This year’s YAPC::EU was again a three-day event featuring three parallel tracks of talks during the day, followed by a set of lightning talks and a keynote speech every evening. In his opening keynote, ‘You’re Killing Managers (Keep It Up)‎’, Curtis Poe (‎Ovid‎) provided us with lots of food for thought when it comes to managerless companies. Despite generally being seen as a nightmare by many traditionally minded managers, agile methodologies reduce the need for at least some of the middle management, and some companies already succeed without having any kind of predictable shipping date for their products.

The regular talks again covered a broad range of topics including the web, dev ops, community management, databases, functional programming and, of course, the current state of Perl 6. Some talks were already familiar to me from previous events like the German Perl Workshop, but there was still a variety of interesting presentations to choose from. → Read more…


Posted by Björn Jensen

Filed under Agile Everything else

Ready, steady, go!

The first Agile Coaching Circle event got off to a flying start

It started with a simple post to all the agile coaches at XING: what do you think about the “Kollegiale Beratung” coaches exchange and its format, its value?

Björn Jensen introducing "Nobody's perfct"

Time for something new?

After some back and forth, Alexey Krivitsky, Julia Rüterböries and Björn Jensen met up in our kitchen on the 6th floor to discuss some options. In the end, we came to the conclusion that opening the coaches exchange to a wider audience would make sense for us as coaches and for us as XING as well.

Why? That’s easy – the coaches exchange should enable us to grow by sharing experiences, failures, findings, etc. So it’s perfect aligned with our vision: “enable professionals to grow – for a better working life”. Eating your own dog food is good, but getting input from the outside world is also valuable. So we thought it would be cool to listen to others and share our experience with them.

But something new also means creating something valuable for the existing communities that isn’t already in place. We have a lot of community meet-ups here in Hamburg, but they’re generally some kind of open forum or frontal presentation, so we decided to merge both approaches.
→ Read more…