Monday, September 9, 2019

The Smalltalk IDE I wish would exist

When I was using Smalltalk in a daily basis I had the chance to understand quite well the things that would make productivity go high. Here are some sketches I’ve done. I didn’t do the debugger and the package manager system, and both of them have great impact on this but hopefully you can imagine how productive this could be.
All collapsed by default.
A bottom bar opens with focus on the input ready to evaluate anything or open common tools in one click or key combination.
The classic time-proven Class Hierarchy Browser has two major changes: 1. it exposes a maximised hierarchy so abstractions can be visually inferred and exploration encouraged and 2. it has a permanently exposed input to a case-insensitive search that will help the user to frictionlessly jump to classes and method names.
Everything can be clean again.
Floating windows with snippets that can spawn from the main expression input at the lower-left. Floating windows are important because they allow drag-grop operations between them. On the top of the code pane, the Class Hyerarchy Browser should have exposed a couple of buttons (no more than 4 to 6) with commands that should follow a cache strategy. They should be the absolutely most basic and frequently used commands, like remove method, find senders, find implementors, versions and perhaps not anything else (unless we have data that proves is a hot cache hit).


Run brew cleanup and claim some disk space

The starting point was to do a scan with OmniDiskSweeper.
OmniDiskSweeper's User Interface allows you to easily navigate the directories that are occupying space the most so you can investigate what in those big directories is actually useful and what can be archived.
Beside the directories that was just fine to delete, my findings allowed me to see which ones was okay to archive to a big external disk. At the end of that scrutiny freeing the Trash freed up ~50GB which was a nice bunch :)
And then I saw Cellar occupying a lot and I've found that I had 6 versions of MongoDB. I only use the latest stable and I have no reason to keep the older ones.
So, if you like me, use brew and don't need to keep older versions of the installed applications and libraries, then doing a cleanup in brew is really handy.
For me today was ~5GB handy :)
Run brew cleanup -n to see which packages would be removed, and when you feel ready hit it with a brew cleanup


Controller expression evaluation on render with Angular

This is a really common need that AngularJS is not providing out of the box.
I needed it myself for some projects and you might too?
Ok, even if many will tell you that you should not program in a way that needs to use this feature, I beleive that there is plenty of people that knows exactly what they are doing. There is plenty of cases that have real and justified reasons to use this feature and they can use it properly. In short, when adequate this do not necessarily implies bad design.
So here we go.
What I'm using to get expressions evaluated after the render is a custom directive named, you guessed, afterRender:
define(['angular'], function (angular) {
  'use strict';
  return angular.module('app.common.after-render', [])
    .directive('afterRender', [ function() {
    var def = {
        restrict : 'A', 
        terminal : true,
        transclude : false,
        link : function(scope, element, attrs) {
            if (attrs) { scope.$eval(attrs.afterRender) }
            scope.$emit('onAfterRender')
        }
    };
    return def;
    }]);
});
Transclusion doesn't make sense here, so we set it false and is restricted to 'A' because, to be useful, what we want is to add this into any controller's template by adding it as an attribute like this:
which will make the controller owning that piece of template able to observe the event onAfterRender fired by this directive and react with arbitrary code of its own.
Here is an example of such controller's initialize method would look like:
$scope.initialize = function () {
    // Makes this controller to have some default initial state and 
    // wires the reactions that belong to its concern.

    $scope.$on('onAfterRender', function (){ $scope.thatGuyJustRendered()});

};

// Reacts doing this and that after that guy had rendered
$scope.thatGuyJustRendered = function () {
    console.log('yep, cool, this computes after that guy had rendered');
};

// ... other controller's methods ...

$scope.initialize();
Bonus There is a bonus. But! this is powerful so it comes with a disclaimenr: this is something not to be abused. I do not endorse bloating the views (templates) with logic because that's something that concerns the controller.
Said that, here is how you'd use it to run an arbitrary expression:
You can put there where you see the $emit any expression you want but you should know that in all my real-world code using the after-render, I only use it to trigger specific events like in that example and program the reaction in the right controller that is wired up with reactions so it knows what to do.
I hope you find it useful and let me know if you need help with it or have any remarks about it

Pharo image shutdown after an OS signal

Sometimes you need to control how a worker image starts and stops right from the operative system. You my do it from the terminal but the really important use for this comes with automation and orchestration.
In airflowing, the Pharo worker images start and stop automatically and on command from the OS and in other to shutdown, the images use the technique I'm describing here.
To do thins you need 3 things:
  1. A VM process listening to the TERM signal
  2. A helper object to hold that VM process
  3. A reaction to handle that signal
The helper object usually instantiates on image start and holds a VM process running in the lowest priority. On start it will listen for the TERM signal:
Helper>>makeStopHook

    "Answers the process that hooks to the 
    OS signal that makes this worker to shutdown
    when the VM process receives a TERM signal from
    the OS."

    ^ [|semaphore|
        semaphore := OSProcess accessor forwardSigTerm.
        semaphore wait.
        self onTerminationSignal] 
            forkAt: Processor systemBackgroundPriority 
            named: 'Image TERM'.
Then you need to implement the reaction to handle that OS signal, and since you probably want a clean shutdown without preserving state, you can use:
Helper>>onTerminationSignal
    "The process for the VM of this image 
    has received a TERM signal from the OS.
    React accordingly"

    self log: 'That''s all folks. This worker is shutting down. Bye bye...' level:#messages.
    OSProcess accessor restoreSigTerm.
    SmalltalkImage current snapshot: false andQuit: true.
Bonus Here is what you do to stop the VM process on that image so you can do a clean exit on any services it might be providing:
Helper>>stopSignalProcesses
    self isOnUnixLikeOS ifFalse:[^nil].
    self log: 'Stopping stop hook...' level:#messages.
    stopHook ifNotNil: [|value|
            value := stopHook.
            stopHook := nil.
            OSProcess accessor restoreSigTerm.
            value].


Improving the Amber Experience

There are many things we can do to have an Amber Smalltalk IDE that makes the difference in terms of developing experience and productivity. The best ones take a lot of effort that is currently unfunded. Maybe we should start a Kickstart campaign and change that. But in the meantime why not do smaller steps in the right direction? We could do small incremental improvements with what we already have.
So for now, let’s take a look at the current IDEs: Helios and Legacy IDE.
Why I don’t like Helios?
First of all, is totally okay to like Helios and I personally liked that Nicolas tried to innovate on the Smalltalk IDE design. I’ve talked with him many times about it and I’ve helped to implement it with some contributions in the inspector and workspace. Innovation on the Smalltalk IDE it’s not something trivial because the traditional designs are extremely well validated and pass the test of time.
Still, there is room to innovate the Smalltalk IDE and truth is that even I have already some drafts on what a rockstar Smalltalk IDE would be. I’m validating its design with some inner-circle veteran developers before any disclosing or deciding to do anything beyond some UX/UI drafts.
The thing is I’ve tried hard with Helios and it really didn’t work for me. You could say that is a matter of preference on developing taste for stateful User Interfaces, like “are you a vi person or a non-vi person?”
But is not.
With time I’ve got some muscular training on getting the right key combinations and end up doing things apparently fast. It wasn’t. The deal-breaker for me was a pragmatic test on plain old productivity.
Helios takes too much time to pop-up and open and hides some actions behind a wall of sequenced keystrokes while the classic IDE provides an instant embedded open and is more “mouse friendly.”
In the end, Economics decided for me. Yes, Helios could connect to a remote environment but (a) that does not happen today and (b) might never do because the development of that feature, sadly, is not moving forward. The day to day result is that Helios made me overall less productive and slower than using the good old Legacy IDE.
Hence the divorce.
So after moving away from it I’ve started to see new things and try to figure out new possibilities and I’ve come to the personal conclusion that for the goal of having a more productive and overall better User Experience developing with Amber, it would take significantly less effort to make the Legacy IDE way better than Helios way better.
I am the only one perceiving this?
How do you use Amber to code? Here is a poll I’m running to understand this question better.
I hope this doesn’t sound rhetorical because this is a genuine question I have. I can easily just fork and do the incremental adjustments I want to see done on the classic IDE or, I can bother myself in trying to amplify those benefits for the whole community. And I don’t know what to do yet.
What do you think? Should I try to promote this Legacy IDE improvements and fixes in the official Amber repo or just fork? Please help this spread and leave a comment with your preference so our community can find it and know.
Here is the issue I’ve tentatively opened: https://github.com/amber-smalltalk/amber-attic/issues/3
Stating these problems as a start:
  • Typography issues
  • Poor contrast issues
  • Focus issues
  • Lack of search keyboard shortcut
  • Tab close area too small
  • SUnit button alignment
  • Horizontal arrow keys should change the pane in focus (on Browser and SUnit)
  • Vertical arrow keys should change the selected list item when focus is in a list pane
  • Save button disabled on pristine
  • Class browse shortcut
  • Icons on the class list
  • Icons on the package list
  • Drag and drop to categorise methods
  • Marking changed packages
  • Visual feedback on successful commit finished
  • Visual feedback on failed commit (handle exception and display proper message)
  • Select and change theme easily and persist the preference on localStorage
  • Change theme to be dark by default


Debugging Announcement issues in Amber Smalltalk

And while developing, is normal to rename a class.
Today I've was working with a product and I had this announcement class with a typo OrdedProductEditRejected which I've renamed to OrderedProductEditRejected.
None of the current Amber IDE's have a refactoring tool to help you to rename globally and changing the methods that are using the class, so you have to go old school and rename in every place yourself.
So far so good. Until you forget to rename it in one method and your app uses that.
What happens in the method using the old name, is that you get nil there and the announcer will throw an exception (nil does not understand #name).
Trying to find references of the class doesn't work anymore because it already has the new name. And if you forgot the exact previous name, the search for references will not help.
So what do you do!?
In flow based applications, the App class implements on:do: in this way:
App>>on: ann do: aBlock

  self announcer on: ann do: aBlock
So every time your code subscribes to observe an event it will send that message. Knowing that, you can debug this kind of problem by setting a halt so when the announcement class is nil it stops and you know what to fix.
This is how it looks:
App>>on: ann do: aBlock

  ann ifNil: [ self halt ].

  self announcer on: ann do: aBlock
With that, you use your application and when it halts, you'll see in the debugger's stack the sender you forgot to correct.


Accepting vs. Selective

Keeping the engines running, understandably, demands attention and energy into maintaining the statu quo. A defence of the current state.
Things that go under the hood, the engines that keeps things moving reliably and performing well, they usually demand tighter error margins in all its parts. The people that takes care of the engine need to be selective and rigorous to keep the system producing value.
Backends’ internal parts comes to mind.
Think DevOps. Think about DBA's and sysadmins and all the backend’s gatekeepers curating its reliability. In a strike of rigour, they will happily pospone progress and innovation if things doesn't fit. The profile here is being conservative to only allow what preserves the system’s current production of value.
Now let’s see things from the other side.
In order to create better User Experiences you usually need to go in the exact opposite direction.
A more accepting User Interface is a less rigorous and less selective interface. In other words, an interface that can be used by a more diverse audience. One that is usable by many people with many different forms to see and experience the world.
Finding one, can, in theory, happen by accident or in semi-random attempts, but it's more interesting to think in what could happen if you have a bunch of folks intentionally pursuing that goal. What if they do that systematically?
They can raise the chances of getting there just because believing that they can makes them to pay more attention to detect when they have produced something that resonates with a wider audience.
If they find the thing that works for more people, those guys go from naĂ¯ve experimenters to startup founders to change makers to hight-impact entrepreneurs.
The Lean Startup method is trying to help on that.
Any product they will try to build, will intentionally be closer to the Robustness Principle.
In computing, the robustness principle, or Postel’s Law, is a general design guideline for software:
Be conservative in what you do, be liberal in what you accept from others (often reworded as “Be conservative in what you send, be liberal in what you accept”).
This is really hard to do because it points the self-criticism (rigor) to oneself and intentionally deescalates the rigor and demands on others. This is usually the exact opposite of what the forces of the Ego ask you to do. The Ego will distract you from that because is basically a self-serving endpoint that neutralises network value creation.
And here is the strategic opportunity:
Because is really hard to do, most people is simply not even willing to try so there is way less competition in that direction.
Because being more accepting and generous to others usually connects people (and that raises the value of the network).
Because is easier to distribute a product in a market if you know how to seduce it and generosity is the right start for that goal.
The Separation of Concerns between frontend and backend allows specialists to do their bests in each domain negotiating a sweet spot in this spectrum of tension between being more accepting vs. more selective.
Fullstack developers resolves this as inner-conflicts.
And the way to level up the value for everybody in anything being made, is by constantly exposing the big picture so those specialists don’t get lost in micro-compartmentalized details that might easily diverge from a better future. When the specialists converge into something meaningful they can do something that people can believe in. When they are doing the thing, they can drive their energy inspiration and passion to it, instead of maintaining the statu quo by just doing the job.

Flow demoed at Smalltalks2014

 In November 5, 6 and 7th I was at Smalltalks2014 where I presented a talk about Startups and Smalltalk that mentions flow.
I want to say a thanks to the organizers for having me there to bring this topic that gave me the opportunity to share this information among many Smalltalk enthusiasts, but also because I met new friends and found some old ones.
One common theme I've found: I had many great and deep conversations with lots of them. There is something fundamental that is interesting about this technology that seems to make people to be really conscious and thoughtful.
Special thanks to Esteban Maringolo for being a great roommate and pal; to Facundo Vozzi for having big laughs and teaching me about new beers; to Boris Shingarov for deep technical talks about Cathedral's organs and going from the Plank Scale to the Cosmos in half second; to Andrés Valloud for being that pre-adolescent friend sharing games in floppy disks in the 90's rediscovered twenty years later presenting the notion of "the kid's play is the man's work"; to Peter Hatch for amazing deep chats and World Conquer plans and talking about George Carlin!; to Allen and Rebeca Wirsf-Brock for great long chats and being part of this Smalltalk invention and making JavaScript better; to Juan Vuletich for helping to figure out "what should be maximized?" when using Metcalfe's Law and to James Foster that so kindly showing me a fantastic way to work with Gemstone/S.
Thank you guys!!!
As you can see in the slides of the talk, one of the topics is Single Page Applications and flow is actually quite on topic about that. At the end of the day, it was the "Show your projects" section and I demoed flow in about 10 minutes.
It was nicely received and the video of that might actually get published eventually. I'll share it as soon as I have news on that. One thing that is worth mentioning is that, with Esteban Maringolo, we're actually thinking making a Mapless adaptor to Postgres and with the fantastic work of Sebastian Hiedbrink we had a pre-alpha of flow in Gemstone/S.
Can you feel the power?
Excited?
We are!
Here are some photos
Peter Hatch giving his talk about Virtual Machines, Critical Thinking and Reliability
Andrés Valloud and me "twenty years later"
Thanks to Esteban Maringolo for noticing that FAST has its own Chris Anderson in HernĂ¡n Wilkinson from 10Pines. You almost can notice how he is mesmerized by NicolĂ¡s Papagna's TED-style talk☺
From left to right: Esteban Maringolo, Jannik Laval, Sebastian Sastre, Adam Jacques, Prof. John Sarkela, Josh Fridstorm, Kurt Kilpela and

Controller based title change with Angular

Here is a tip on how to keep nice titles in your AngularJS-based SPA - Single Page Application.
The strategy is this:
  1. Remember current title (whatever it might be)
  2. Set the title to whatever new value you want
  3. Observe when the controller gets destroyed and
  4. React restoring that previous value in the title
controllers.controller('AmazingDetailController', [
    '$scope',
    '$window',
    function ($scope, $window){

      // Sets this controller with the expected initial state
      // and perform any other initial activity needed
      $scope.initialize = function () {

         // Remember the previous title (whatever it might be)
         $scope.previousTitle = $window.document.title;

         $window.document.title = 'Amazing Detail!';

         // Observes $destroy to restore the title of the page to its original
         // value once user navigates out of this controller
         $scope.$on('$destroy', function() {
           $window.document.title = $scope.previousTitle;
         });
      };


      // Does specific behavior 1

      // Does specific behavior 2

      // ...

      // Does specific behavior N


      $scope.initialize();
    }]);
A realistic use will probably be use a model that is coming from a service from the backend (or cache) or collaborating with other objects somehow. But this strategy is still valid, clean and works like a charm.
Enjoy and let me know how it goes for you!

Controller based title change in Angular

Here is a tip on how to keep nice titles in your AngularJS-based SPA - Single Page Application.
The strategy is this:
Remember current title (whatever it might be) Set the title to whatever new value you want Observe when the controller gets destroyed and React restoring that previous value in the title
controllers.controller('AmazingDetailController', [
    '$scope',
    '$window',
    function ($scope, $window){

      // Sets this controller with the expected initial state
      // and perform any other initial activity needed
      $scope.initialize = function () {

         // Remember the previous title (whatever it might be)
         $scope.previousTitle = $window.document.title;

         $window.document.title = 'Amazing Detail!';

         // Observes $destroy to restore the title of the page to its original
         // value once user navigates out of this controller
         $scope.$on('$destroy', function() {
           $window.document.title = $scope.previousTitle;
         });
      };


      // Does specific behavior 1

      // Does specific behavior 2

      // ...

      // Does specific behavior N


      $scope.initialize();
    }]);
A realistic use will probably be use a model that is coming from a service from the backend (or cache) or collaborating with other objects somehow. But this strategy is still valid, clean and works like a charm.
Enjoy and let me know how it goes for you!


App, main and other controller accessors

When I've started flow, one of the features I wanted for it was scaffolding from the front-end and be able to do things like:
Flow scaffold model: #User
or:
Flow scaffold crudFor: #Task
and have created the Model and Controller classes and accessors in environment so you can continue developing the app pulling things from there.
There are several reasons to have scaffolding features, the utilitarian and most pragmatic reason is that it helps you to show something useful fast. A cheap positive feedback loop that allows you to scaffold the next basic feature of your app. That's something really aligned with flow's mission regarding to productivity.
A secondary good reason is that scaffolding makes it easier to spread basic good practices. It shows by example to new people how to get new models and controllers in an application that can scale in complexity with elegance and high maintainability.
But I'm not implementing scaffolding just yet.
The reason why is not being done yet is because we are still in discovery mode of what are those practices. The idea is to really confirm if they are common, general and frequent enough.
In this article, I'm going to share the current best candidates for those good practices. If I'd have to implement the scaffolding system today, I'd make it build the App and its main controller, the main controller accessors, models and router and here I'd show you how. Also we'll cover here what's the suggested convention to name things and why is convenient to do it that way.
App and main Since version 0.2.7, a flow-based application has the idea of App and main. A default clone of the flow repo will use the App class and MainController class for a sample tutorial-like application.
The App class is a convenient starting point to access and "talk with your app" whatever app it is. In flow we asume you'll have to investigate things on your app and its controllers so we are trying to make that easy for you. One way is providing easy navigation. Here is how you access the main controller of your application which is the root of the controller's graph. "Used by index.html to start your app."
App start.
"Deals with routes definition and is part of the starting process of your frontend." App setupRouter.
"Accessor to the instance of MainController of your app." App main.
Take the last one for example, it's 2 words, one of 3 characters the other has 4. Really friendly to type. Amber doesn't have autocomplete so by choosing two short words, we are lowering the friction to access the root controller of your application so you can easily inspect, send commands and see how it reacts. Is safe to say it will be used a lot so you'll profit a lot. For example, an inspect on that code allows you to navigate to any controller that got currently instantiated. That makes easy diagnose possible issues and prototype live-coding the next feature.
The MainController should have as minimum two methods: #home and #reset. You should be able to do:
"Get to the default state on the main controller." App main reset.
"Answers the 'home' controller of the app." App main home.
Here is code that implements the #reset method taken from a real application: MainController>>reset
self navbar deactivateAll.
self hideAllBut: #navbar.
self home show
That reset method makes the app to instantly show the home without any blinks on the screen.
Accessors Now take a look at the #home accessor
MainController>>home "Answers the home controller of the app. Creates it lazily if needed." ^ self ifAbsentAt: #home put: [ HomeController for: model on: self appendingTo: ‘#home-wrapper’ asJQuery ]
So by just naming it with App home, you get it created. Once created, you get that instance as answer every time. That's as close as you can be to zero friction between developer's wish and reality (machine's answer). Just the way things should be. Note we are using here the class method to instantiate controllers: #for:on:appendingTo:
Controller class>>for: aModel on: aParentControllerOrNil appendingTo: aHtmlElement “Answers a new instance of this controller dedicated to aModel, child of aParentControllerOrNil and meant to be appended to aHtmlElement.” ^ self new model: aModel; parent: aParentControllerOrNil; parentElement: aHtmlElement; yourself
Lets take a look at what it expects:
  • In the for: part it expects the model for the new controller
  • In the on: part it expects the parent controller, a MainController in this case.
Note that the parent controller has sense to be nil only when you instantiate the MainController which is a controller that is the root of the whole graph of controllers.
In the appendingTo: part it expects a DOM element to be the parent element of whatever that new controller needs to render. Typically that would be a
with an id named consistently with the controller class name plus the 'wrapper' suffix as you see in that snippet. The tutorial sample application of a default flow clone has 5 subcontrollers covering from the most basic template based controllers to two-way data binding, composition and client-server RESTful interactions. On its MainController you find 5 accessors: example1, example2, etc. up to example5. They all use the same idea of this #home accessor.
Models
Models in flow are really friendly. Creating the class is enough to start using them. They are Mapless objects which means you don't really need to declare in advance what instVars and accessors they need to have in order to be usable by your application. This makes really easy to work in a prototypical way encouraging discovery and experimentation, two really strategic features for innovation projects and startups. Any subclass of Model you add is going to be a Mapless. So basically you only care about the model name and add all your model classes. Later you add the methods that makes them to have special behaviour. As general rule, Mapless don't need setters and getters, they use DNU to get and set automatically whatever you tell them to. They will answer nil when you ask for something they don't have. In the following snippet we create an instance of the Visitor class, we set the language according to the browser and we save it in the backend:
"Create a model of the visitor, set its current language and saves it in the backend." | visitor | visitor := Visitor new. visitor language: window navigator language. visitor save. This feature of DNU and returning nil makes them a bit different if you want to have lazy initializations on some of their properties. How does it look a lazy initialization in a mapless? Here is another example taken from real code: Order>>products "Answers the products in this order. Creates the empty collection if needed." super products ifNil: [ self products: OrderedCollection new ].
^ super products
Routes
Lets dig now on the routing system used in flow applications. It all begins at load time. When the frontend is being loaded by your browser using RequireJS, it comes to a moment where it installs the 'App' package containing the App class and all the other classes and methods of your application.
When Amber installs classes on the package loading process, the classes will receive the initialize message on its class side. If there is none, nothing special will happen but if your class implements it, it will perform those custom actions.
In flow, we use this:
App class>>initialize self setupRouter
So even before he application starts, it already will have the router programmed to react correctly to whatever your app should do with the given initial and following URIs.
Lets see the setupRouter now:
App class>>setupRouter "Program the application reactions for different URI routes." Router rlite "Normalization of the home route." add: ‘’ do: [ :r | Router set: ‘#/home’ ]; add: ‘#’ do: [ :r | Router set: ‘#/home’ ]; add: ‘#/’ do: [ :r | Router set: ‘#/home’ ]; add: ‘/’ do: [ :r | Router set: ‘#/home’ ]; add: ‘home’ do: [ :r | App main reset ]; "Reactions related to Contact models" add: ‘contacts’ do: [ :r | App main showContacts ]; add: ‘contacts/:id’ do: [ :r | Router set: ‘#/contacts/’,r params id,’/view’ ]; add: ‘contacts/new’ do: [ :r | App main showNewContact ]; add: ‘contacts/:id/view’ do: [ :r | App main showContactId: r params id ]; add: ‘contacts/:id/edit’ do: [ :r | App main editContactId: r params id ]; add: ‘products’ do: [ :r | App main showProducts ]; add: ‘products/:id’ do: [ :r | Router set: ‘#/products/’,r params id,’/view’ ]; add: ‘products/:id/view’ do: [ :r | App main showProductId: r params id ]; add: ‘search/:target’ do: [ :r | App main showSearchResultsFor: r params target ]; yourself
At this point you'll see that the code is quite self explanatory which is one of the guiding principles behind flow. In the same way this example uses #showNewContact, #showContactId: and editContactId: you would do different routes for different models on your own application. Bonus As a bonus, here is how #editContactId: looks like:
MainController>>editContactId: anId self hideAllBut: #navbar. self contactEditor editId: anId
The editor accessor that you already can infer:
MainController>>contactEditor
^ self ifAbsentAt: #contactEditor put: [ ContactEditorController on: self appendingTo: ‘#contact-editor-wrapper’ asJQuery ]
The #editId: on the editor controller taking the model from the backend:
ContactEditorController>>editId: anId
self showPreloader. Person findOne: #{ ‘_id’ -> anId } then: [ :person | self editContact: person. self hidePreloader ] ifNone: [ ] onError: [ :res | self showError ]
And finally:
ContactEditorController>>editContact: aPerson
self model: aPerson. self show done: [ "specific stuff" ]
The #show method in Controller always return a promise so you can do your own custom stuff when the view gets created asynchronously without complicating your code. So we don't have yet scaffolding today (January 2015) but I hope this article encourages you to write highly readable code on flow.
Happy coding!

flow

I’m starting this blog here to make a coder-friendly open conversation with contributors and enthusiasts about flow’s design.
This blog will be doing two things in one move:
  1. A source of fresh input, so feedback, so inspiration.
  2. An output about progress on this line of work, so relevance of the mission.
But lets back up a bit, what is flow after all?
I like to say that flow is a mission with a framework.
Here is flow’s mission from the project’s readme:
flow’s mission is to provide consultants, startups and software houses with a competitive Smalltalk full-stack framework that allows them to quickly deliver a demo with all the modern html5 features the market expects today (2014). The idea is that they can tactically use this framework to keep momentum up among their prospects and clients and scale things to full successful projects delivered by kickass productive teams or individuals.
Why Smalltalk you might ask? Is a great question that should be experienced more than described, but if I have to tell you only three things about it, they will be around flow the psychological phenomenon embedded into the principles of design of Smalltalk itself and I particularly want to highlight that they help with:
*Intuition Instant feedback (discovery) Personal mastery *
Does that resonate in you? I encourage you to join this effort!
It’s all open source, MIT License, and the project's Kanban is being organized in this open board you can join here. By the way, I had the chance to presented flow at CampSmalltalkVI2014, big thanks to Sebastian Heidbrink for the hard work of organizing it and the invite!
There is no video about the talk but here are some slides I’ve made for it:
flow: a living full-stack ‎framework for the web
~900 views in a couple of days, and many shares? That’s a nice signal that we might just be into something here Beside a nice quantity of views on those slides what I like is the offline reception of the project and how people reacts to it during the few pairing session I had showing it. People is asking for the petshop sample app already!
I have concrete needs of my own with the framework, mostly being pulled by my clients and projects. That's great because is validated needs that will eventually cascade features to the framework. So all that is expected to be a major drive of course.
At the same time I'm interested in innovation in general and how talented individuals and teams deal with innovation for their needs so I’m curious about how would you push this mission forward. I see this blog like a good opportunity to ask design questions and talk about it.
In the next posts I'll write about the current technical challenges and hopefully you might have good ideas to share on how to face them best.
I'd like to expose things so people can understand why flow is a curated project and how it's being done.
But before digging ourselves into tech stuff too soon, let me ask you…
What do you think about the mission?
How would you use it?
If not, what stops you in using it? What bumps or showstoppers have you found?
Have your clients asked you to do Single Page Applications for them?

The way you understood it wrong

When I was doing engineering, I had a very good algebra teacher.* Those where the days full of vectors and subspaces and subspaces of polynomials and matrices and subspaces of matrices of polynomials.
All from 7 a.m to 12 p.m.
In the middle of that math trench he said once something that my head really saved.
The teacher was explaining yet another concept while the sky was still dark in the morning and there was this guy that asked him to clarify a detail.
The question was asked and the teacher clarified.
He was a good teacher so, before moving on, he asked to this student if the idea was now understood.
He wanted this student validation.
The guy said ‘yes’ and right away this student started to describe all sorts of details about how he was reaching to the wrong conclusions by following an alternative reasoning based on the wrong assumptions he had while not having clear what he later asked about.
The teacher stopped him saying something I've never forgot:
No, no, wait, wait. Please do not explain me how you understood it wrong. Tell me instead how you're going to remember it right.

Update: together with my good friend Pablo Dobrusin we joined efforts and figured out who the teacher was, he was Fernando Acero at FIUBA - Facultad de IngenierĂ­a Universidad de Buenos Aires.
Timeless insight.
Hats off to teachers like that.


Context is King

When you trust your content is when you can forget it. At that point you’ll get that Context is King.
…to make a Leonardo you need more than his innate ability. You also need Florence in 1450. Paul Graham.
Yes I know… we are not da Vinci, we don’t have Florence in 1450 nor we have a Medici patron for our talent.
Florence in 1450 is context. The problem is that without an appropriate context talent is useless. To be fair, not useless but seriously compromised. That’s why talented people want to run away from places that are hostile to their talent and, the opposite of that problem: knowing how to build appropriated contexts will cultivate talent and open you more doors than working on the content. The good part: today is simpler and cheaper to build desirable contexts so wealth creation can find its way to be deployed in the world.
Some examples:
  • A blank sheet of paper, something to write and a pleasant ambiance.
  • Your laptop + WiFi in an inspiring coffehouse.
  • To be able to write about high culture in a conversational tone.
  • A great story for you blog or, way better, book chapter.
  • When the world gives you the present of a synchronicity or a serendipity.
  • Your sketching tools and your favorite music in the background.
  • Finding the layout that works.
  • Your design when it has your rules and honors the basic principles at the same time.
  • To fit that image in the rule of thirds. And the right light and shadows!
  • When you make your model feeling natural and engaged during the shots.
  • Your camera and accessories in an historical moment.
  • To be able to capture technically well without being distracted by technical stuff.
  • When you can make your actors to inspire one to each other when filming.
  • Your musical instrument and a couple of friends.
  • To relax before an audition confident on your practices.
  • The visual finalization details of your site.
  • The usability of your application.
  • The ambiance you were able to architect.
  • A customer has a problem you can help with.
  • The results created by your movement before asking for donations.
  • To say “hello” with a sincere smile.
  • To listen your interlocutor’s problem.
  • To ask the right question.
  • When you renew the inspiration and hope of a member of your community.
  • Your intervention adding momentum to a project.
Because context is dynamic in nature, it can be very brief. When you get one that works take advantage of it putting all the momentum in the substance and commit to the truth. If you do that you can be sure you will be closer to some valuable things:
The identity of what you provide will be faithful to what you are.
Your talents will have a better chance to shine over their opposite keeping what you don’t like in you at a safe distance. When something you don't like comes up, the feedback will be more useful because is the right input on the right problem, which leads to good diagnosis and good reviews and solutions.
Ultimately this is useful because all the contexts you manage to build are the real signature of your consciusness and you can be familiar with it while, unfortunately, most people don’t even know they have one.
Originally published in July 7, 2009. Reviewed in November 17, 2017