Yesterday I walked into the Burlington Mall's Apple Store and tried out the iPad for the first time. (I have decided to buy the new iPhone 4 rather than an iPad and so the impulse to have one has waned.) It was much smaller than I expected but this does make it more book-bag friendly. I was very impressed with its speed especially compared to my iPhone 3G. I really wanted it to have a cover. The screen just screams at you "Please take care of me! I am going to be scratched." I don't want a sleeve: Where would I put it when it is not in use? I want a cover that works something like a triptych that folds flat into the back of the iPad or can be folded for use as a stand.
I have been thinking about interface design for the iPhone and iPad for a while now. I have been working through ideas with the design of an issue tracking application as this is a tool I will use every day. (I am a software developer, after all.) I am greatly inspired by Mag+ design. It is such a deep source of ideas. The Mag+ magazine is virtually laid out in a very strong 2d space: The horizontal is used to hold the articles side by side and the vertical is used to hold the article's content. This is a very easy visual model to internalize and it can be used for lots of different kinds of content with strong peer relationships and long content. I had assumed that Apple had this idea too. You see it in their photograph applications, but I was wrong. When reviewing the iPad's email application I was shocked that I could not swipe to view the next or the previous email. This was such a natural gesture that I assumed I did something wrong. As far as I can tell, I did not. Afterwards I realized that I can't swipe horizontally with the iPhone either.
The A Future of Information Interfaces for Emergency Management
* big displays with three-heads being common
* virtual whiteboard+touch screen that shows the distant participant as if on the other side of the device.
* pie menus are finally (!) showing their strengths in a touch-screen world.
* more direct touch interaction with specialized virtualized controls.
* heads-up display on the truck's windshield.
MonoTouch and Apple's Section 3.3.1: Two Theories
I do believe that Mono has meaning for developers. Everytime I listen to the Mono folks I hear them saying the right things. Here is another one of the right things:
MonoTouch and Apple's Section 3.3.1: Two Theories
"[...] MonoTouch has been misrepresented, initially by Gruber and by most people covering the debate over section 3.3.1. Probably because few of them have actually used MonoTouch or because they are not familiar with .NET. Probably folks think that MonoTouch is .NET, and .NET is Microsoft's Java and draw their own conclusions.
MonoTouch brings the C# language and the core of .NET to the iPhone, but does nothing to provide a cross-platform UI experience or for that matter any sort of mobile device cross-platform APIs.
We bring the C# language, garbage collection, a type safe system that help reduce errors, make programmers happier and more productive on the iPhone while getting access to every single iPhoneOS API that they want to.
We have also been able to expose new APIs that Apple has exposed in record time thanks to the fact that we are not really an abstraction layer over the iPhoneOS, but merely a compiler that talks to the native APIs. [...]"
MonoTouch and Apple's Section 3.3.1: Two Theories
"[...] MonoTouch has been misrepresented, initially by Gruber and by most people covering the debate over section 3.3.1. Probably because few of them have actually used MonoTouch or because they are not familiar with .NET. Probably folks think that MonoTouch is .NET, and .NET is Microsoft's Java and draw their own conclusions.
MonoTouch brings the C# language and the core of .NET to the iPhone, but does nothing to provide a cross-platform UI experience or for that matter any sort of mobile device cross-platform APIs.
We bring the C# language, garbage collection, a type safe system that help reduce errors, make programmers happier and more productive on the iPhone while getting access to every single iPhoneOS API that they want to.
We have also been able to expose new APIs that Apple has exposed in record time thanks to the fact that we are not really an abstraction layer over the iPhoneOS, but merely a compiler that talks to the native APIs. [...]"
JConsole and JMXMP
For the record, if you want to use jconsole with an MBean server using JMXMP you need to run it using
Other incantations just don't work. Define JAVA_HOME, JAVA_LOCAL_LIBS, JMXMP_HOST and JMXMP_PORT appropriately. Now, back to work.
java \ -classpath $JAVA_HOME/lib/jconsole.jar:$JAVA_LOCAL_LIBS/jmxremote_optional.jar \ sun.tools.jconsole.JConsole \ "service:jmx:jmxmp://$JMXMP_HOST:$JMXMP_PORT"
Other incantations just don't work. Define JAVA_HOME, JAVA_LOCAL_LIBS, JMXMP_HOST and JMXMP_PORT appropriately. Now, back to work.
Network activity records and the common good
The record of activities of users of Google, Facebook, Twitter, etc have enormous use in the service of the common good [1]. Google shows us how searching on flu and flu related terms bests the CDC's reportage on outbreaks by two weeks. Facebook's shear population size and its tools for instant affinity groups sees people helping people under good and adverse circumstances. And lack of Twitter activity is the same warning signal grasshoppers give [2]. The upshot of this is that in our current networked world these private institutions need to start making this activity record public.
At one time most decent roadways were private enterprises. They supported commerce and so tolls were used to support them. At some point, roads were seen as too valuable to be held in private hands and government took over the task of building and maintaining decent roadways. The same story can be told about potable water. But why did this not happen to the electric grid or the telephone infrastructure? I don't have an answer today but I do want to find out. I think the answer will lead to a better understanding as to our rights as citizens to having the activity records available for the common good.
[1] http://en.wikipedia.org/wiki/Common_good
[2] The Origins of Knowledge and Imagination. Jacob Bronowski. http://bit.ly/akd0gR
At one time most decent roadways were private enterprises. They supported commerce and so tolls were used to support them. At some point, roads were seen as too valuable to be held in private hands and government took over the task of building and maintaining decent roadways. The same story can be told about potable water. But why did this not happen to the electric grid or the telephone infrastructure? I don't have an answer today but I do want to find out. I think the answer will lead to a better understanding as to our rights as citizens to having the activity records available for the common good.
[1] http://en.wikipedia.org/wiki/Common_good
[2] The Origins of Knowledge and Imagination. Jacob Bronowski. http://bit.ly/akd0gR
Varanasi has an almost perfect web site
Varanasi, http://www.varanasi-indian.com/, has an almost perfect restaurant web site. Just one page containing the menu, hours of operation, and location. And one page that works with a mobile browsers as well as a desktop browsers. No Flash. No extra navigation. No big pictures. No complex layout. It was a pleasure to use.
The food, by the way, is fantastic. I really enjoyed the Punjabi Eggplant with spice level 4.
Ranks and snap lines in Instaviz
A Graphviz features is the abilty to align nodes using "ranks" [1]. Does Instaviz [2] offer a means of using ranks? If not, I imagine a means of dragging a node to "snap" to one of several equidistant lines drawn on the canvas. In this way, the user is able to specify some node organization and still allow Instaviz to automatically layout the graph as a whole. (I think it is reasonable to limit the snap lines to be in one direction only per graph.)
[1] http://www.graphviz.org/pdf/dotguide.pdf
[2] http://itunes.apple.com/us/app/instaviz/id299022481?mt=8
UpdateFor example, I want a graph to have have three ranks: The first rank contains the nodes A, C, and E; The second contains B, D, F; And the third contains X. Without ranks the following definition
digraph rankexample {
A -> B -> X;
C -> D -> X;
E -> F -> X;
C -> X;
X -> C;
}
Creates this graph:
However, adding ranks (i.e. the "snap lines") to the definition
digraph rankexample {
{ rank = same; A; C; E; }
{ rank = same; B; D; F; }
{ rank = same; X; }
A -> B -> X;
C -> D -> X;
E -> F -> X;
C -> X;
X -> C;
}
I get the layout I was looking for:
Addressing the needs of individual and groups with predictability
There has been some good observations of failures to help customers affected by Iceland's volcano eruption. David Weinberger's blog has a typical posting http://www.hyperorg.com/blogger/2010/04/18/volcano-1-internet-0-01/. I think the roots to this problem are that money and effort is being spent on
1. style over substance, and
2. individual-casting over broad-casting.
The style over substance argument is very easy to see. Every travel website that I have used obscures the process's workflow (and the broader information architecture) with abusive Web 2.0 techniques. Most of these techniques require an inordinate number of communications between the browser and the server. The upshot is that under moderate load the website fails to respond with predictable timing. Without this predictability customers are greatly frustrated and this leads them to use a telephone where they can at least know what their predicted wait time is!
The casting issue is more difficult to see. There are more casting groups then just "me" and "everyone else". Depending on your service, customers can be group into multiple and overlaps groups. For example, specific airport groups, country groups, traveling with children groups, etc. Each of these groups have common and unique information and advice needs in times of emergency (and times of calm!). The general public group is, generally, the most useless group unless there is system-wide failure. Without addressing the needs of affinity groups you are not truly servicing the needs of your customers.
The upshot is, let's spend less money and effort on individual-casting with technical acrobatics and instead balance the money and effort on addressing the needs of individual and groups with predictability.
This posting was inspired by Mark Bernstein's posting http://www.markbernstein.org/Apr10/InternetFailure.html
1. style over substance, and
2. individual-casting over broad-casting.
The style over substance argument is very easy to see. Every travel website that I have used obscures the process's workflow (and the broader information architecture) with abusive Web 2.0 techniques. Most of these techniques require an inordinate number of communications between the browser and the server. The upshot is that under moderate load the website fails to respond with predictable timing. Without this predictability customers are greatly frustrated and this leads them to use a telephone where they can at least know what their predicted wait time is!
The casting issue is more difficult to see. There are more casting groups then just "me" and "everyone else". Depending on your service, customers can be group into multiple and overlaps groups. For example, specific airport groups, country groups, traveling with children groups, etc. Each of these groups have common and unique information and advice needs in times of emergency (and times of calm!). The general public group is, generally, the most useless group unless there is system-wide failure. Without addressing the needs of affinity groups you are not truly servicing the needs of your customers.
The upshot is, let's spend less money and effort on individual-casting with technical acrobatics and instead balance the money and effort on addressing the needs of individual and groups with predictability.
This posting was inspired by Mark Bernstein's posting http://www.markbernstein.org/Apr10/InternetFailure.html
Always include a telephone number
Whenever you find yourself typing or saying "call me" ALWAYS include a telephone number. It it only 7 numbers locally and 10 nationally. Obviously, this is a pet peeve of mine.
Tomcat, JMX and working at the local library
When working within a restricted IP network -- like those found at libraries, cafes, and other hot-spots -- make sure you run services on 127.0.0.1 and not "localhost". This will ensure that all network services you are working with -- and, in my case, developing for -- do not need to access the restricted network. For Tomcat 5.5.x you will need to edit ./conf/server.xml and add the attribute "address="127.0.0.1" to each <Connector> element. For example,
<Connector address="127.0.0.1" port="8080" redirectPort="8443" minSpareThreads="25" connectionTimeout="20000" maxSpareThreads="75" maxThreads="150"> </Connector><Connector address="127.0.0.1" port="8009" redirectPort="8443" protocol="AJP/1.3"> </Connector>
Atul Gawande: The Checklist Manifesto | Free Lecture | Forum Network from PBS and NPR
Brilliant man. Well worth listening to.
Looking for webapp suitable for community garden hub
I am looking for a webapp that combines
* Wiki
* Issue Tracking
* CRM
All of these can be -- and, perhaps, should be -- feature-light. This will be used by members of a community garden. Anyone know of a turn-key solution for this?
Using a proxy & reflection to access a JMX Standard MBean
A current project uses JMX to monitor the application. Using JMX's Standard MBeans makes publishing an application's health, for example, very easy. This is the "server" side of the story. The "client" side of the story is not so satisfying. The JMX API is designed to support a highly dynamic management environment. To this end, the API uses an indirect access to the data. The client uses textual, untyped descriptors to get, set, and invoke methods on mbeans. Unless you are building a general purpose client this leads to lots of code and mental overhead. For example, if this is your Standard MBean
To use the isHappy() method requires the code
If you are using Standard MBeans to publish data it would be great for your client to also use the Standard MBean to access the data. For example,
To this end, below is a little set of helper classes that use Java's reflection and proxy facilities to do just this. The first code we need is an invocation handler that will send attribute and invocation mbean requests between the proxy and the mbean server:
And now we need a factory (or perhaps just a static creator method somewhere) to tie together the Standard MBean interface, the MBeanClient helper, and the proxy:
Now, connect the client and create the proxy
Post script: Here is how to connect to a JMX server running on localhost at port 9999 using RMI:
public interface HugsMBean { boolean isHappy(); int getHugs(); void addHugs( int hugCount ); }
To use the isHappy() method requires the code
MBeanServerConnection mbeanServerConnection = ... ObjectName happyMBeanName = new ObjectName( "com.andrewgilmartin.hugs:name=hugs"); Boolean isHappy = (Boolean) mbeanServerConnection.invoke( happyMBeanName, "isHappy", null, null ); if ( isHappy ) { ... }
If you are using Standard MBeans to publish data it would be great for your client to also use the Standard MBean to access the data. For example,
MBeanServerConnection mbeanServerConnection = ... HugsMBean hugs = ... // i.e. associate with com.andrewgilmartin.hugs:name=hugs if ( hugs.isHappy() ) { ... }
To this end, below is a little set of helper classes that use Java's reflection and proxy facilities to do just this. The first code we need is an invocation handler that will send attribute and invocation mbean requests between the proxy and the mbean server:
package com.andrewgilmartin.common.management; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import javax.management.Attribute; import javax.management.JMException; import javax.management.MBeanServerConnection; import javax.management.ObjectName; public class MBeanClient implements InvocationHandler { private MBeanServerConnection mbeanServerConnection; private ObjectName mbeanName; public MBeanClient( MBeanServerConnection mbeanServerConnection, String mbeanName ) throws JMException { this.mbeanServerConnection = mbeanServerConnection; this.mbeanName = new ObjectName( mbeanName ); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ( method.getName().startsWith("get") && method.getParameterTypes().length == 0) { String attributeName = method.getName().substring(3); return mbeanServerConnection.getAttribute( mbeanName, attributeName); } else if ( method.getName().startsWith("set") && method.getParameterTypes().length == 1) { String attributeName = method.getName().substring(3); Attribute attribute = new Attribute( attributeName, args[0] ); mbeanServerConnection.setAttribute(mbeanName, attribute); return null; } else { return mbeanServerConnection.invoke(mbeanName, method.getName(), args, null); } } }
And now we need a factory (or perhaps just a static creator method somewhere) to tie together the Standard MBean interface, the MBeanClient helper, and the proxy:
package com.andrewgilmartin.common.management; import java.lang.reflect.Proxy; import javax.management.JMException; import javax.management.MBeanServerConnection; public class MBeanClientFactory { private MBeanServerConnection mbeanServerConnection; public MBeanClientFactory( MBeanServerConnection mbeanServerConnection ) { this.mbeanServerConnection = mbeanServerConnection; } publicT create( String objectName, Class... mbeanInterfaces ) throws JMException { T mbeanClient = (T) Proxy.newProxyInstance( this.getClass().getClassLoader(), mbeanInterfaces, new MBeanClient( mbeanServerConnection, objectName ) ); return mbeanClient; } }
Now, connect the client and create the proxy
// connect to the mbean server
MBeanServerConnection mbeanServerConnection = ... // create the mbean client factory
MBeanClientFactory clientFactory = new MBeanClientFactory(mbeanServerConnection); // create the mbean client for the server's mbean
HugsMBean hugs = clientFactory.create("com.andrewgilmartin.hugs:name=hugs",HugsMBean.class); // use the mbean client while ( ! hugs.isHappy() ) { hugs.addHugs( 27 ); } System.out.println( "happy with " + hugs.getHugs() + " hugs");
Post script: Here is how to connect to a JMX server running on localhost at port 9999 using RMI:
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi"); JMXConnector jmxc = JMXConnectorFactory.connect(url, null); MBeanServerConnection mbeanServerConnection = jmxc.getMBeanServerConnection();
A vi command line helper
A great command line file editing helper is to combine find and vi so that you can skip specifying paths. For example, the command
vif IndexerTool.javaeffectively is the same command line as
vi ./java/org/crossref/qs/citationdocument/index/IndexerTool.java(for a current project.) The script is
#!/bin/bashYou can use wild cards too. For example, this will edit ALL your java files
[ -z "$1" ] || vi $(find . -name $1 -type f)
vif \*.java
Blogger and Twitter link
This tip is a reworking of the tip given in Blogger Buster: 16 Useful Twitter Tools for Blogger Add a simple "Tweet This" link. Since Blogger's links can be long, the code uses bit.ly to shorten the link. The code to use is
somewhere within the DIV element
Replace YOUR-TWITTER-USERNAME with your Twitter user name. See the original tip for more details.
<!-- TWITTER -->
<a expr:href='"http://bit.ly/?u=" + data:post.url + "&s=" + data:post.title + " (via @YOUR-TWITTER-USERNAME)"' target='_new' title='Tweet via bit.ly'>Tweet This</a>
somewhere within the DIV element
<div class='post-footer-line post-footer-line-1'>
Replace YOUR-TWITTER-USERNAME with your Twitter user name. See the original tip for more details.
Blogger and conditional widgets
Quick note that to make a widget/gadget conditional in Blogger you need to edit the template's HTML and add a <b:if cond='... tag. For example, the following makes the given HTML widget only display on the index page (the main page).
This can be useful if you want some introductory content to be displayed to the viewers of the home page but not to viewers of of the specific posting pages.
Also, a new feature of Blogger is "Pages". Pages are named postings that can be listed and accessed by direct links. There is also a widget for showing the pages as a list or as tabs.
<b:widget id='HTML1' locked='false' title='' type='HTML'>
<b:includable id='main'>
<b:if cond='data:blog.pageType == "index"'>
<!-- only display title if it's non-empty -->
<b:if cond='data:title != ""'>
<h2 class='title'><data:title/></h2>
</b:if>
<div class='widget-content'>
<data:content/>
</div>
<b:include name='quickedit'/>
</b:if>
</b:includable>
</b:widget>
This can be useful if you want some introductory content to be displayed to the viewers of the home page but not to viewers of of the specific posting pages.
Also, a new feature of Blogger is "Pages". Pages are named postings that can be listed and accessed by direct links. There is also a widget for showing the pages as a list or as tabs.
Shell enhancement to round-robin through list of directories
When working at the command line (Unix mostly) I am often working with files in several directories at once. The pushd and popd commands are useful but require a strict stacked directory use and require too much planning for me to use efficiently. (Clearly, self actualization has reached a new level of specificity.) What would be better would be a way to change directories by rotating through a list of directories. Much as is done today with applications vis Cmd-Tab under Mac OS X and Alt-Tab under Windows. Configuring the list of directories should be via a hot-key. The hot-key should work not only when in the current working directory but also when using filename completion. Often, the directories I want to return to are discovered during filename completion. So, one hot-key is used to add and remove directories from the list and another hot-key to change directories to the next directory in the list.
Re: What the iPad Means for the Future of Computing
Comment regards Wired's What the iPad Means for the Future of Computing:
What the iPhone did (and iPad will do) is to bring back sanity to interface design. For decades UI vendors — Microsoft, Apple, HP, Sun, etc — brought to tool/application front-end development well considered and consistent structural and visual interface elements. The tool’s new users needed only to learn how these elements were applied to the business function to use the tool. The value of this UI work was, some how, lost during the rise of the web.
The other element of the iPhone’s success is single user focus. The iPhone becomes the tool/application in use. User multi-tasking is not a requirement to productivity. Switcher was one of Apple’s greatest productivity successes. It was ahead of its time and ahead of the capabilities of the hardware. The hardware in the iPhone and the iPad make switching to another application fast and into the same context you were when you left.
What the iPhone did (and iPad will do) is to bring back sanity to interface design. For decades UI vendors — Microsoft, Apple, HP, Sun, etc — brought to tool/application front-end development well considered and consistent structural and visual interface elements. The tool’s new users needed only to learn how these elements were applied to the business function to use the tool. The value of this UI work was, some how, lost during the rise of the web.
The other element of the iPhone’s success is single user focus. The iPhone becomes the tool/application in use. User multi-tasking is not a requirement to productivity. Switcher was one of Apple’s greatest productivity successes. It was ahead of its time and ahead of the capabilities of the hardware. The hardware in the iPhone and the iPad make switching to another application fast and into the same context you were when you left.
Subscribe to:
Posts (Atom)