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
Without further ado...
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;
}
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
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
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.
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
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
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
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!