Phones, tablets, laptops, desktops – different form factors with different usage styles. Why Apple won’t compromise and merge iOS and MacOS

Following Apple’s announcement of the new MacBook Pro models today and the impressive looking Touch Bar, cnet have a fascinating interview (and timeline of Apple’s laptops from the original PowerBook through to the latest MacBook Pro models) with Senior VP of Marketing Phil Schiller, software engineering lead Craig Federighi and Apple’s Chief Design Officer Jony Ive.

Although the media focus is predominantly on the new Touch Bar, there’s several interesting quotes in the article on why we won’t be seeing a combined or merged OS or hardware device from Apple that combines iPhone/iPad touchscreen functionality with the laptop format of the MacBook product line – Schiller said:

“We did spend a great deal of time looking at this a number of years ago and came to the conclusion that to make the best personal computer, you can’t try to turn MacOS into an iPhone. Conversely, you can’t turn iOS into a Mac…. So each one is best at what they’re meant to be — and we take what makes sense to add from each, but without fundamentally changing them so they’re compromised.”

I’ve agreed with this line of thought for a while, and discussed this last year when Tim Cook said something very similar.

While it might be immediately obvious to some that the way you interact with a smart phone that fits in your hand is a completely different experience to how you interact with a computer while sitting at a desk, Microsoft’s (failed?) attempt at combining both of these usage styles into a single phone device with Continuum that you can use as a phone or plug into a dock and use as a desktop has always seemed to me to be a massive compromise. How you use a phone with a small screen and limited input capability is so completely and radically different from how you interact with a desktop computer with a keyboard, mouse and large LCD screen, why you would even try to combine these two experiences into one device is just beyond me.

Anyway, I’m pleased to heard Apple reiterating on their understanding of how different devices have different capabilities. Until a radical new approach comes along for how you interact with your devices where the reduced physical size of a portable device is no longer a constraining factor, a phone is still best as a phone, and your desktop or laptop is still best as what they do. Even in this “Post-PC” era, there’s still a place for both.

 

Dependency management with npm

A few rough usage notes:

  • npm install module : download and install module. Saves dependency in node_modules by default
  • npm install module –save : saves module info in package.json
  • npm install module -g : downloads and installs module globally, not just in the current dir/project, so can be reused by all projects
  • npm init : creates a new package.json from answers to a few questions, plus any existing downloaded modules in node_modules (useful to recreate package.json if you didn’t install modules with –save initially)

Getting past Vagrant’s “Authentication failure” error when starting up OpenShift Origin

For getting up and running quickly with OpenShift Origin, RedHat have an all-in-one VM image you can provision with Vagrant. The instructions mention to not use Vagrant 1.8.5 as there’s an issue with the SSH setup – since I already had 1.8.5 installed for some other projects, I tried anyway, and ran into issues with SSH’ing into the VM with SSH keys.

When provisioning the VM, you’ll see:

 

Kevins-MacBook-Pro:openshift-origin kev$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'openshift/origin-all-in-one' is up to date...
==> default: Resuming suspended VM...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...

There’s a number of posts discussing this issue and a few workarounds, for example, here and here.

The suggestions relate to switching from the ssh authentication to userid/password, by adding this to your Vagrantfile:

config.ssh.username = "vagrant"
config.ssh.password = "vagrant"

I tried this, and when running vagrant up I had different errors about “SSH authentication failed”. Next I tried adding this recommendation:

 

config.ssh.insert_key = false

This didn’t make any difference initially, but doing a vagrant destroy, and then trying to bring it up again initially ran into the same issue, I Ctrl-C’d out and tried again and then it worked second time. I’m not sure what steps got past the ssh keys issue, but at this point I was up and running. There’s a long discussion in both the linked threads above that describe the cause of the issue, so if you’re interested take a look through those threads.

Building a multi-container Spring Boot and MongoDB webapp with Docker 1.12.x

I’ve spent a bunch of time playing with apps in single containers up until now and reached the point where I started to think about questions like:

“ok, so how is this done if you have an application with multiple services, where you may need to scale individual services but not others?”

and

“how does an app in one container talk to another container?”

Composing applications from multiple containers and handling the scaling I think this is the sweetspot for Kubernetes, but I don’t feel ready to ramp up quite that much just yet. Besides, with Docker 1.12 adding ‘swarm mode’ and with docker-compose, it’s looking like Docker has most of the tools you need to build and scale a multi-container app out of the box without adding additional tools to the stack.

So here’s where I started:

  • Container 1: Spring Boot app with JAX-RS RESTful endpoints
  • Container 2: MongoDB database
  • Container 3: Data volume container for MongoDB

As it turns out, this is doesn’t involve too much additional work than just building Dockerfiles for the individual containers and then wiring them together with a docker-compose.yml file.

Starting with each container, here’s the pretty simple Dockerfiles for each:

Spring Boot container:

FROM java:openjdk-8-alpine
ADD SpringBootAddressBook-0.0.1-SNAPSHOT.jar /opt/SpringBootAddressBook-0.0.1-SNAPSHOT.jar
EXPOSE 8080
ENV MONGODB_DB_NAME addressbook
ENV MONGODB_DB_HOST mongo
ENV MONGODB_DB_PORT 27017
ENTRYPOINT ["java", "-jar", "/opt/SpringBootAddressBook-0.0.1-SNAPSHOT.jar"]

 

MongoDB container:
MongoDB can be run straight from the official dockerfiles on Docker Hub, using one container for the server and one for a data container – see the complete docker-compose file below.

Bringing it all together, here’s the Docker Compose file to orchestrate the containers together:

version: '2'
services:
    mongodata:
        image: mongo:3.2
        volumes:
        - /data/db
        entrypoint: /bin/bash
    mongo:
        image: mongo:3.2
        depends_on: 
            - mongodata
        volumes_from:
            - mongodata
        ports:
        #kh: only specify internal port, not external, so we can scale with docker-compose scale
            - "27017"
    addressbook:
        image: addressbook
        depends_on: 
            - mongo
        environment:
            - MONGODB_DB_NAME=addressbook
        ports:
            - 8080:8080
        links:
            - mongo

At this point, the group of containers can be brought up as a whole with:

docker-compose up

… and brought down with:

docker-compose down

You can individually scale any container with:

docker-compose scale containername=count

…. where count is the number of container instances to spin up.

 

So what if you want to add in a web frontend as a container too? Easy enough. Here’s an AngularJS frontend, served by nginx:

    web:
        image: docker-web-angularjs
        ports:
            - "80"

Now, if we spin up multiple containers for the REST backend and the nginx frontend as well, we need a load balancer as well, right? Also easy, just add in haproxy:

    lb:
        image: dockercloud/haproxy
        depends_on: 
            - addressbook
        environment:
            - STATS_PORT=1936
            - STATS_AUTH="admin:password"
        links:
            - addressbook
            - web
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
        ports:
            - 80:80
            - 1936:1936

I had noticed that the startup order of the containers was not always predictable, and sometimes the Spring Boot container would start before the MongoDB container was up. This can be fixed by adding the depends_on element. I’m not sure if I really needed to add all the dependencies that I did in order to force a very specific startup order, but this seems to work for me. The order I have in the complete docker-compose.yml is (from first to last):

  • mongodata (data container)
  • mongo
  • addressbook (REST backend)
  • web (AngularJS frontend)
  • haproxy

The complete source for the AddressBook backend is available in this project on github. The deploy-* folders contain the individual dockerfiles:

https://github.com/kevinhooke/SpringBootRESTAddressBook