Rescale: The Return

What is Tech Talk?

A Brief History

Circa: 2000BC, my old boss, Rich, starts the practice

At Rescale, I started talking about refactoring

We keep it going at PAX

The point of Tech Talk is:

talk about what you're learning

When engage with Tech Talk, you're always looking at your work and thinking, "What am I learning now?"

Helps you become a better engineer

The Prompt:

  • What's something you worked on lately?
  • What made it interesting?
  • What did you learn from it?

Without further ado...

What's something I worked on lately?

Java Modules

Introduced in java 9

Declare dependencies on other modules

Declare packages that are exported

Open packages for reflective access

open module com.alexkudlick.authentication.models {
requires jackson.annotations;
requires com.google.common;

requires validation.api;
requires hibernate.validator;

exports com.alexkudlick.authentication.models;
}

Why is this a good thing?

Forces developer to be explicit about dependencies

Allows for controlled visibility

About those dependencies...

The complexity of basic projects is astounding

+--- io.dropwizard:dropwizard-core:1.2.9
| +--- io.dropwizard:dropwizard-util:1.2.9
| | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| | +--- com.google.guava:guava:23.5-jre (*)
| | --- joda-time:joda-time:2.9.9
| +--- io.dropwizard:dropwizard-jackson:1.2.9
| | +--- com.google.guava:guava:23.5-jre (*)
| | +--- io.dropwizard:dropwizard-util:1.2.9 (*)
| | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| | +--- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-guava:2.9.6
| | | +--- com.google.guava:guava:18.0 -> 23.5-jre (*)
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.6
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.6
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.6
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- com.fasterxml.jackson.module:jackson-module-afterburner:2.9.6
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-joda:2.9.6
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | +--- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | | --- joda-time:joda-time:2.7 -> 2.9.9
| | --- org.slf4j:slf4j-api:1.7.25
| +--- io.dropwizard:dropwizard-validation:1.2.9
| | +--- io.dropwizard:dropwizard-util:1.2.9 (*)
| | +--- org.hibernate:hibernate-validator:5.4.2.Final (*)
| | --- org.glassfish:javax.el:3.0.0
| +--- io.dropwizard:dropwizard-configuration:1.2.9
| | +--- io.dropwizard:dropwizard-jackson:1.2.9 (*)
| | +--- io.dropwizard:dropwizard-validation:1.2.9 (*)
| | +--- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.9.6
| | | +--- org.yaml:snakeyaml:1.18
| | | --- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | --- org.apache.commons:commons-lang3:3.6
| +--- io.dropwizard:dropwizard-logging:1.2.9
| | +--- io.dropwizard:dropwizard-jackson:1.2.9 (*)
| | +--- io.dropwizard:dropwizard-validation:1.2.9 (*)
| | +--- io.dropwizard.metrics:metrics-logback:3.2.5
| | | --- io.dropwizard.metrics:metrics-core:3.2.5
| | +--- org.slf4j:slf4j-api:1.7.25
| | +--- org.slf4j:jul-to-slf4j:1.7.25
| | | --- org.slf4j:slf4j-api:1.7.25
| | +--- ch.qos.logback:logback-core:1.2.3
| | +--- ch.qos.logback:logback-classic:1.2.3
| | | --- ch.qos.logback:logback-core:1.2.3
| | +--- org.slf4j:log4j-over-slf4j:1.7.25
| | | --- org.slf4j:slf4j-api:1.7.25
| | +--- org.slf4j:jcl-over-slf4j:1.7.25
| | | --- org.slf4j:slf4j-api:1.7.25
| | --- org.eclipse.jetty:jetty-util:9.4.11.v20180605
| +--- io.dropwizard:dropwizard-metrics:1.2.9
| | +--- io.dropwizard:dropwizard-lifecycle:1.2.9
| | | +--- org.slf4j:slf4j-api:1.7.25
| | | +--- com.google.guava:guava:23.5-jre (*)
| | | +--- org.eclipse.jetty:jetty-server:9.4.11.v20180605
| | | | +--- javax.servlet:javax.servlet-api:3.1.0
| | | | +--- org.eclipse.jetty:jetty-http:9.4.11.v20180605
| | | | | +--- org.eclipse.jetty:jetty-util:9.4.11.v20180605
| | | | | --- org.eclipse.jetty:jetty-io:9.4.11.v20180605
| | | | | --- org.eclipse.jetty:jetty-util:9.4.11.v20180605
| | | | --- org.eclipse.jetty:jetty-io:9.4.11.v20180605 (*)
| | | --- io.dropwizard:dropwizard-util:1.2.9 (*)
| | +--- io.dropwizard:dropwizard-jackson:1.2.9 (*)
| | +--- io.dropwizard:dropwizard-validation:1.2.9 (*)
| | +--- io.dropwizard.metrics:metrics-core:3.2.5
| | --- org.slf4j:slf4j-api:1.7.25
| +--- io.dropwizard:dropwizard-jersey:1.2.9
| | +--- io.dropwizard:dropwizard-jackson:1.2.9 (*)
| | +--- io.dropwizard:dropwizard-validation:1.2.9 (*)
| | +--- io.dropwizard:dropwizard-logging:1.2.9 (*)
| | +--- org.glassfish.jersey.core:jersey-server:2.25.1
| | | +--- org.glassfish.jersey.core:jersey-common:2.25.1
| | | | +--- javax.ws.rs:javax.ws.rs-api:2.0.1
| | | | +--- javax.annotation:javax.annotation-api:1.2
| | | | +--- org.glassfish.jersey.bundles.repackaged:jersey-guava:2.25.1
| | | | +--- org.glassfish.hk2:hk2-api:2.5.0-b32
| | | | | +--- javax.inject:javax.inject:1
| | | | | +--- org.glassfish.hk2:hk2-utils:2.5.0-b32
| | | | | | --- javax.inject:javax.inject:1
| | | | | --- org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b32
| | | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | | +--- org.glassfish.hk2:hk2-locator:2.5.0-b32
| | | | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | | | +--- org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b32
| | | | | +--- org.glassfish.hk2:hk2-api:2.5.0-b32 (*)
| | | | | +--- org.glassfish.hk2:hk2-utils:2.5.0-b32 (*)
| | | | | --- org.javassist:javassist:3.20.0-GA
| | | | --- org.glassfish.hk2:osgi-resource-locator:1.0.1
| | | +--- org.glassfish.jersey.core:jersey-client:2.25.1
| | | | +--- javax.ws.rs:javax.ws.rs-api:2.0.1
| | | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | | +--- org.glassfish.hk2:hk2-api:2.5.0-b32 (*)
| | | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | | | +--- org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b32
| | | | | +--- org.glassfish.hk2:hk2-api:2.5.0-b32 (*)
| | | | | +--- org.glassfish.hk2:hk2-utils:2.5.0-b32 (*)
| | | | | --- org.javassist:javassist:3.20.0-GA
| | | | --- org.glassfish.hk2:osgi-resource-locator:1.0.1
| | | +--- org.glassfish.jersey.core:jersey-client:2.25.1
| | | | +--- javax.ws.rs:javax.ws.rs-api:2.0.1
| | | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | | +--- org.glassfish.hk2:hk2-api:2.5.0-b32 (*)
| | | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | | --- org.glassfish.hk2:hk2-locator:2.5.0-b32 (*)
| | | +--- javax.ws.rs:javax.ws.rs-api:2.0.1
| | | +--- org.glassfish.jersey.media:jersey-media-jaxb:2.25.1
| | | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | | +--- org.glassfish.hk2:hk2-api:2.5.0-b32 (*)
| | | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | | +--- org.glassfish.hk2:hk2-locator:2.5.0-b32 (*)
| | | | --- org.glassfish.hk2:osgi-resource-locator:1.0.1
| | | +--- javax.annotation:javax.annotation-api:1.2
| | | +--- org.glassfish.hk2:hk2-api:2.5.0-b32 (*)
| | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | +--- org.glassfish.hk2:hk2-locator:2.5.0-b32 (*)
| | | --- javax.validation:validation-api:1.1.0.Final
| | +--- org.glassfish.jersey.ext:jersey-metainf-services:2.25.1
| | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | --- javax.ws.rs:javax.ws.rs-api:2.0.1
| | +--- org.glassfish.jersey.ext:jersey-bean-validation:2.25.1
| | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | +--- org.glassfish.jersey.core:jersey-server:2.25.1 (*)
| | | +--- javax.validation:validation-api:1.1.0.Final
| | | +--- org.hibernate:hibernate-validator:5.1.3.Final -> 5.4.2.Final (*)
| | | --- javax.ws.rs:javax.ws.rs-api:2.0.1
| | +--- io.dropwizard.metrics:metrics-jersey2:3.2.5
| | | +--- io.dropwizard.metrics:metrics-core:3.2.5
| | | --- io.dropwizard.metrics:metrics-annotation:3.2.5
| | | --- org.slf4j:slf4j-api:1.7.22 -> 1.7.25
| | +--- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.9.6
| | | +--- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:2.9.6
| | | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | | --- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.9.6
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- org.glassfish.jersey.containers:jersey-container-servlet:2.25.1
| | | +--- org.glassfish.jersey.containers:jersey-container-servlet-core:2.25.1
| | | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | | +--- org.glassfish.jersey.core:jersey-server:2.25.1 (*)
| | | | --- javax.ws.rs:javax.ws.rs-api:2.0.1
| | +--- io.dropwizard.metrics:metrics-jersey2:3.2.5
| | | +--- io.dropwizard.metrics:metrics-core:3.2.5
| | | --- io.dropwizard.metrics:metrics-annotation:3.2.5
| | | --- org.slf4j:slf4j-api:1.7.22 -> 1.7.25
| | +--- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.9.6
| | | +--- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:2.9.6
| | | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | | --- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.9.6
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| | | +--- com.fasterxml.jackson.core:jackson-core:2.9.6 -> 2.9.9
| | | --- com.fasterxml.jackson.core:jackson-databind:2.9.6 -> 2.9.9 (*)
| | +--- org.glassfish.jersey.containers:jersey-container-servlet:2.25.1
| | | +--- org.glassfish.jersey.containers:jersey-container-servlet-core:2.25.1
| | | | +--- org.glassfish.hk2.external:javax.inject:2.5.0-b32
| | | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | | +--- org.glassfish.jersey.core:jersey-server:2.25.1 (*)
| | | | --- javax.ws.rs:javax.ws.rs-api:2.0.1
| | | +--- org.glassfish.jersey.core:jersey-common:2.25.1 (*)
| | | +--- org.glassfish.jersey.core:jersey-server:2.25.1 (*)
| | | --- javax.ws.rs:javax.ws.rs-api:2.0.1
| | +--- org.eclipse.jetty:jetty-server:9.4.11.v20180605 (*)
| | +--- org.eclipse.jetty:jetty-webapp:9.4.11.v20180605
| | | +--- org.eclipse.jetty:jetty-xml:9.4.11.v20180605
| | | | --- org.eclipse.jetty:jetty-util:9.4.11.v20180605
| | | --- org.eclipse.jetty:jetty-servlet:9.4.11.v20180605
| | | --- org.eclipse.jetty:jetty-security:9.4.11.v20180605
| | | --- org.eclipse.jetty:jetty-server:9.4.11.v20180605 (*)
| | +--- org.eclipse.jetty:jetty-continuation:9.4.11.v20180605
| | --- org.apache.commons:commons-lang3:3.6
| +--- io.dropwizard:dropwizard-servlets:1.2.9
| | +--- org.slf4j:slf4j-api:1.7.25
| | +--- io.dropwizard:dropwizard-util:1.2.9 (*)
| | +--- io.dropwizard.metrics:metrics-annotation:3.2.5 (*)
| | +--- io.dropwizard.metrics:metrics-core:3.2.5
| | --- ch.qos.logback:logback-classic:1.2.3 (*)
| +--- io.dropwizard:dropwizard-jetty:1.2.9
| | +--- io.dropwizard:dropwizard-logging:1.2.9 (*)
| | +--- io.dropwizard.metrics:metrics-jetty9:3.2.5
| | | --- io.dropwizard.metrics:metrics-core:3.2.5
| | +--- org.eclipse.jetty:jetty-server:9.4.11.v20180605 (*)
| | +--- org.eclipse.jetty:jetty-servlet:9.4.11.v20180605 (*)
| | +--- org.eclipse.jetty:jetty-servlets:9.4.11.v20180605
| | | +--- org.eclipse.jetty:jetty-continuation:9.4.11.v20180605
| | | +--- org.eclipse.jetty:jetty-http:9.4.11.v20180605 (*)
| | | +--- org.eclipse.jetty:jetty-util:9.4.11.v20180605
| | | --- org.eclipse.jetty:jetty-io:9.4.11.v20180605 (*)
| | --- org.eclipse.jetty:jetty-http:9.4.11.v20180605 (*)
| +--- io.dropwizard:dropwizard-lifecycle:1.2.9 (*)
| +--- io.dropwizard.metrics:metrics-core:3.2.5
| +--- io.dropwizard.metrics:metrics-jvm:3.2.5
| | --- io.dropwizard.metrics:metrics-core:3.2.5
| +--- io.dropwizard.metrics:metrics-servlets:3.2.5
| | +--- io.dropwizard.metrics:metrics-core:3.2.5
| | +--- io.dropwizard.metrics:metrics-healthchecks:3.2.5
| | +--- io.dropwizard.metrics:metrics-json:3.2.5
| | | --- io.dropwizard.metrics:metrics-core:3.2.5
| | +--- io.dropwizard.metrics:metrics-jvm:3.2.5 (*)
| | --- com.papertrail:profiler:1.0.2
| | --- joda-time:joda-time:2.9.1 -> 2.9.9
| +--- io.dropwizard.metrics:metrics-healthchecks:3.2.5
| +--- io.dropwizard:dropwizard-request-logging:1.2.9
| | +--- io.dropwizard:dropwizard-jetty:1.2.9 (*)
| | +--- io.dropwizard:dropwizard-logging:1.2.9 (*)
| | --- ch.qos.logback:logback-access:1.2.3
| | --- ch.qos.logback:logback-core:1.2.3
| +--- net.sourceforge.argparse4j:argparse4j:0.7.0
| --- org.eclipse.jetty.toolchain.setuid:jetty-setuid-java:1.0.3

What kind of classes is my project actually using?

From the dependency tree, it's impossible to tell

module com.alexkudlick.authentication.application {
requires com.alexkudlick.authentication.models;

requires jackson.annotations;
requires com.google.common;
requires javax.ws.rs.api;
requires java.naming;

requires java.sql;
requires java.xml.bind;

requires hibernate.jpa;
requires dropwizard.hibernate;
requires hibernate.core;
requires spring.security.crypto;
requires dropwizard.servlets;
requires dropwizard.db;
requires dropwizard.migrations;
requires com.fasterxml.jackson.databind;

requires validation.api;
requires hibernate.validator;

requires dropwizard.core;
requires dropwizard.configuration;

opens com.alexkudlick.authentication.application.config to com.fasterxml.jackson.databind;
opens com.alexkudlick.authentication.application.web to jersey.server;
opens com.alexkudlick.authentication.application.entities to hibernate.core, javassist;
}

The module-info.java provides a high-level description of the module

The other benefit: explicit package export

Allows for hidden internal complexity

,

This is especially with good dropwizard bundles

You can build modules that only export one package with a bundle

No possibility for confusion about how to use the module

What made it interesting?

The blog is self-referential in a number of ways

The first - everything is referencing commits in a repo

I wanted to build a real application

None of the advice online talked about real problems

So I solved those problems and wrote about it

The blog is two things - an application, and a story about building the application.

Self Referential Structure

Documents have an inherent structure: time

Sections are linked by the order in which you read them

,

But on the web, you're always linking to other sites

,

I wanted to take it to the next level

Link parts of the to document to each other

,

Makes the document feel more like a codebase

Code doesn't have a linear structure

Neither did the blog - could have written sections in a different order

What did I learn from it?

React Context API

export class SectionRegistry {
constructor() {
this.sections = [];
this.sectionListeners = [];
}

registerSection(title, id) {
this.sections.push({ title, id });
this.sectionListeners.forEach(listener => { listener(this.sections); });
}

onNewSection(consumer) {
consumer(this.sections);
this.sectionListeners.push(consumer);
}
}

export const SectionContext = React.createContext(new SectionRegistry());
export class RegisteredSection extends React.Component {
static contextType = SectionContext;

...

componentDidMount() {
this.context.registerSection(this.props.label, makeId(this.props.label));
}
class BlogEntry extends React.Component {
constructor(props) {
super(props);
this.sectionRegistry = new SectionRegistry();
}

...

render() {
<SectionContext.Provider value={this.sectionRegistry}>
{ this.props.children }
</SectionContext.Provider>
}
export default class TableOfContents extends React.Component {
static contextType = SectionContext;

...

componentWillMount() {
this.context.onNewSection(sections => {
this.setState({ sections });
});
}

Contexts are a good way to manage sibling communication

You could use state on the parent node

But that couples children to the parent

And makes nesting a pain

Build the tools / Write the client first

Don't just solve a problem, build the tools to solve the problem

Alex K.

This will come from writing the client first

Or rather, write the code you wish you had

At first I started writing links like this:

<a href="https://github.com/akud/modular-java-example/commit/528572a284a38d27d497df596ba50fa5c8150442">this commit</a>

That got tiring, so I did this:

const CommitLink = ({ hash, children }) => <a href={`https://github.com/akud/modular-java-example/commit/${hash}`}>{children}</a>

...
... <CommitLink hash='528572a284a38d27d497df596ba50fa5c8150442'>this commit</CommitLink>

CommitLink became a tool

It saved me typing

But also gave me a concept to think with

I could imagine features like making all commit links purple

The same thing happened with tabs

As I was writing, I noticed I wanted code in tabs

So I just wrote <TabGroup> and implemented it later

Quality doesn't always lead to success

This subject is pretty esoteric, which limits interest

But my primary motivation is quality

Plus now I have all these tools in my website codebase

And thanks to David for organizing this!