Life Codecs @ NamingCrisis.net

Ruminations. Reflections. Refractions. Code.

Oct 29, 2017 - Software dev Angular WebStorm

Non-Relative Module Imports on Angular 2+ CLI and WebStorm

Problem

I’ve just started exploring Angular 2+ and the Angular CLI. I have custom libraries in my application, and wish to avoid using stupid relative paths like ../../../common/mylib.ts in imports. This post documents what is needed to get both WebStorm (or IDEA) and Angular CLI resolving these paths cleanly.

The project structure is as follows:

// Various files not shown for brevity

 ui (-> ng new ui)
 ├── node_modules/
 ├── package.json
 ├── src
 │   ├── app/*
 │   ├── index.html
 │   ├── main.ts
 │   ├── tsconfig.app.json
 │   └── typings.d.ts
 ├── tsconfig.json
 ├── tslint.json
 └── yarn.lock

Example modules/files of interest:

///
/// ui/src/app/common/illegalargumenterror.model.ts
///
export class IllegalArgumentError extends Error {
  constructor(msg: string) {
    super(msg);
  }
}


///
/// ui/src/app/risk-reward-calculator/risk-reward.model.ts
///
import { IllegalArgumentError } from "@app/common/illegalargumenterror.model";
// Much nicer than
// import { IllegalArgumentError } from "../common/illegalargumenterror.model";
// especially for deeper hierarchies where this noise builds up.


export class RiskRewardItem {
...
  constructor(rewardFactor: Big, entryPrice: Big, stopLossPrice: Big) {
    if (entryPrice.lte(0)) {
      throw new IllegalArgumentError(`Non-positive entry...`);
    }
  }
}

Solution

We are primarily interested in the app module right now, handled by the following files:

  • ui/src/tsconfig.app.json
  • And the common configuration, ui/tsconfig.json; note that the app file extends this common file.

To get custom module resolution working on Angular CLI (including ng serve), we change ui/src/tsconfig.app.json, adding compilerOptions.paths (which relies on compilerOptions.baseUrl — should already be there):

/// ui/src/tsconfig.app.json

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "baseUrl": "./",
    "module": "es2015",
    "types": [],
    // BEGIN
    // Note that the paths are relative to 'baseUrl'
    "paths": {
      "@app/*": ["app/*"]
    }
    // END
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ]
}

WebStorm (as at Release 2017.2), however is only aware of ui/tsconfig.json (see this), and just modifying the above leaves the IDE TypeScript Language Service complaining with an error in the editor, so we also update ui/tsconfig.json.

/// ui/tsconfig.json - note compilerOptions.baseUrl and compilerOptions.paths

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ],
    // BEGIN
    // Note that the paths are relative to 'baseUrl'
    "baseUrl": "./",
    "paths": {
      "@app/*": ["src/app/*"]
    }
    // END
  }
}

You’ll need additional entries for other modules/tests if you require, but the idea is the same.

Limitations

Initially, I found that I could not navigate to the definition of modules imported in this custom manner. Doing a WebStorm Invalidate Caches and Restart seems to have sorted this out.

Unfortunately, refactors (e.g. renames), don’t seem to be propagating cleanly. I’ve tried using both just the TypeScript Language Service, and using IDEA’s compiler.

I’ll update the post if I figure out how to get WebStorm’s key features working with non-relative/custom-resolution imports.

Alternatively, contact me if you find out!

Sep 10, 2017 - Software dev work culture philosophy reflection

On the Wisdom of Waiting

An excerpt from the excellent (as expected, really) write-up, Toward Go 2:

“We did what we always do when there’s a problem without a clear solution: we waited. Waiting gives us more time to add experience and understanding of the problem and also more time to find a good solution”.

The whole thing is a worth a read for its clarity of writing, but I wish to focus on the importance of waiting.

A lot of technical problems are made big deals of without clear evidence of harm. If one can live with something for a while, clarity comes with time. Better solutions present themselves, and often, we get lucky: the problem can actually go away. Well, they did have to fix it in the case of Go above, but my point stands!

I recall an incident early in my career where a problem had been in production for at least a year: the company ‘policy’ was to be more secure by avoiding auto-completion (preventing auto-saved values) on form fields in the browser. Long story short, this is achieved by the autocomplete attribute in HTML forms.

A prior incarnation of the site had this feature enabled, a subsequent upgrade missed it. A tester notices it one afternoon, and suddenly management deliberates till around two in the morning, cozily from their own homes, while us developers were on standby in the office. We fixed it that night, but at an expensive human cost for no evidence of real benefit. It could have waited till the morning, at least. And arguably, saving form fields should be a choice left to the user.

Of course, this applies to life in general, too. A deliberate, active decision to wait is not the same as being complacent. It is being fully aware of the urgency of an issue, and its current lack of clarity. Not knowing, and having the luxury to wait and to defer, is a blessing. When available, gee, take it, don’t fight it!

I have used the word ‘waiting’ because of the excerpt, but taking it further, the value of deliberately taking a time to be in quietude as ways of achieving clarity should now be more… wait for it… clear.

Book plug: over the past couple of years, I have delved a bit more deeply into reflections such as these, and collected them in a book of a spiritual, non-dogmatic nature, Touching Nature. If you like applying life lessons inspired by experiences, you might like the book. I also promise that the book is more soberly edited than my sometimes rambling posts. :-)

Sep 10, 2017 - Software dev work culture

Diversity and Inclusiveness

I came across this insightful article today, and have further thoughts on it.

Diversity comes from people with differing interests, not only those who love to hack late into the night. While there are such ‘flow’ days, 4–5 hours of deep, focussed work generally is more productive and leaves one happier. Being present during a core set of hours is better than half-working through many more hours.

Really liked the example in the article where dress code does not equate to diversity or lack thereof. Though, I personally would have trouble with terribly stringent dress codes! To me it is just another form of assumption: that professionalism is not possible without dressing stringently. Certainly, dressing like a slob is another extreme.

If people are having to work longer because there’s too much work, or the work is not spread out well, that’s a deeper problem, and working longer hours is, at best, a band-aid solution.

We might lose a certain depth by diversifying, but the breadth gained in an overall more inclusive team, internally, and a product reflecting this externally often makes up plenty, and in time, a different sort of depth is gained.

Digressing a bit on working longer hours: besides looming or unrealistic deadlines, the one constant reason, in my experience has been the existence of too much non-core work (e.g. meetings!) taking up most of the day, forcing one to do actual work later in the day.

People in managerial roles who spend most of their day facilitating work through mechanisms like meetings tend to forget that developers still have to actually do the work that came out of meetings. Their day is not yet over.

I said I was digressing, but the lack of understanding by managerial staff of this phenomenon, in a sense, is also a form of accidental non-inclusiveness. It is an assumption that everyone works the same way. The coin has two sides, as usual. :-)

Jul 18, 2017 - Software dev Docker

Hugo with Pygments Docker Container

TL;DR

Derived a Docker-wrapped Hugo with Pygments binary.

Documentation can be found on the github page.

Rivetting Long Story

I recently switched this site over to using Hugo, a static site-generator.

On Debian, even running a mix of testing and unstable, the packages are out of date, even worse, some combination Hugo and Pygments stopped working. Completely the opposite effect of simplifying my writing, argh.

Why yet another container? As the author whose container I forked points out, there are a lot of stale Hugo/Docker containers. Here’s another one that may go stale – but unlikely, while I continue to use Hugo.

May 3, 2017 - Software dev Kotlin

Kotlin Quick Ref: Multiple Constraints/Bounds on Type Parameters

I’ve been using Kotlin the past few weeks, mainly to write JustLogIt!.

I very nearly thought Kotlin was missing a feature that Java has: multiple bounds or constraints on a type parameter. In Java, one can do:

interface A {}
interface B {}

// constrain the type parameter T to be a subtype of both A and B
class Foo<T extends A & B> {}

A feature I occasionally find very useful. The syntax is nowhere near the same for Kotlin, and only a very small example right at the end of the Generics documentation is provided:

https://kotlinlang.org/docs/reference/generics.html

Some discussion around the syntax can be found here:

https://discuss.kotlinlang.org/t/why-the-scattered-generic-types/1917

I had a more involved use-case:

class FragmentCanRequestPermissions<out T>(val fragment: T) :
    CanRequestPermissions, FragmentCompat.OnRequestPermissionsResultCallback
    where T: Fragment, T: FragmentCompat.OnRequestPermissionsResultCallback {
  ...
}

Thus, where defining constraints occurs at the end of other declarations.

Let’s see the more general syntax for when we have multiple type parameters, each having multiple bounds/constraints:

interface A
interface B
interface C
interface D
interface E
interface F

class Meow<ABC, CDE, DE>: A, F
where 
  ABC: A, ABC: B, ABC: C,
  CDE: C, CDE: D, CDE: E,
  DE: D, DE: E
      

In fact, as you might infer, the order of bound declarations does not matter:

class RandomOrderLikeAirportRandomChecks<ABC, CDE, DE>: A, F
where 
  ABC: A, CDE: D, ABC: C,
  DE: E, CDE: C, ABC: B, CDE: E,
  DE: D

// "Random". Yeah. Right.

Yes, I am on a plane.

Mar 18, 2017 - Software dev

Bye, bye Dreamhost

After nearly 10 years of hosting with Dreamhost (including this site) with mostly okay service — it had its bad days! — I decided to migrate everything over to Webfaction (affiliate link) which I have been using since around 2014 for a few things.

In the words of Dreamhost’s billing:

You are not within our 97 day money back guarantee (it has been 3585 days since 2007-05-25)!

Woot!

The following points tipped me over:

  • The ability to deploy long running services (called applications) that run on a port
    • This port can be exposed if needed, though rarely do you want this.
    • Instead you deploy websites whose requests are proxied through to these internal applications. With this, even on a shared host, I can (and do) run a memory-bounded JVM application on Jetty, for example. You can also run high-performing, low-footprint web servers to host your applications, and save memory.
    • Your stock standard static/php/cgi application also exists.
  • PostgreSQL Support by default! Seriously, Dreamhost, it is stupid how you don’t yet have this for shared hosting. Sticking with MyOrac^H^H^H^HSQL is most unsound.
  • A generous 1GB guaranteed memory for applications in the base USD 10/mo plan.
  • Like Dreamhost, it has SSH access. A crucial facility for developers, even on shared hosting.

I’m only on Webfaction’s basic plan, so have no comment on how they scale. But it’s a much more flexible, and competitively-priced shared hosting option.