This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-15
Channels
- # architecture (5)
- # babashka (34)
- # beginners (72)
- # calva (42)
- # cherry (31)
- # cider (14)
- # clojure (27)
- # clojure-europe (11)
- # clojure-norway (17)
- # clojure-uk (1)
- # clojurescript (25)
- # community-development (13)
- # conjure (1)
- # core-async (11)
- # datascript (18)
- # datomic (11)
- # emacs (12)
- # fulcro (10)
- # integrant (5)
- # introduce-yourself (3)
- # jobs (8)
- # juxt (2)
- # malli (22)
- # off-topic (11)
- # pathom (18)
- # polylith (62)
- # rdf (18)
- # reagent (8)
- # releases (1)
- # shadow-cljs (35)
- # sql (3)
- # squint (141)
- # tools-deps (12)
- # vim (4)
- # xtdb (4)
having a strangely fun time trying to do polylith but with java modules
@JollyModule(ModuleKind.COMPONENT)
module dev.mccue.realworld.user {
requires dev.mccue.jollylith;
requires java.sql;
}
I'm not convinced the interface.clj
has as much of a place (everything in java is behind a logical interface + there is the service provider thing), but still its interesting.
Also the code layout for a pure java module project is mostly polylith friendly, but its cumbersome to make the folders for projects/components/bases and stuff - hence me making an annotationSo I have this as "UserService"
package dev.mccue.realworld.user;
import javax.sql.DataSource;
public interface UserService {
static UserService create(DataSource datasource) {
return new UserServiceImpl(datasource);
}
sealed abstract class LoginFailure extends Exception {
public static final class BadUsername extends LoginFailure {}
public static final class BadPassword extends LoginFailure {}
}
User login(String username, String password) throws LoginFailure;
sealed abstract class RegistrationFailure extends Exception {
public static final class EmailTaken extends RegistrationFailure {}
public static final class UsernameTaken extends RegistrationFailure {}
}
void register(
String username,
String email,
String password
) throws RegistrationFailure;
}
and then a UserServiceImpl inside of this package - but if I were to want to do swapping of implementation I think I would instead do the service provider thing where there is code like
ServiceLoader.load(UserService.class).findFirst().orElseThrow()
inside of create() and code like
module project {
requires com.github.sormuras.bach;
provides java.util.spi.ToolProvider with
project.Build2;
}
inside of the module declarationHi @U3JH98J4R!
Interesting. If I was going to do it in Java I would almost copy the way it’s implemented in Clojure:
• use the same directory structure:
◦ workspace
▪︎ components
• user
◦ src
▪︎ bases
• mybase
◦ src
▪︎ projects
• userservice
◦ pom.xml
• put each component interface in e.g. com.topns.user.User
and the functionality it exposes would be put in “functions” = public static methods, that often delegate to implementing “namespaces” = classes under com.topns.user
(the last name in a Clojure namespace is compiled to a Java class, so we have to mimic that).
• a base like mybase
would live in the namespace com.topns.mybase
where its API could live in e.g. com.topns.mybase.Api
and supporting “namespaces” also as classes undere com.topns.mybase
.
• each project would be a collection of all source directories of the selected bricks (components and often one base). Because Java only supports one namespace, you need solve that in some way, where one way is to use https://mvnrepository.com/artifact/org.codehaus.mojo/build-helper-maven-plugin Maven plugin.
If I remember right, the Java modules didn’t solve this problem, because you can not use the same component in more than one module (I may have wrong, because I haven’t programmed in Java for eight years!).
> it exposes would be put in “functions” = public static methods, I don't like this one because Java is obtuse to work with in that way, but also its restricting the kind of interface you can provide
> Because Java only supports one namespace, you need solve that in some way So with this system you can use javac like
javac --module-source-path . --module dev.mccue.realworld.main
and it will compile all dependent modules as part of its thingand either put the modules into folders that are called components/bases/etc OR put compontent/base in the package name OR add that as metadata to the module-info and shrug your shoulders, which is where im at
Okay, so the modules are equivalent to Polylith projects - the place you choose which bricks to include?
module dev.mccue.realworld.main {
requires dev.mccue.realworld.database;
requires dev.mccue.realworld.user;
}
@JollyModule(ModuleKind.COMPONENT)
module dev.mccue.realworld.database {
requires dev.mccue.jollylith;
requires java.sql;
}
Can you have multiple implementations of the same component, e.g. dev.mccue.realworld.user
? (to support swappable components)
1. Put the different dev.mccue.realworld.user implementations in different places in the filesystem and use --module-source-path to affect which one is found during compilation
2. Make explicit implementation modules dev.mccue.realworld.user.impl1
, dev.mccue.realworld.user.impl2
and have the api provided by dev.mccue.realworld.user
delegate to them
Do you also get the single development experience where you can work with all your code/bricks from one place?
The second one is what this syntax is for
provides java.util.spi.ToolProvider with
project.Build2;
Okay, cool!
making a module path that has external modules is unsolved-ish. I can make a module path with ant or whatever and use $(cat path) on everything
but that approach assumes that the whole project wants the same resolved dependencies for all artifacts so its...interesting
It would be cool if you could create a working https://codebase.show/projects/realworld?category=backend&language=java for the RealWorld.
Cool.
Yes, I saw realworld
in the package name.
Now you just have to implement tools.deps for Java! 😉
Nice!
https://get-coursier.io/ This exists and is pretty good, just married to scala at runtime
I contacted a university to see if I could wrestle up a group of students to translate that to Java as a senior design project
Okay, smart idea.
yep got green light from profs, present to students in a week. Trying to ego detach for the sake of making things happen
but yeah, with external dependency resolution this will work. Modules are still 😬 levels of support in the ecosystem, but...
and like mechanically they aren't solving much here other than 1. Making it clean 2. Convenient javac invocation 3. Declarative brick requires
and all the people who think modules really aren't useful still have the same points so I doubt this in particular will catch on, but i want to see the demo through
One way of approaching it could be to consume the Clojure implementation as a library from Java, and wrap each of the bricks with an interface in Java as a Polylith workspace, and when it works, replace one at a time with Java code.
This is how you could convert a codebase from e.g. Java to Clojure, but the other way around!
what never stops feeling strange is why im doing this - i used to write clojure for fun but now that i write clojure for work I write Java for fun
The benefits become more obvious when you have more than a handful bricks and a service, but maybe you will be able to sell the idea.
Okay, so this is just because you are curious to see how it would work out in Java, interesting!
> but maybe you will be able to sell the idea. With Java, even ideas i have really good pitches for I am pitching to an empty room
I tried to pitch Polylith to a really senior Java developer, but every time I said something, he replied that he could do the same using Maven!
read this thread if you want to be depressed https://www.reddit.com/r/java/comments/wodoy4/if_you_were_the_single_main_designer_of_java_what/
I have a post in there i wonder if you'll pick out, but like the community that does exist is focused on very silly things
or things that feel like bigger problems than they are because of people like that senior java dev to whom "everything is fine"
People don’t like change, in general. Most people like to feel safe and comfortable. If you have programmed in Java for 10+ or 20+ years, then generating toString, equals and hashCode methods from your IDE has become things you just do, without reflecting, it’s part of your workflow.
I guess this must have been by you “The verbosity of Java is one of the main reasons I like it so much.“!
Ha ha, bad joke.
https://www.reddit.com/r/java/comments/wodoy4/comment/ikc1d2v/?utm_source=share&utm_medium=web2x&context=3 This is a good overview of what i care about though. In truth the language is fine and getting better. Its everything around the language
Yes, it looks like Oracle has made a good job when they took over after Sun.