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.