Server Side Mustard Cut

Go to Source

The term “mustard cutting” in web design comes from developers at the BBC who wanted to serve different experiences of their site to different browsers on different devices. They were specifically trying to avoid User Agent sniffing:

But these days, with such a long tail of user agents now accessing the site, this becomes a fruitless exercise.

Instead, they used feature detection. Modernizr is the classic (awesome) example of that, but ala carte feature tests can be quite small and simple all by themselves. This is the logic the BBC used to determine if a browser cut the mustard or not:

if('querySelector' in document
     && 'localStorage' in window
     && 'addEventListener' in window) {
     // bootstrap the javascript application
     }

If that logic failed, the website still loads what they called a core experience. If that logic passed, additional resources would load for an enhanced experience.

Pretty cool.

Loading additional CSS and JavaScript is fairly easy

There are various ways to do it, typically involving an XHR for the resource. Filament Group has some very tiny, focused scripts just for this: loadCSS and loadJS.

Loading a bit of extra HTML via XHR is similarly easy. But…

It’s too hard to load an entirely different document client-side

Say you don’t need just a bit of extra CSS, scripts, or a bit of HTML. What you want is an entirely different document.

Your “core experience” and “enhanced experience” are entirely different sets of HTML, CSS, and JavaScript. Trying to do this client-side would mean trying to load a super bare-bones document, then trying to essentially re-create how the browser parser works. First you mustard-cut, then XHR for the right set of HTML you need, then either drop it into the DOM, or perhaps wait until you’ve XHR’d for the CSS so you don’t get a flash of unstyled document. Then XHR for all the scripts, and make sure that you execute them in order (tricky).

Hard to pull off.

Allow the server to serve the correct document based on mustard-cutting information

If the server knew the results of your mustard-cut, you could avoid all that trouble and serve the correct document right off the bat.

That’s the whole point of client-side mustard-cutting: it can only be done on the client. But… you could save that data to a cookie, and cookies can be read by the server.

It you had a cookie you could count on, you could do something like this in the routing of your site:

<?php
  // This is just a fake routing/controller kinda setup.
  if (isset($_COOKIE["mustard"])) {
    // Enhanced experience
    if ($_COOKIE["mustard"] == true) {
      include_once("enhanced.php");
    // Core experience
    } else {
      include_once("core.php");
    }
  // No cookie = core experience
  } else {
    include_once("core.php");
  }
?>

What happens on the first page view though?

That’s the tricky part here. That cookie won’t exist on the first page view. You could just let subsequent pages serve the correct experience, but that’s not likely to be acceptable.

Here comes the most controversial part: if you don’t have the cookie but can tell the browser supports them and they are enabled, you refresh the page.

Refresh the page?! Are you kidding?

Totally reasonable questions: How can a refresh possibly be a good user experience? Aren’t refreshes slow? Couldn’t you get caught in a refresh loop?

I think all of these things can be addressed.

At the very top of the document, if that cookie is not there and the browser does support cookies:

  1. Mustard-cut and save the data to a cookie with JavaScript
  2. If the mustard-cut data tells you you should be loading a different document: halt the page from loading/doing anything else (window.stop();) and refresh (location.reload(true);).

Upon refresh, the cookie will be there for the server.

It all happens so fast when it’s the very first thing a document does that I find it barely noticeable. This is what we’re doing for the editor page on CodePen, see:

Fresh page load on a new incognito window (no cookies saved). The desktop view is actually the default, but the refresh happens and the mobile view loads because of a mustard-cut.

The trick to avoiding a refresh loop is to only execute that part of the JavaScript if you’re sure cookies are supported and enabled.

The mustard-cutting script

Here’s a mustard-cut that only tests the screen width. Bear in mind a mustard-cut could be anything you want it to be that you can test client-side.

(function() {

  // If the browser supports cookies and they are enabled
  if (navigator.cookieEnabled) {

    // Set the cookie for 3 days
    var date = new Date();
    date.setTime(date.getTime() + (3 * 24 * 60 * 60 * 1000));
    var expires = "; expires=" + date.toGMTString();

    // This is where we're setting the mustard cutting information.
    // In this case we're just setting screen width, but it could
    // be anything. Think http://modernizr.com/
    document.cookie = "screen-width=" + window.outerWidth + expires + "; path=/";

    /*
      Only refresh if the WRONG template loads.

      Since we're defaulting to a small screen,
      and we know if this script is running the
      cookie wasn't present on this page load,
      we should refresh if the screen is wider
      than 700.

      This needs to be kept in sync with the server
      side distinction
    */
    if (window.outerWidth > 700) {

      // Halt the browser from loading/doing anything else.
      window.stop();

      // Reload the page, because the cookie will now be
      // set and the server can use it.
      location.reload(true);

    }

  }

}());

In fact, we don’t have to load that script at all if the cookie is already there, since if it is, we know the correct page has loaded already.

<?php
    // Run this script as high up the page as you can,
    // but only if the cookie isn't already present.
    if (isset($_COOKIE["screen-width"]) == 0) { ?>
      <script src="mobile-mustard.js"></script>
<?php } ?>

Possible Scenarios

  • The normal first time visitor: No cookie is present. Mustard-cut script will run and refresh the page quickly. They will get correct document based on cut.
  • The repeat visitor: Cookie is already present. They will get correct document based on cut.
  • Visitor with incorrect cookie: Perhaps they have a desktop browser but it was very narrow when the page loaded the first time, but they have since widened it. We can detect that with a CSS @media query and offer a link to correct the problem (see demo).
  • Visitor with cookies off: We serve our choice of documents. Could potentially be wrong. Serve the best likely case based on data.
  • Visitor in which JavaScript doesn’t run: We serve our choice of documents. Could potentially be wrong. Serve the best likely case based on data.

Possible Problems

For the record, I’m not saying this is the best possible solution to this problem. In fact, if you’re in a situation where you can do everything purely client-side, that’s probably better.

Here’s some potential problems with this solution:

  • Perhaps the reload is slower than I think it is. I didn’t do any testing of super old / super slow devices like I probably should have.
  • HTML caching could be a problem. I experienced this first hand when building the demo on a site that was using that method. The server serves a cached document, which then is determined to be the incorrect one and refreshed, causing the dreaded refresh loop. Solution: don’t HTML cache this page, or redirect to subdomains based on the cut.
  • Security settings that prevent server-side access to cookies created by JavaScript. If you can’t control that, that would be a problem.

I do use this technique in production though and haven’t had an issue in a lot of months, so I’m pretty happy with it.

Demo and Repo

Here’s a demo and the code is up on GitHub if you spot any fouls.

Also, I thought client hints was supposed to be the savior here, but I’m just not sure anymore where it fits into this situation.


Server Side Mustard Cut is a post from CSS-Tricks

Go to Source

Create stunning effects with Amberlight for Windows or Mac – only $9

Go to Source

  • Perfect for all artists, from budding beginners to advanced.
  • Enhance your existing images and designs by adding Amberlight layers right on top of them.
  • Create beautiful unique backgrounds, wallpapers, presentations or gorgeous book covers.
  • Export your images into other graphic applications to include them in a larger art project.
  • Incredibly intuitive and user friendly user interface.

Normally, Amberlight sells for $29.99, but for a limited time only, you can get this fabulously unique artistic tool for a mere $9 – That’s a huge savings of 70% off the regular price – See the deal


Go to Source

Putting Mobile Back End As A Service Into Practice (Part 1)

Go to Source

In a previous article1 I introduced mobile back end as a service (MBaaS) which aims at giving app developers the ability to create seamlessly new feature-complete cross-platform native and web applications.

The next step is implementing a complete demo application using those ideas. Through this real working application, you will be able to see the areas in which MBaaS provides value. This first part will walk you through a messaging application demo powered by the Kinvey application and explore how to leverage user management, file storage and the data store.

The second part will complete the demo and demonstrate how to leverage two key pieces of Kinvey functionality: the permissions provided by the data store, and push notifications, which are enabled through the business logic functionality.

Setting Up

Before jumping into the demo application, I want to highlight a few points. First, because I am using a real app to discuss MBaaS, knowledge of the development platform would be extremely helpful. I am leveraging iOS with Swift. In addition, knowing how to integrate with back-end services would certainly be helpful, in order to understand more about what Kinvey is doing under the hood. While all of this is helpful, the application’s full source is included; feel free to analyze the code at your own pace.

Secondly, because the demo application has more of an enterprise focus (as opposed to a consumer focus), I chose Kinvey2 for the MBaaS platform. In the last article3 I walked through the process of evaluating MBaaS providers. Note that Kinvey is not a free service, and licensing terms are attached to its SDKs (as one would expect). Licensing terms are included with each SDK download. You can get more information at the following links:

A Demo Application

In the past three years, several clients have approached me about developing an internal messaging platform for their organization. This need has led to the success of such companies as Slack6 (which we use internally at Universal Mind7) and others like it. Because this was a common request, I wanted to see what it would take to implement a basic one-to-one messaging solution for an organization over top of an MBaaS solution.

To help you understand these concepts in a real application, I have provided the application’s entire source code. You can check it out on Github, “WaterCooler Demo8.”

Note: For more information on how to choose between the available MBaaS options, please see the initial article in this series, “Understanding Mobile Back End as a Service9.”

Screenshots of WaterCooler app10
WaterCooler demo messaging app. (View large version11)

Summary of Requirements

To illustrate how an MBaaS solution can power an app like this one, we need to meet a few key requirements. Users should be able to do the following with the app:

  • create an account and set up their profile (including name, title, profile picture, email address and password);
  • log in (and be required to log in only once — at least until they log out);
  • exchange one-to-one messages with other members (visible only to the sender and recipient and inaccessible to other users);
  • browse a directory of members who currently have an account on the platform;
  • log out;
  • manage and update their profile information;
  • be alerted through a push notification that they’ve received a new message.

The following sections detail how I used Kinvey to meet these requirements. While I won’t go into detail on how every part of the application was created, I will give full context of the areas where Kinvey was leveraged.

Technical Details

The demo application is an iOS app targeting iOS 8+. It utilizes Swift (Xcode 6.1.1 and iOS 8.1.3).

The user interface was created following standard UI principles for iOS. It leverages Auto Layout12 (both within the storyboard and programmatically). The creation of this interface is beyond the scope of the article, but hopefully the example code will be helpful for your iOS applications.

Getting Started With Kinvey

If you’re following along, you’ll probably want to build the source code and run the application yourself. To do this, you will need both to create a Kinvey app and to include the credentials for the app in your code.

Creating a Kinvey App and Environment

To create a Kinvey app and environment, you will need to create a Kinvey account13. After signing up, select “Get Started with Your First App.” From this page, give your app a name, select iOS and the platform, and then click “Create App.”

Screenshot of creating an app in Kinvey14
A view of the process of creating an app in Kinvey. (View large version15)

From here, you will have an app created with a single development environment. Clicking on the “Development” environment will take you to the console. In the console, you will see both your appKey and appSecret in the top right. Copy these pieces of information because you’ll need to include them in the iOS app.

Configuring the iOS Application

Once you have created your Kinvey app and gathered your credentials, grab the code from the repository. Next, open the AppDelegate.swift file and update these values in the application:DidFinishLaunchingWithOptions: method.

// Extracted from AppDelegate.swift (http://tuck.cc/1w7wkyI)

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

 // --------------------------------------------------------------------
 // INCLUDE YOUR KINVEY CREDENTIALS HERE
 // --------------------------------------------------------------------

 let appKey = ""
 let appSecret = ""

 //---------------------------------------------------------------------

 …
}

Once this is in place, you should be able to run the application as expected. If you want to run the application on a device, you will have to update the code signing as provisioning profiles (as with any iOS application).

  • For more information on setting up an iOS application with Kinvey, check out the “Getting Started16” tutorial.

User Management

One foundational element of any MBaaS is user management. This application will leverage user management to control individual user accounts and their respective profile information, as well as provide a directory of all users in the system. Just as with the rest of the functionality we will cover, this integration is provided through Kinvey’s iOS SDK17.

Sign-up, log-in and profile views18
A view of the sign-up, log-in and profile views in the application. (View large version19)

Creating a User

The first step in the process is to enable a user to create an account. When a user launches the application, they will land on the view that allows them to either log in or sign up. If the user selects “Sign Up,” they will be taken to the “Sign Up” page, which will guide them through the process of entering their profile information. When this process is complete, the code below is executed, which creates an account and logs the user into the application.

In this example, you will see the KCSUser class. This class handles the representation of a user and is also the gateway for all operations related to user management:

// Extracted from SignupViewController.swift (http://tuck.cc/1vsaWcr)

// Set the parameters of the user
var userParams = [
 KCSUserAttributeGivenname : firstNameField.text,
 KCSUserAttributeSurname : lastNameField.text,
 KCSUserAttributeEmail : emailField.text,
 kWaterCoolerUserTitleValue : titleField.text
];

// Save the user to Kinvey
KCSUser.userWithUsername(emailField.text, password: passwordField.text, fieldsAndValues: userParams) { (user:KCSUser!, error:NSError!, result:KCSUserActionResult) in
 if(error != nil) {
 println("USER NOT CREATED - ERROR: " + error.description)
 } else {
 // User created successfully
 // Do other tasks, such as uploading profile picture to the file store
 }
}

In this case, the fields for first name, last name and email address are include in the KCSUser object. However, Kinvey allows us to save other pieces of data in this object as well. The user’s title will be saved in one of these additional fields. An extension to the KCSUser object is also included (as seen below) to make it easier to access this value for a user within the application:

// Extracted from KinveyExtensions.swift (http://tuck.cc/1vsb5N7)

// Create a constant for accessing the title key from the user object
let kWaterCoolerUserTitleValue = "title"

extension KCSUser {
 var title:String {
 return self.getValueForAttribute(kWaterCoolerUserTitleValue) as String!
 }
}

Logging In

If the user selects the option to log in from the landing page, they will be able to enter their email address and password (which they entered in the sign-up process). They are presented with an alert if their attempt is unsuccessful, and if they log in correctly, they are redirected to the main view of the application.

// Extracted from LandingPageViewController.swift (http://tuck.cc/1vsbeAe)

func attemptLogin() {
 // Get the values from the form
 let username = loginEmailField.text
 let password = loginPasswordField.text

 // Attempt to log in to the application
 KCSUser.loginWithUsername(username, password: password) { (user, error, actionResult) -> Void in
 if(error == nil) {
 self.successfulLogin()
 } else {
 self.incorrectLoginWithError(error)
 }
 }
}

func incorrectLoginWithError(error:NSError) {
 // Let the user know an error occurred in login. In this case
 // we just present an alert using the UIAlertController.
 let alert = UIAlertController(title: "Failed Login", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.Alert)
 alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: { (alertAction) -> Void in
 self.dismissViewControllerAnimated(true, completion:nil)
 }))

 // Present the alert
 presentViewController(alert, animated: true, completion: nil)
}

func successfulLogin() {
 // There is already a segue defined to the main threads view.
 // We need to perform this segue if we have a successful login.
 performSegueWithIdentifier(WaterCoolerConstants.Segue.Login, sender: self)
}

Logging Out

From the profile management page, the user can log out of the application. Upon doing this, Kinvey’s iOS SDK also does some additional work in the background, including clearing out any cached values. In this example, after logging out, the user is redirected back to the landing page.

// Perform the log-out and send the user to landing page
@IBAction func logout() {
 KCSUser.activeUser().logout()
 performSegueWithIdentifier(WaterCoolerConstants.Segue.Logout, sender: self)
}

User Directory

To fulfill all of our requirements, the application also needs to provide a list of all users. A special collection, KCSCollection.userCollection(), provides access to the collection of users for an application. Once you have created a store from this collection, you can query it as you would any other data collection. The following example illustrates how to fetch all users for the application:

// Extracted from KinveyDataManager.swift (http://tuck.cc/1vsd0Bp)

// Create the app data store corresponding to the users collection
lazy var userStore:KCSAppdataStore = {
 let userCollection:KCSCollection = KCSCollection.userCollection()
 let store = KCSAppdataStore(collection: userCollection, options: nil)
 return store
}()

// Fetch the users from the user store
func fetchUsers(completion: ([KCSUser]!, NSError!) -> ()) {
 userStore.queryWithQuery(KCSQuery(), withCompletionBlock: { (results, error) -> Void in
 if(error == nil) {
 self.users = results as [KCSUser]
 completion(results as [KCSUser]!, nil)
 } else {
 completion(nil, error)
 }
 }, withProgressBlock: nil)
}

Note: For more information on managing users with Kinvey’s iOS SDK, be sure to check out the “Users20” guide.

File Management

One powerful feature of many MBaaS solutions is file storage. In our WaterCooler application, this comes into play when a user creates an account and adds a profile picture. We could also leverage this heavily to extend the app to support the uploading of images within messages. In this process, the file is uploaded to a content delivery network (CDN) and, like any other piece of data, has a full configuration of permissions.

// Extracted from SignupViewController.swift (http://tuck.cc/1vsaWcr)

// Upload the profile picture to the Kinvey file store
func uploadProfilePicture(completion:(file:KCSFile!) -> ()) {
 if((self.photo.image) != nil) {
 let photoData = UIImageJPEGRepresentation(self.photo.image, 1.0)

 KCSFileStore.uploadData(photoData, options: fileParams, completionBlock: { (file:KCSFile!, error:NSError!) -> Void in
 completion(file: file);
 }, progressBlock: nil);

 } else {
 completion(file: nil);
 }
}

// Once we have completed the file upload, assign the file ID to the user
// using a custom attribute
func assignProfilePictureIdToUser(user:KCSUser, picture:KCSFile, completion: () -> Void) {
 user.setValue(picture.kinveyObjectId(), forAttribute: kWaterCoolerUserProfilePicFileId);
 user.saveWithCompletionBlock { (user:[AnyObject]!, error:NSError!) -> Void in
 completion();
 }
}

In the code above, two distinct steps are occurring. First, we are uploading the profile picture to the file store. Once this process is completed, we are updating the user with the ID that the file store has returned. In this manner, we are leveraging yet another custom property on the user to store an identifying piece of information. Now, anywhere we display a list of users, we can also display their profile picture.

Note: For more information on working with files in Kinvey’s iOS SDK, see the “Files21” guide.

Data Model

One of the benefits of Kinvey’s iOS SDK is that it allows you to map your Swift (or Objective-C) objects to Kinvey collection objects. The KCSUser class is a special class that is already defined and mapped to the user object, but in our case we will create two additional data classes that map to conversations and the messages within them.

WaterCooler Data Model

The WaterCooler data model will have two main entities, Message and MessageThread.

The MessageThread class will be responsible for representing a conversation between two users. It will contain information about the users involved in the conversation, as well as a reference to the last message sent in the conversation.

Within Kinvey, the entityId is a special field. If you do not assign a value to it, the system will assign one when the object is saved to the data store. In our case, we will go ahead and define a special value that maps to the two users who are in a conversation for the MessageThread class. The method that calculates this value can be seen below:

// Extracted from MessageThread.swift (http://tuck.cc/1w7jdOd)

// This method simply takes a user and the current user and creates
// an ID based on the alphabetized array of user IDs between these
// two users. In this way, we don't have to fetch additional information
// when displaying the message thread view.
class func threadIdentifierForUser(user:KCSUser) -> String {
 let userAIdentifier:String = KCSUser.activeUser().userId
 let userBIdentifier:String = user.userId
 let identifiers:[String] = [ userAIdentifier, userBIdentifier ]
 let sortedIdentifiers = identifiers.sorted {
 $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending
 }
 return ":".join(sortedIdentifiers)
}

The Message class will be responsible for tracking an individual message within an overall conversation. This class contains information about the message, including its time, contents, sender and related message thread. To get all of the messages for a particular conversation, we simply query based on the threadId of the conversation. The following code fetches all of the messages for a predefined message thread:

// Extracted from KinveyDataManager.swift (http://tuck.cc/1vsd0Bp)

func messagesForThread(thread:MessageThread, completion:([Message]) -> ()) {
 let query = KCSQuery(onField: "threadId", withExactMatchForValue: thread.entityId)
 messagesStore.queryWithQuery(query, withCompletionBlock: { (results, error) -> Void in
 completion(results as [Message])
 }, withProgressBlock: nil)
}

Data Model Relationships

Kinvey supports data model relationships within both the core data store as well as the iOS SDK. In our situation, the lastMessage property on the MessageThread class is one such instance. When we fetch a thread, it looks at specific methods in our class to determine how it should handle references to other collection objects. In our case, the following methods allow it to treat this reference as a Message instance:

// Extracted from MessageThread.swift (http://tuck.cc/1w7jdOd)

// This method tells Kinvey to save the message in the lastMessage property
// when the thread is saved. If this method were not included, the message
// itself would not be saved when the thread is saved.
override func referenceKinveyPropertiesOfObjectsToSave() -> [AnyObject]! {
 return [
 "lastMessage"
 ]
}

// This maps the properties in the class to specific values in the Kinvey
// data store.
override func hostToKinveyPropertyMapping() -> [NSObject : AnyObject]! {
 return [
 "entityId" : KCSEntityKeyId,
 "lastMessage" : "lastMessage",
 "metadata" : KCSEntityKeyMetadata
 ]
}

// This method tells Kinvey that the lastMessage property is a member of
// the Messages collection. (You need to put the name of the Kinvey collection
// here and not the name of the class.)
override class func kinveyPropertyToCollectionMapping() -> [NSObject : AnyObject]! {
 return [
 "lastMessage" : "Messages"
 ]
}

// Here you tell Kinvey which class to map the lastMessage property to. This
// is how it knows how to build the object when it fetches it from the server.
override class func kinveyObjectBuilderOptions() -> [NSObject : AnyObject]! {
 let referenceMap:[NSObject : AnyObject] = [
 "lastMessage" : Message.self
 ]
 return [
 KCS_REFERENCE_MAP_KEY : referenceMap
 ]
}

Data Model Classes in Swift

For data model classes to work properly in Swift, they need to be able to leverage the default initializer. This means you need to have a default value for each property within the class. You can still leverage convenience initializers, as we have done here with the Message class:

// Extracted from Message.swift (http://tuck.cc/1w7kkgB)

// This initializer creates a Message instance based on the message text
// and the recipient ID. This is the initializer that is used when a
// user creates a new message in a conversation.
init(messageText:String, recipientId:String) {
 senderId = KCSUser.activeUser().userId
 self.messageText = messageText
 entityId = NSUUID().UUIDString
 metadata = KCSMetadata(userIds: [recipientId], includeActiveUser:true)
}

Note: For more information on the data store and data modeling in Kinvey, see the “Data Store22” guide.

Conclusion

Through this process, we have completed the core of Kinvey interactions for the application. However, with all of this in place, two key requirements still have not been met: data permissions and push notifications. In the next article, we will explore the permissions model in Kinvey, as well as the business logic functionality provided by the platform.

(da, al, ml)

Footnotes

  1. 1 http://www.smashingmagazine.com/2014/12/15/understanding-mobile-back-end-as-a-service/
  2. 2 http://www.kinvey.com/
  3. 3 http://www.smashingmagazine.com/2014/12/15/understanding-mobile-back-end-as-a-service/
  4. 4 http://www.kinvey.com/pricing-starter
  5. 5 http://www.kinvey.com/pricing
  6. 6 https://slack.com/
  7. 7 http://www.universalmind.com/
  8. 8 https://github.com/davidtucker/WaterCooler-Demo
  9. 9 http://www.smashingmagazine.com/2014/12/15/understanding-mobile-back-end-as-a-service/
  10. 10 http://www.smashingmagazine.com/wp-content/uploads/2015/03/01-watercooler-demo-app-opt.jpg
  11. 11 http://www.smashingmagazine.com/wp-content/uploads/2015/03/01-watercooler-demo-app-opt.jpg
  12. 12 https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/Introduction/Introduction.html
  13. 13 http://www.kinvey.com/
  14. 14 http://www.smashingmagazine.com/wp-content/uploads/2015/03/02-new-app-kinvey-opt.jpg
  15. 15 http://www.smashingmagazine.com/wp-content/uploads/2015/03/02-new-app-kinvey-opt.jpg
  16. 16 http://devcenter.kinvey.com/ios/guides/getting-started
  17. 17 http://devcenter.kinvey.com/ios/guides/getting-started
  18. 18 http://www.smashingmagazine.com/wp-content/uploads/2015/03/03-user-management-opt.jpg
  19. 19 http://www.smashingmagazine.com/wp-content/uploads/2015/03/03-user-management-opt.jpg
  20. 20 http://devcenter.kinvey.com/ios/guides/users
  21. 21 http://devcenter.kinvey.com/ios/guides/files
  22. 22 http://devcenter.kinvey.com/ios/guides/datastore

The post Putting Mobile Back End As A Service Into Practice (Part 1) appeared first on Smashing Magazine.

Go to Source

Could you really be a UX designer?

Go to Source

So you think you are a user experience designer?

Are you sure? You might have it in your job title, but are you somebody who designs experiences for users? Or do you design user interfaces?

UX vs. UI

Some argue that you cannot design a user’s experience. After all there are so many things beyond your control that you cannot influence. But that is not my point. My point is that many people claim to design experiences, when they are actually designing a user interface. You see the user interface is just a tiny part of the experience, not the whole thing.

Take, for example, the rides at Disney. These rides are a crucial component of the Disney experience, but they are not the whole thing. Disney know this, which is why they craft every aspect of their customers’ experience, from the moment you buy tickets, to the member of staff who waves goodbye as you leave the park.

There is nothing wrong with being a user interface designer. But if you are keen to start designing the user experience, you will need to step outside of your comfort zone.

Adjust your attitude

The first step to becoming a user experience designer is a change in attitude.

As designers we tend to have a focused view on what our role is. But if we are going to call ourselves user experience designers we need to ditch the it’s not my area mentality.

A user experience designer has to be a maverick…willing to challenge traditional business

Take, for example, content. We are quick to complain if the client does not deliver the content or if the content is of poor quality. But we are slow to correct the situation. After all it is not our job. We are not paid to write copy.

Even so, if you call yourself a user experience designer you are responsible for any area that impacts the user experience. Even if somebody else also considers that area their responsibility.

A user experience designer has to be a maverick. Somebody willing to challenge traditional business silos and roles. You need to be somebody who doesn’t give up on a better user experience just because you meet a barrier.

Imagine you cannot take a particular design approach. Somebody feels it would break the company’s brand guidelines. What will you do?

A user interface designer may accept that constraint. After all, branding is outside their area of responsibility. A user experience designer would not. They would find out who owns the brand guidelines and work with them to find the right solution.

You see, user experience design is about collaborating with others to create the best user experience.

Collaboration lies at the heart of good user experience

There is no way you can create a great user experience alone. There are too many factors involved, too many disciplines required.

Being a user experience designer requires a collaborative relationship with a range of specialists. A user experience designer works with:

  • user interface designers;
  • content specialists;
  • developers;
  • business strategists;
  • retailers;
  • mobile experts;

and more, to create an outstanding experience.

You need to collaborate over areas such as content creation, site performance, SEO, and social media. Each will help to streamline the user’s experience. This is especially important in a multi-channel world.

We all know user interface design has become more complicated with the plethora of devices we now use. But for a user experience designer that is just the tip of the iceberg. Not only do you need to worry about users moving between devices, we also need to consider how users are moving between channels. A user may start on Facebook, move to a website and end up on YouTube.

In larger organisations things get even more complex as users get passed between departments. Often different business silos manage different parts of the website or different mailing lists. This can lead to a jarring experience for users.

For example, I once worked with a charity whose most dedicated donors received over eight emails a week from the them. They were spamming their best donors, all because nobody was tracking what went out.

But the user experience is not just about devices and channels. We must also realize that the users’ experience extends beyond their screens.

Following UX beyond the screen

If we wish to call ourselves user experience designers, we need to consider the context of the users’ digital experience. Digital interactions do not happen in isolation. They are a part of a broader customer experience. You can have the best website in the world; but if the rest of the customer experience is poor, you have achieved nothing.

The success of Zappos.com was not down to their user interface

The success of Zappos.com was not down to their user interface. It was down to the amazing experience created by their return and shipping policy.

I once worked on an e-commerce site that delivered frozen ready meals to the elderly. This was not an audience who were particularly comfortable with the idea of e-commerce. We needed to do everything possible to make it a painless experience. Many of the things we did focused on simplifying the online purchasing experience. That, and reassuring the user about things like security or privacy. But one key component of the experience lay beyond the user interface. Many of our elderly customers were nervous about a stranger delivering goods to their door. This was especially true when one of the services offered was unpacking the delivery in the customer’s home. As a user interface designer it would be tempting to add a reassuring message onto the website and conclude that was all you could do. Instead, together with the client, we decided to police check all the delivery people as a way of reassuring customers.

It is always important to remember that the digital tools we build are just one small part of the customer experience. Other areas such as customer service, fulfillment, governance and strategy are also crucial to the experience.

How far are you willing to go?

Have you had enough of building websites or mobile apps that fail? Fail because of shortcomings in other areas of the user experience? If so then it is time to push the boundaries of your role.

It is time to start questioning and collaborating with everybody to build a better experience. Do not presume you have all the answers. But be willing to challenge the status quo. Ask difficult questions. Do whatever it takes, if it has the potential to improve the user’s experience.

 

Featured image, collaboration image via Shutterstock.

InstaGlam: Add Gold and Glam to your designs – only $17!
Could you really be a UX designer?

Source
Go to Source

Collective #161

Go to Source

Collective161_diePNG

Die PNG. Die!

Vincent Le Moign shows how to use vector icons in your app and finally ditch those PNG assets.

Read it

Advertisement

Collective161_cuberunner

Cuberunner

Game5 created this superb and addictive game made with WebGL, Three.js and Shaders. Featured in Chrome Experiments.

Check it out

Collective161_BadHead

Free Font: Badhead

A fresh looking font with a strong character designed by ianmikraz and freely available on PixelBuddha.

Get it

Collective161_Primer

Primer

Primer is the CSS toolkit that powers GitHub’s front-end design and now you can use it in your project.

Check it out

Collective161_shaders

The Book of Shaders

Patricio Gonzalez Vivo introduces you to the abstract and complex universe of Fragment Shaders. A work in progress with new chapters being released regularly.

Read it

Collective161_Periscope

Periscope

The next big app for sharing and watching live video broadcasts from your mobile phone. Read more about it here.

Check it out

Collective161_cssloaders

Loaders.css

If you’re still not on the SVG bandwagon for loaders and prefer HTML and CSS, then have a look at Connor Atherton’s loader set.

Check it out

Collective161_whisky

Whiskey Break

Evgeniy Artsebasov designed this set of Whiskey-related icons and offers them for free on The Noun Project.

Get it

Collective #161 was written by Mary Lou and published on Codrops.


Go to Source

Our favorite tweets of the week: March 23, 2015 – March 29, 2015

Go to Source

Every week we tweet a lot of interesting stuff highlighting great content that we find on the web that can be of interest to web designers.

The best way to keep track of our tweets is simply to follow us on Twitter, however, in case you missed some here’s a quick and useful compilation of the best tweets that we sent out this past week.

Note that this is only a very small selection of the links that we tweeted about, so don’t miss out.

To keep up to date with all the cool links, simply follow us @DesignerDepot

Funny collage series by Brest Brest Brest http://ow.ly/i/a78PN http://bit.ly/1E34Cf4

 

Nuclide — a unified IDE from Facebook http://bit.ly/1ygGsq3

 

Periscope by Twitter http://bit.ly/1EHj0V3

 

Find the perfect colour for your website http://bit.ly/T1orO4 via @CreativeBloq

 

#WordPress: it ain’t perfect – but neither are the people who use it http://bit.ly/1EXP3D5

 

SoundCloud new music player and flatter UI http://bit.ly/1Ng8Np3 What do you think?

 

When to Sell Your Company http://bit.ly/1mgKngb

 

YES, you can use Twitter Group DM for business http://bit.ly/1ximkZj

 

When you should design against client expectations http://bit.ly/1xjvyoc

 

Wamer Sketch – online #WYSIWYG tool for component-based web development http://wamer.net/sketch/ via @speckyboy

 

Mobile #SEO – Can you optimize for user experience and Google at the same time? http://bit.ly/19WqRGK

 

Why @vandelaydesign switched its hosting to WP Engine & the experience they’ve had so far http://bit.ly/19OxRWb /@JHTScherck

 

CSS dancing robots http://bit.ly/1DRr2zN via @andysowards

 

The user is drunk http://bit.ly/19O0OBv

 

Coca-Cola 100×100 by Greig Anderson http://bit.ly/1y4L7LG /@abduzeedo

 

Can you name these 27 movie posters missing their titles & characters http://bit.ly/1CjVIaQ

 

Impulse Ecommerce: applying real world principles online http://bit.ly/1B7WT9f

 

 Awesome illustration by David de Ramon http://on.be.net/1xdTmd9

 

Goethe’s theory of colors http://bit.ly/1yy6aH7 via @brainpicker

 

Want more? No problem! Keep track of all our tweets by following us @DesignerDepot

InstaGlam: Add Gold and Glam to your designs – only $17!
Our favorite tweets of the week: March 23, 2015   March 29, 2015

Source
Go to Source

Comics of the week #280

Go to Source

Every week we feature a set of comics created exclusively for WDD.

The content revolves around web design, blogging and funny situations that we encounter in our daily lives as designers.

These great cartoons are created by Jerry King, an award-winning cartoonist who’s one of the most published, prolific and versatile cartoonists in the world today.

So for a few moments, take a break from your daily routine, have a laugh and enjoy these funny cartoons.

Feel free to leave your comments and suggestions below as well as any related stories of your own…

If you’ve seen one, you’ve seen them all

Comics of the week #280

 

What’s the second prize?

 

Comics of the week #280

No offense

Comics of the week #280

Can you relate to these situations? Please share your funny stories and comments below…

Magnolia: 150+ Professional Infographic Elements – only $9!
Comics of the week #280

Source
Go to Source