Music, Shares

salada de frutas – para ti

do álbum SEM AÇÚCAR, de 1980 – letra de Lena dAgua, música de José da Ponte

anoiteceu, meu amor o dia desceu no mar
escrevo o teu nome na areia, o tempo parou por instantes
vagueavas sozinho na praia
juntei-me a ti, mergulhei no teu silêncio mágico
lentamente

anoiteceu, meu amor, pressinto-te perto
corro descalça por ti, a lua poisou-te nos olhos
e soltei os cavalos do vento, demos as mãos
caminhámos num abraço eterno
tão ao longe

encontrei-te no mar, percorri-te de cor
nos teus braços de amor adormeci
embarquei no milagre que há em ti
perdi-me contigo no silêncio do cais

amanheceu, meu amor
por dentro nasceu o sol
sobes por mim devagar, procuras o céu no meu corpo
num sorriso os teus olhos encontram nos meus
mais uma estrela que se acendeu
em ti deslizo mansamente

Quotes, Shares

Karl Popper’s Abstract Society

From Karl Popper’s “The Open Society and Its Enemies”. Are we abstract yet?

“As a consequence of its loss of organic character, an open society may become, by degrees, what I should like to term an ‘abstract society’. It may, to a considerable extent, lose the character of a concrete or real group of men, or of a system of such real groups. This point which has been rarely understood may be explained by way of an exaggeration. We could conceive of a society in which men practically never meet face to face — in which all business is conducted by individuals in isolation who communicate by typed letters or by telegrams, and who go about in closed motor-cars. (Artificial insemination would allow even propagation without a personal element.) Such a fictitious society might be called a ‘completely abstract or depersonalized society’. Now the interesting point is that our modern society resembles in many of its aspects such a completely abstract society. Although we do not always drive alone in closed motor cars (but meet face to face thousands of men walking past us in the street) the result is very nearly the same as if we did — we do not establish as a rule any personal relation with our fellow-pedestrians. Similarly, membership of a trade union may mean no more than the possession of a membership card and the payment of a contribution to an unknown secretary. There are many people living in a modern society who have no, or extremely few, intimate personal contacts, who live in anonymity and isolation, and consequently in unhappiness. For although society has become abstract, the biological make-up of man has not changed much; men have social needs which they cannot satisfy in an abstract society.”

It’s 2021, is it still an exaggeration?

Links, Shares

No, We Won’t Have a Video Call for That!

Just read this article. A written version of a talk by Florian Haas about

  • What modes we have available for communications in teams;
  • Why distributed teams always collaborate asynchronously, and what communication modes lend themselves to that particularly well;
  • Why written communication is so important in distributed teams;
  • And why meetings (like video calls) are a mode of communication that effective distributed teams hardly ever need to use — except for very specific reasons.

My favorite part was this 5-paragraph format for briefing people.


Whenever you need to thoroughly brief a group of people on an important matter, consider using a 5-paragraph format.

  1. Situation
  2. Mission
  3. Execution
  4. Logistics
  5. Command and Signal

Let’s break these down in a little detail:

  1. Situation is about what position we’re in, and why we set out to do what we want to do. You can break this down into three sub-points, like the customer’s situation, the situation of your own company, any extra help that is available, and the current market.
  2. Objective is what we want to achieve.
  3. Plan is how we want to achieve it.
  4. Logistics is about what budget and resources are available, and how they are used.
  5. Communications is about how you’ll be coordinating among yourselves and with others in order to achieve your goal.
Longs, Original

Cake.Console 1.2.0

After a bit of work, I have found Cake.Console stable enough for a first release. I decided to version it with the same number as Cake itself. If needed I will update the revision number.

Usage

Create a new project referencing Cake.Console. It will look something like this

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <OutputType>exe</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Cake.Console" Version="1.2.0" />
  </ItemGroup>
</Project>

Add a single Program.cs file with the code. Take advantage of top-level statements.

There are 2 ways of using Cake.Console:

  1. Building an IScriptHost. This is the implicit object in the .cake scripts, so we can use it to register tasks, perform setup, etc.
var host = new CakeHostBuilder().BuildHost(args);

host.Setup(() => { do something });
host.Task("TaskName").Does(c => c.Information("Hello"));
host.RunTarget(host.Context.Arguments.GetArgument("target"));
  1. Using the Cake Cli, that includes arguments like –target, –version, –info, –tree, –description, –exclusive…
    It’s very similar to frosting
new CakeHostBuilder()
    .WorkingDirectory<WorkingDirectory>()
    .ContextData<BuildData>()
    .RegisterTasks<CakeTasks>()
    .InstallNugetTool("NuGet.CommandLine", "5.9.1")
    .RunCakeCli(args);

In this case, we dont have access to the host, so we need to define the build with the 4 extensions that come with Cake.Console:

  • WorkingDirectory<>
  • RegisterTasks<>
  • ContextData<>
  • InstallNugetTool

WorkingDirectory<>

Here we can use a class that has the interface IWorkingDirectory and implements the string WorkingDirectory property.

The class can receive in the constructor any part of the cake infrastructure (ICakeContext, ICakeLog, ICakeArguments, ICakeConfiguration…)

RegisterTasks<>

Here we can use a class that has the interface ICakeTasks.

The class can receive in the constructor any part of the cake infrastructure (ICakeContext, ICakeLog, ICakeArguments, ICakeConfiguration…)

All the methods that have the signature void Name(CakeTaskBuilder builder) will be called, and the name of the method will be the name of the task.

ContextData<>

Here we can use any class that will then be available for use in the task’s definitions.

InstallNugetTool

Given a package name and a version, installs a nuget package as a Cake tool

Summary

Putting it all together

using Cake.Common.Diagnostics;
using Cake.Console;
using Cake.Core;

new CakeHostBuilder()
    .WorkingDirectory<WorkingDir>()
    .ContextData<ContextData>()
    .RegisterTasks<CakeTasks>()
    .InstallNugetTool("xunit.runner.console", "2.4.1")
    .RunCakeCli(args);

record WorkingDir(string WorkingDirectory = ".") : IWorkingDirectory;

class ContextData
{
    public string SomeVeryImportantData { get; set; } = "Cake is awesome!";
    public ContextData(ICakeArguments args)
    {
        if (args.HasArgument("tone-down"))
        {
            SomeVeryImportantData = "Cake is pretty good...";
        }
    }
}


class CakeTasks : ICakeTasks
{
    private readonly ICakeContext ctx;

    public CakeTasks(ICakeContext ctx) => this.ctx = ctx;

    public void TaskName(CakeTaskBuilder b) => b
        .Description("Some task")
        .Does(() => ctx.Information("Something"));

    public void AnotherTask(CakeTaskBuilder b) => b
        .IsDependentOn(nameof(TaskName))
        .Does<ContextData>(data => ctx.Information(data.SomeVeryImportantData));
}
Longs, Original

Presenting Cake.Console

I wanted to run Cake inside a console app, without the penalty of pre-processing the .cake DSL, and have the all the power of an IDE (refactorings, find usages,…). I had 2 possibilities:

  1. Cake.Frosting
    This was the best option, but I really didn’t like a couple of things like, the ceremony of writing a class for each task or using attributes for describing tasks instead of the fluent syntax of cake scripts
  2. Cake.Bridge
    This was more in line with what I wanted, but It missed some stuff like tool installing.

So, it was time to roll up my sleeves and get to work. Presenting Cake.Console!

var cake = new CakeHostBuilder(args)
    .InstallNugetTool("xunit.runner.console", "2.4.1")
    .Build();

cake.Task("Hello")
    .Description("This is just like a cake script")
    .IsDependeeOf("World")
    .Does(c => c.Information("but methods are on the 'cake' object"));

cake.Task("World")
    .Does(c => c.Information("Hello world"));

var target = cake.Context.Argument("target", "hello");
cake.RunTarget(target);

It’s a fairly simple project, but I learned a lot about cake’s internals.

Cake has an architecture where every piece of functionality is behind an interface and is injected into objects as needed. Then the registering of interfaces into implementations is defined in “Modules”. There is a ICakeContainerRegistrar Object that can receive registrations. I needed to implement a registrar if I wanted to take advantage of internal implementations of interfaces from Cake. So I did create a CakeContainer that can receive registrations from Cake.Core and Cake.Nuget modules and then create an IServiceProvider that can instantiate the needed parts of cake.

After understanding this part, It’s just a case of wiring some moving parts and I got it to work. The only “hand coded” part was the parsing of commandline arguments, which was done very naively.

What I got was a piece of code that can give me a IScriptHost object, which is the implicit object that is called on .cake scripts when we define Tasks or use Addins.

I still needed one thing, the installation of tools. I then added 2 things, a way to register stuff into the ICakeContainerRegistrar and a special interface IHostBuilderBehaviour that executes a Run() method before returning the IScriptHost, to add functionality into Cake.Console. What I got was a very simple CakeHostBuilder that I can then extend via extension methods.

With all this infrastructure in place I then added 5 extensions that fulfilled all my needs in this project

Installing Tools

I added the interface ICakeToolReference, and the ToolInstallerBehaviour. Created also a CakeNugetTool class to create the correct Url for a nuget package.
Then it’s just a matter of registering ICakeToolReferences into the ICakeContainerRegistrar

Tasks from methods

I added the ICakeTasks interface and the TaskRegisteringBehaviour, which instantiates the ICakeTasks, and calls all the methods that receive a CakeTaskBuilder. This CakeTaskBuilder will already have created the Task with the same name as the method.

Changing WorkingDirectory

Once more I added the IWorkingDirectory interface which has working directory string a and the WorkingDirectoryBehaviour, that converts it to an absolute path and changes the working directory. Useful when your build scripts are not in the same tree as the code itself.

Auto setup context data

The Setup callback on the IScriptHost can return an object that can then be used in the CakeTaskBuilder extensions. This is called a Typed Context. I wanted a typed context that could tap into the internals of cake, so it needed to be registered into the ICakeContainerRegistrar.

Once more I created a SetupContextDataBehaviour, and I’m good to go. I can even register multiple typed context and use the needed one on different tasks.

Run target

I found myself hating that part of the script that reads the “target” from the arguments. It just breaks the fluent vibe from the code! So I extended the CakeHostBuilder to have a Run method that simply reads the target from the arguments and runs it. Putting it all together…

All modesty aside, I really think it is looking great!