Monday, January 11, 2016

Images CSS

Let`s discuss few different image usage patterns, and their relevant CSS.
In all cases, we assume source image size is different from the div we want it to be in the page, and that aspect-ratio must remain.

  • Full site background image (all-page width and height)
  • Full width but small-height header/middle-page image, common in bootstrap templates.
  • User image by itself, sometimes with circle around it
  • User image inside a gallery of images, where we have known X images in each row, but almost infinite number of scrolling rows.

good start at: http://www.w3schools.com/css/css3_backgrounds.asp


Full site background image (all-page width and height)

.your-div-class {
    background-size: cover;

    background: url(splash-bunny.jpg) no-repeat  center center;
}

Few notes:
1. "background-size: cover"  expects your image to be always greater than the size of the div.  So if your max target size is Samsung note 2 (720x1280), make sure that your image is equal or bigger than that.  If not, the image will be at it`s maximum size on the center of the page, which you don`t want!
2.  Cover will only show a fraction of your image, think of it as a "sliding-window" above your image.  Ask your art dude to make sure the important stuff is in one postion, so that users with small screen can still understand it. It is common to put the important stuff in the center of the image, and then use "center center".
If the important stuff is on the top left, use "top left", see this lovely bunny:

 If you use "center center", on small screens you will only see his pink belly, and no one will understand what the cover image means.
If you use the "top center" , even on narrow screen, the bunny face will be shown (but the right/left side of it will not)
If you use the "top left" , on narrow screens, only the text will be shown.
If you use "center bottom" the feet will always be shown, but on small devices (and landscapes) the head will not.





3. This css does not make your div as big as the screen, this is your job.  I won't get into it , but only for pure testing, try min-height: -large-number-like-1800px;


Full width but small-height header/middle-page image, common in bootstrap templates.

see above, just one change: reduce the height of your div to be what ever you like.


User image by itself, sometimes with circle around it


If your div and your user-image aspect-ratio are the same (200x200 against 100x100 image source or 500x500 image-source.  this is trivial (use either contain or cover).
If your div is a square and the user-image is not, you can use 'cover' and then choose the right top/bottom/center right/left/center,  to catch the user face. in the bunny above top-center is best, but it will still show the text on the left and some of the belly.
Lot of sites allow the user to choose an crop a square.  When the user is doing it you can actually crop the image and generate a new one.
Making it circle is as easy as adding:  border-radius:50% 50% 50% 50%;
Note:  Make sure, again, that the image size is BIGGER than the div size. cover will not work otherwise.






Thoughts on mobile app prototyping

I`ll discuss two questions

  1. Why it is so hard to create good cross-platform mobile app.
  2. Why it is hard to take the leap from prototype to real app, without re-coding.

Why it is so hard to create good cross-platform mobile app.


All the solutions for cross-platform apps try to use pre-exiting technology for cross-platform development. The most popular is Html5.  The next one is Xamarin (C#).
Sadly this solution is sub-par, as app development uses 3 "modules", and sadly, most don`t cover them.

  • The Programming language itself(Object-C , iOS)
  • The controllers and layout library (buttons, input-text, time-picker, page-transitions, menu-drawers)
  • System libraries like browsing-contacts, changing-contact-ringtome, play-music, take-a-picture

It will be clearer, we we go over the current solution:
Html5 + Cordova/phone-gap


  • Programming language is Java-script. Code will run on an internal-browser( WebView) [good]
  • Controllers and layout use Html/Css based , as desktop controllers/layout don`t work well out-of-the-box there are libraries which re-implement them like Ionic, Jquerymobile, but both don`t cover all the components, for example: date-time-picker is missing (mobi-scroll can cover this for a price), map location is bad . page transitions are slow. [bad- clearly sub-par components ]
  • Cordova create native-code wrappers around some of the system-libraries, and you can write new ones, but it actually means that for non-trivial things, you will have to write quite the code yourself.
C#/Xamarin
  • Programming language is C#. On Android is is run in an interperter, on iOS compiled to native code.
  • The controllers and layout are Xamarin`s . They are not exactly like native, and sometimes look bad (time-pciker android version as an example). transitions look good, as performance is better.
  • Again, native-code wrappers, with limited system-library usage. The wrappers here are better, and usually expose more details than the js version, but still not all are exposed.
Corona labs (used for mobile games
  • Programming lanaguge is C++ (natively supported) or internal scripts
  • There is no real need to controlelrs/layout, so they are not really supported. Games UI is different.
  • Limited Native code wrappers


Is there another way?
Currently no, but let`s discuss an "invented" one.  Assuming there is a close-correlation between the controllers and the layout of iOS and Android, can't we define it in one language ('xml') and compile it to the other languages?
Can't we write code in one langauge (simplified java/js like, with only if,loops and no special stuff) and generate java/object-code from it?
System libraries are pain, is there a way around them?





App Prototyping using appery.io . Which shortcuts work and which do not


appery.io had a great idea. Let`s make the next Wix/Webydo, but for apps.
Their solution tries to cover (almost) all aspects of app development, but it is lacking in many of them.

  • The app itself is based of JQueryMobile.  It contain a really great UI Editor (drag&drop components with properties editor) and a simple way to add events to it.
    This is a great feature, and it works fine for small apps prototyping.  
    • Problem:  JQueryMobile has it`s limits and although you can use Cordova, there are many things which are pain/impossible to do , like using native Facebook login intent.
    • Problem: Once you get to a bit more complex things, which is not part of the well defined components, it becomes messier.
  • Great tool (similar to curl) to test REST services, and to visually map properties from the REST result to the UI properties. This works very well, for most of the REST calls, as most services result JSON is  quite simple.
  • Built-in database, exposing REST api.  This one similar (maybe equal) to MongoDB.
  • Server code:  Most apps will require extra code on the server. You can write a hosted REST service quite easily (using js code) and schedule it.
  • Simple testing (on the browser) and exporting to .apk/iOS.
See a cool sample here.

Let`s prototype an app together. It will be "kickstarter" for events.
UI:
  • login&user-profile
  • create new event
  • search events and get event list
  • event details & add-me-to-event
  • push-notifications on kick-started event


Create event:
  • Input text for event-image-url (assuming the user knows how to click copy-image-url in the browser).
  • open-text for event data.
  • time-picker for start time. Date and time
  • event-type radio-buttons (sport / lecture /food)
  • "save event" button.
not MVP: add option to upload file from the phone and save it to appery.io FileAPI.
allowed age range (20-30). allowed gender (5 men, 5 women ... or any-gender)

Implementation issues:
  • There is a JQueryMobile date-picker , but not time (hour/min) picker. The forum recommends mobiscroll.com (195$ for few controllers). For now, I used open text.
  • During development, I added new columns to the database, after it was already created. Sadly the database-service does not get refreshed automatically and you have to re-create it (maybe to add parameters manually, didn`t try)
  • Create-service need to map the date+hour input fields into one date db field. This required custom js.
    //look at the date-format, currently it is yy-mm-dd , we convert to yyyy-mm-dd
    return "20"+ value + " "+Apperyio("hour").val();




Login&Profile screen. In the upper part: "Login to facebook" button.
  • In the lower part, the user image (taken directly from facebook profile picture) , a text which can be edited by the user, and the user age.  gender/age. will be taken from facebook
Search event request: choose location in a text box (like , 5th street, SF, California), the box by default will show device location.
event-type radio-button
Search event response: a list of events (image, text, date), for each one,
  •  a status: Open/Full 
  • combo-box for GOING/Maybe/NO 
  • a list of profiles which actually going/maybe.
Push notifications when an event had been kick-started, with the phone number of the event creator


  • TBD...............My events:  a list of the events the user created, clicking on one allows to edit it (the image and text)

The limitations:
Facebook login will not use the native-facebook app which exists on the device and will instead use a rather ugly facebook web page. This is pure ugly stuff.
(this is not appery.io limitation, but any js based implementation. PhoneGap does not fully covers this either)

Abstractions problems (tedious things you still need to do)
Android generate certificate





















Implementing a chat. It is not easy as it sounds...


Chat.  One of the most basic modules in any social app/site, but it still costs you. alot.

Requirements
Let`s go over the requirements of my typical 1on1 chat:
  • The user can have multiple 1x1 chats in parallel. He can see a list of the open chats, and see which chats have unread messages.
  • If it`s an app, a push notification to tell me someone is trying to reach me can be nice.
  • Every chat has history, I want to see, at least, the last 100 messages.
  • Low latency for new chat
  • Presence is optional (mark user as online/offline)
Client-Server protocol
There are two technologies to discuss here.
First, should we use custom chat messages and custom server code for message-format, presence keep-alive, user unique-id, or should we use the well known XMPP protocol (used by lots of IM, like google talk).  Using this known protocol, we can find well tested servers (like ejabberd) which implement it.
Second. what push/poll technology to use?
  • Regular Polling - to achieve low latency we will need to poll each 10 seconds, even if there is no update. This is a bit of a waste.
    Long Polling (also called Comet/Hanging Get) - the client calls a Get and the server will not respond until an update is ready, even if it will "wait on it" for an hour. This trick allows to have a one directional simulated "push" from the server to the client.
    WebSockets - open a bi-directional, always open, socket between the server and the client.  Not all browsers support it yet. The major unsupported version is Android prior to 4.4, this is still quite big market. And (TBD:verify) I heard it may work not as great on mobile, when switching network.

Implementation 

There are many ways to solve this. Let me discuss my solution, which is good for small apps/prototypes. In the appendix, I will describe few more, which can scale better.As my current back-end is based on Parse.com, we will use for the chat-history DB.  As Parse does not have realtime support (no long-polling or web-sockets), we will use a different back-end provider, quickblox, for realtime chat.

The data model:
The trivial one, is storing each message in a log-like table (from, to , time, message,opened-flag) and on query, read the last X(=100) message, and on the client-code combine them into Y(=15) chat conversations and mark those still not-opened.
This is the standard "SQL" way, let`s think about the "Non-SQL" / "Document" way. Another problem here is that X might need to be very large.

One option:

Using quickblox:
Integrate with quickblox users (you can use external users, as long as you saved the user id outside).
On signup/login, login with the same user&password to all platforms. Save in each platform, the user-id in the other platform ,for example use Parse id in Quickblox user.externalUserID, and vice versa.  If you already have some users, change the login code to sing-up quickblox and then login.


Use the chat api 2.0 , when current user P1 wants to communicate to P2 (parse-users-id), retrieve the curent user quickblox id (B1) on the current-user, and query P2 for it`s external B2 id.

Online/Offline - if you want to see the online state of users, you can use the roster chat option. You register for all the users you are intrested in the client (for example current 10 friends) and will get updates in realtime.
Note that this is a very resource intensive action. If a user roster contains 20 friends, although no chat messages is done, you still get updates. A less real-time option will be to use your server to see the states, and let the user query this once in few minutes. 


Other options...

Implement it using Google App Engine Channels (Comet/hanging GET).  Pricing

WebSockets - there are node.js open source implementations, 
or use (Still in alpha) Google App Engine has two option,  the  WebSocket-server on ManagedVM 

You can use a BaaS which provide chat or realtime-data services. This is usually free at first, but costly in large-scale. Generally a good option for rapid-development, for example: Firebase, Pusher (no history), Layer (no js.. coming soon)


Friday, November 27, 2015

Project time estimates and Murphy's law


As we saw in the last few iterations, Murphy's law: "Anything that can go wrong, will go wrong" tend to be 
very strong resident in our midst.

Let's take a client-server short-project as an example. When you ask the client developer how much time will it take he answers 10 hours of uninterrupted work.
Usually a developer will interact with the world and his team mates (eat-lunch, do code-review, attend a meeting) , so let's count this as 2 days.


Now let's go to Murphy

client-code:
    1. Complexity in library-code:  You thought the default 1 row of code will do the work for you but it turns out it does not support your use-case, or t fails unexpectadly only in your input/
    2. Complexity in code: changing one element caused an unexpected bug in another unrelated component.
    3. Infrastructure failures:  your machine/network/server- can be down for few hours.
    4. computer/network/coruppted-int server can take 0-5 hours to overrcome
    5. Product requirements may slightly change when they see your finished feature. They don't ask for a new feature, they just explaining you what they ment before better.
UI related code:
    1. UI/Art integration may not be flawless, depending on your workflow
    2. Sometimes, you can't use the Art "as is" and it is not apparent until you actually try.
client-server potential issues:
    1. Miss-understanding of the API usage, can take some time to debug and understand.
    2. Sometimes it is not a miss-understanding, but a plain bug in the server-code.
    3. Sometimes it's not a bug,but a miss-configuration / not latest-version of code etc

So, there are at least 10 potential risks. What should be the estimate in this case?

One approach is to look at the optimistic scenario and say 2 days. It will sometimes work, but a lot of the time will fail poorly.

Second, opposite approach is to look at the worst case scenario and assume all the problems will happen simultaneously. This approach will say let's estimate 8 days.  One might say "better safe than sorry" and if it will be faster, the developer will say he is done.
A third approach is to aim to be correct most of the time (80-90%) but assuming that some problems might happen , but not all of them at the same week. 
Someone, on the upper-management has to fully understand this, and to manage the risk accordingly.
If you actually want numbers.  Let's say this is an example of (a-low) risk-matrix for the 2 days task. No real human think of this in this manner, but you do have "hunches" about it. In this case, I include a 0.1 chance fo r 2 extra-days due to bad-library behavior. 0.2 extra-day if sever-code does not work etc.

risk0.10.20.050.10.20.1
extra-day2.0015113

The probability of failure for this risks is:
46% - 0 late
71% - up to 1d late
83% - up to 2d late
90% - up to 3d late
94% - up to 4d late
97% - up to 5d late
98.7% up to 6d late
99.1% up to 7d late
99.8% up to 8d late (remember it's on a 2d task....)


Now let's talk about who takes the buffer.  
Let's say a developer gives the matrix to his manager, and ask the manager to tell him how to estimate the task.  What should the manager answer?
Due to Parkinsons's law "work expands so as to fill the time available for its completion", a reasonable manager should do three things.: 
  • Ask the developer to be 80% right, and in this case to add 2d to the estimate : 4d. Tell him that is is ok and fully expected to finish a day early, and they if all hell break loose, the manager got his back with few extra days.
  • Keep a mangment buffer for the next 17% (3 more days) which can be used by the developer, and will be totally ok to use, if the developer explained that the risk actually happened.
    One buffer pool can sometimes be shared amongst multiple team members.
  • Inform his managment about the chances.  If it's a live-or-die scenario, they may have their own buffer on the extra 3% risk.

























Sunday, March 8, 2015

Just few random notes on Parse and Mobile FileUpload


FileUpload on mobile

 <input type="file" accept="image/*">
Android (Chrome and 4.4 native) provides a reasonable, but not-pretty, interface.

If you want to use camera, add the capture camera option. Note that it will not allow other images.


Parse.com allows to upload the file and query it by URL. It`s very simple, but note that it means an image access counts as an API call, and as images usually come in packs, this can cost your quota.

Detect change on textarea

Use $('#textAreaId#).on('change',function() { do something here });
change will be called when the focus is changed and any of the inside-text change.

Parse model update

On many views, you will want to first refresh the view from a saved DB element, and then on edit update(re-save) the element and refresh the view again.
For this pattern, always keep a cached parse object which was returned from the DB and is connected to parse via the row-id.
On refresh, update the cached-element, if found in the DB.
On edit either re-save (on the cached one) if it already exists, or save a new one and create cache.

You can save multiple objects via Parse.Object.saveAll (array)



Parse queries
When querying a pointer, sadly, you can't just pass an instance of a previously returned item (item itself != item pointer). You have to create a pointer object. 
var pointerToUser = {  __type: "Pointer",  className: "_User",       objectId: myUserItem.id };

You can combine multiple queries using Query.or(q1, q2)

Parse weird save/query results

  • Parse will not fail if you query a db class which do not exist at all. Beware of Parse.Object.extend("SpellingMistakeWillNotBeNoticed");
  • It will also allow you to save db columns which do not exist at all. Beware of (item.set('spellingMistake',666).

Tuesday, February 3, 2015

Register/login



Jeff Atwood wrote a great post on creating the simplest login page. Read it!

Let`s use JQueryMobile for the widgests and Parse for the backed.
Insert this html to the JQueryMobile page:

<h3>Login/Register</h3>
<label for="usrnm" class="ui-hidden-accessible">Email:</label>
<input type="text" name="user" id="loginEmail" placeholder="Email">
<label for="pswd" class="ui-hidden-accessible">Password:</label>
<input type="password" data-inline="true" name="passw" id="loginPassword" placeholder="Password">
<input type="submit" data-inline="true" onclick="myForgotPassword();" value="reset pass"> 
<label id="loginMessage" style="color:red"></label>
<input type="submit" data-inline="true" onclick="myLogin();"       value="Log in">
<input type="submit" data-inline="true" onclick="myRegister();"    value="Create new account">


Use JQuery to extract user values and fill login message ($("#input_id".val() , or $(#message_id").text("new text")
We will use Parse user.signUp , Parse.User.logIn and Parse.User.requestUserPassword methods for the backend.



function myRegister() {
    console.log("myRegister");
    $('#loginMessage').text(""); //clean
    var email = $('#loginEmail').val();
    var password= $('#loginPassword').val();
    
    var user= new Parse.User();
    user.set("username",email);
    user.set("email" , email);
    user.set("password", password);    

    user.signUp(null, {
       success: function(user)  {
           console.log("register success");
           $('#loginMessage').text("success");
       },
       error: function(user,error) {
           console.log("register failed "+ error.code +" " +error.message );
           $('#loginMessage').text("failed "+error.message);
       }
       
    });
}

function myLogin() {
    console.log("myLogin");
    $('#loginMessage').text(""); //clean
    var email = $('#loginEmail').val();
    var password= $('#loginPassword').val();
    Parse.User.logIn(email, password, {
       success: function(user)  {
           $('#loginMessage').text("login success");
       },
       error: function(user,error) {
           $('#loginMessage').text("login failed "+error.message);
       }
    });
    
}

function myForgotPassword() {
    console.log("myLogin");
    var email = $('#loginEmail').val();
    
    Parse.User.requestPasswordReset(email , {
       success: function() {
           $('#loginMessage').text("password reset sent");
       },
       error: function(error) {
           $('#loginMessage').text("failed to reset password "+ error.message);
       }
    });
}