{"id":22061194,"url":"https://github.com/binkley/modern-java-practices","last_synced_at":"2025-05-15T00:11:58.312Z","repository":{"id":37087662,"uuid":"300872181","full_name":"binkley/modern-java-practices","owner":"binkley","description":"Modern Java/JVM Build Practices","archived":false,"fork":false,"pushed_at":"2025-05-06T15:34:15.000Z","size":26036,"stargazers_count":962,"open_issues_count":66,"forks_count":71,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-13T00:02:18.287Z","etag":null,"topics":["agile","build","ci","java","jvm","practices","quality","reporting"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binkley.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-10-03T12:11:42.000Z","updated_at":"2025-05-10T14:50:20.000Z","dependencies_parsed_at":"2022-07-12T03:19:53.730Z","dependency_job_id":"886a7379-3bb2-4cac-94ae-d76cbee50ede","html_url":"https://github.com/binkley/modern-java-practices","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binkley%2Fmodern-java-practices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binkley%2Fmodern-java-practices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binkley%2Fmodern-java-practices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binkley%2Fmodern-java-practices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binkley","download_url":"https://codeload.github.com/binkley/modern-java-practices/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254249206,"owners_count":22039029,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agile","build","ci","java","jvm","practices","quality","reporting"],"created_at":"2024-11-30T18:09:43.606Z","updated_at":"2025-05-15T00:11:53.301Z","avatar_url":"https://github.com/binkley.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"./LICENSE.md\"\u003e\n\u003cimg src=\"./images/cc0.svg\" alt=\"Creative Commons 0\"\nalign=\"right\" width=\"10%\" height=\"auto\"/\u003e\n\u003c/a\u003e\n\n**[Read the book!](https://github.com/binkley/modern-java-practices/wiki)**\n_(this jumps to the wiki)_\u003cbr\u003e\n_Jump to [the project card wall](https://github.com/users/binkley/projects/1)\nto see upcoming book and code changes (the card wall tracks Issues for the\nproject)._\n\nSome highlighted documentation pages:\n- [_Keep local consistent with\n  CI_](https://github.com/binkley/modern-java-practices/wiki/Keep-local-consistent-with-CI)\n- [_Shift security\n  left_](https://github.com/binkley/modern-java-practices/wiki/Shift-security-left)\n\n# Modern Java/JVM Build Practices\n\n\u003ca href=\"https://modernagile.org/\" title=\"Modern Agile\"\u003e\n\u003cimg src=\"./images/modern-agile-wheel-english.png\" alt=\"Modern Agile\"\nalign=\"right\" width=\"20%\" height=\"auto\"/\u003e\n\u003c/a\u003e\n\n[![Gradle build](https://github.com/binkley/modern-java-practices/actions/workflows/ci-earthly-gradle.yml/badge.svg)](https://github.com/binkley/modern-java-practices/actions)\n[![Maven build](https://github.com/binkley/modern-java-practices/actions/workflows/ci-earthly-maven.yml/badge.svg)](https://github.com/binkley/modern-java-practices/actions)\n[![CodeQL](https://github.com/binkley/modern-java-practices/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/binkley/modern-java-practices/actions/workflows/github-code-scanning/codeql)\n[![vulnerabilities](https://snyk.io/test/github/binkley/modern-java-practices/badge.svg)](https://snyk.io/test/github/binkley/modern-java-practices)\n[![coverage](https://github.com/binkley/modern-java-practices/raw/master/images/jacoco.svg)](https://github.com/binkley/modern-java-practices/actions/workflows/ci.yml)\n[![pull requests](https://img.shields.io/github/issues-pr/binkley/modern-java-practices.svg)](https://github.com/binkley/modern-java-practices/pulls)\n[![issues](https://img.shields.io/github/issues/binkley/modern-java-practices.svg)](https://github.com/binkley/modern-java-practices/issues/)\n[![license](https://img.shields.io/badge/License-CC0_1.0-lightgrey.svg)](http://creativecommons.org/publicdomain/zero/1.0/)\n\n\u003e [!WARNING]\n\u003e For those using the DependencyCheck plugins for Gradle or Maven, over the\n\u003e July 1st weekend the upstream API for fetching security CVEs changed a major\n\u003e version, and stopped supporting older versions of the data.\n\u003e To get up to date, update to at least version 10.0.2 of either the Gradle or\n\u003e Maven plugin.\n\u003e\n\u003e After the update, the first build will take a _very long time_, but should\n\u003e perform normally afterwards.\n\u003e And during the first week or so after this change, you may see multiple\n\u003e connection failures as OWASP NVD is overloaded with projects all catching up\n\u003e at the same time.\n\u003e The Maven plugin shows progress as CVE records are pulled: to see progress\n\u003e with the Gradle plugin, use the `--info` command-line flag.\n\n**Modern Java/JVM Build Practices** is an article-as-repo on building modern\nJava/JVM projects using\n[Gradle](https://docs.gradle.org/current/userguide/userguide.html) and\n[Maven](https://maven.apache.org/what-is-maven.html), and a _starter project_\nin Java (the advice works for non-Java languages on the JVM though details may\nchange).\n\n\u003e [!IMPORTANT]\n\u003e See [the wiki](https://github.com/binkley/modern-java-practices/wiki) for\n\u003e all pages and sections.\n\u003e This README is only introduction, motivation, and project status.\n\u003e You can use the [table of contents](#table-of-contents) below to quickly\n\u003e jump to bits that interest you.\n\nRegardless of what language(s) or build tool(s) you choose, and you\nshould treat your build and your pipeline as worthy of your attention just as\nyou would your project source code:\n_If it doesn't build right for customers as it does for developers, you have\nsomething to think about._\n\nI'm showing you practices and tools that help you make your build and pipeline\nto production as _first-class_ the same as your own source code.\nAn example of this philosophy for a non-Java language is [Clojure](https://www.clojure.org/guides/tools_build#_builds_are_programs).\n\nYour focus, and the focus of this article, is _best build practices_ and\n_project hygiene_, and helping you have local work that is identical in\nproduction.\nThis project is _agnostic_ between Gradle and Maven: discussion in each section\ncovers both tools (alphabetical order, Gradle before Maven).\nSee [_My Final Take on Gradle (vs.\nMaven)_](https://blog.frankel.ch/final-take-gradle/) for an opinionated view\n(not my own).\n\nThis is not a JVM starter for only Java:\nI use it for starting my Kotlin projects, and substitute complilation and code\nquality plugins.\nAny language on the JVM can find practices and tips.\n\n\u003e [!NOTE]\n\u003e _Scala_ and _Clojure_ have their own prefered build tools not covered here;\n\u003e however, the advice and examples for your **build pipeline** are intended to\n\u003e be just as helpful for those JVM languages.\n\u003e Groovy and Kotlin can use the examples directly (they both tend towards the\n\u003e _Gradle_ option on build tools).\n\nAs a _guide_, this project focuses on:\n\n* A quick starter for JVM projects using Gradle or Maven.\n  [Fork](https://github.com/binkley/modern-java-practices/fork) me,\n  [clone](https://github.com/binkley/modern-java-practices.git) me, copy/paste\n  freely!\n  I am [Creative Commons Public Domain Dedication\n  (CC0)](https://creativecommons.org/public-domain/cc0/).\n* Discuss\u0026mdash;and illustrate (through code)\u0026mdash;sensible default practices;\n  highlight good build tools and plugins\n* Document pitfalls that turned up.\n  Some were easy to address after Internet search; some were challenging\n  (see \"Tips\" sections)\n* Do not be an \"all-in-one\" solution. You know your circumstances best.\n  I hope this project helps you discover build improvements you love.\n  Please share with others through\n  [issues](https://github.com/binkley/modern-java-practices/issues) or\n  [PRs](https://github.com/binkley/modern-java-practices/pulls)\n\n### Two recurring themes\n\n* _Shift problems left_ \u0026mdash; Find issues earlier in your build\u0026mdash;before\n  you see them in production\n* _Make developer life easier_ \u0026mdash; Automate build tasks often done by\n  hand: get your build to complain (_fail_) locally before sharing with your\n  team, or fail in CI before deployment\n\nThese can be summed up as a _Software supply chain_: ensuring reliable,\ntrusted software from local development through ready-to-deploy:\n**Build with confidence**.\n\nBut ... you **must** judge and measure the advice here against your own\nsystems and processes.\nSome things (many or most things) may work for you:\nkeep an eye for things that do not work for you.\n\n### What is a _Starter_?\n\nA project starter has several goals:\n- Help a new project get up and running with minimal fuss.\n- Show examples of _best practices_.\n- Explain the _why_ for choices, and help you pick what makes most sense for\n  your project.\n\nThis starter project is focused on _build_:\n- Easy on-ramp for new folks to try out your project for themselves\n- Support new contributors to your project that they become productive quickly\n- Support current contributors in the build, get out of their way, and make\n  everyday things easy\n\nThis starter project has minimal dependencies.\nThe focus is on Gradle and Maven plugins and configuration so that you and\ncontributors can focus on the code, not on setting up the build.\n\n### Summing up\n\n- _I'm not a great programmer; I'm just a good programmer with great habits._\n  \u0026mdash;\n  [Kent Beck](https://www.goodreads.com/quotes/532211-i-m-not-a-great-programmer-i-m-just-a-good-programmer)\n- _Make it work, make it right, make it fast_\n  \u0026mdash; [C2 Wiki](http://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast)\n\n\u003e [!NOTE]\n\u003e **NB** \u0026mdash; This is a _living document_.\n\u003e The project is frequently updated to pick up new dependency or plugin \n\u003e versions, and improved practices; the `README.md` and\n\u003e [wiki](https://github.com/binkley/modern-java-practices/wiki) update\n\u003e recommendations.\n\u003e This is part of what _great habits_ looks like: you do not just show love\n\u003e for your developers and users, but enable them to feed back into projects\n\u003e and help others.\n\u003e See [_Reusing this\n\u003e project_](https://github.com/binkley/modern-java-practices/wiki/Reusing-this-project)\n\u003e for tips on pulling in updates.\n\n(Credit to Yegor Bugayenko for [_Elegant\nREADMEs_](https://www.yegor256.com/2019/04/23/elegant-readme.html).)\n\n---\n\n\u003ca title=\"Try it\"\u003e\n\u003cimg src=\"./images/try.png\" alt=\"Run from a local script\"\nalign=\"right\" width=\"20%\" height=\"auto\"/\u003e\n\u003c/a\u003e\n\n## Try it\n\nYou should \"kick the tires\" and get a feel for what parts of this project\nyou'd like to pull into your own projects and builds.\nYou run across lots of projects:\nLet's make this one helpful for you.\n\nAfter cloning or forking this project to your machine, try out the local build\nthat makes sense for you:\n\n```shell\n$ earthly +build-with-gradle  # CI build with Earthly\n$ earthly +build-with-maven  # CI build with Earthly\n$ ./gradlew build  # Local-only build\n$ ./mvnw verify  # Local-only build\n```\n\nNotice that you can run the build purely locally, or _in a container_?\n\nI want to convince you that running your builds in a container fixes the \"it\nworked on my machine\" problem, and show you how to pick up improvements for\nyour build that helps you and others be _awesome_.\n\n\u003e [!NOTE]\n\u003e This project uses NVD to check for CVEs with your dependencies which can\n\u003e take a long time to download.\n\u003e You can speed up your build time by [requesting an NVD API\n\u003e key](https://nvd.nist.gov/developers/request-an-api-key) (it can take quite\n\u003e a while to fetch the CVEs list or update it, and may fail with 403 or 404\n\u003e without a key).\n\u003e\n\u003e When you request a key, NVD sends you an email to confirm your identity, and\n\u003e then share an API key web page.\n\u003e See [_Shift security\n\u003e left_](https://github.com/binkley/modern-java-practices/wiki/Shift-security-left)\n\u003e for more details.\n\nSee what the starter \"run\" program does:\n\nBoth Gradle and Maven (after building if needed) should print:\n```\nTheFoo(label=I AM FOOCUTUS OF BORG)\n```\n\nA \"starter\" program is the simplest of all possible [\"smoke\ntests\"](https://en.wikipedia.org/wiki/Smoke_testing_(software)), meaning,\nthe minimal things _just work_, and when you check other things, maybe smoke\ndrifts from your computer as circuits burn out[^1].\n\n[^1]: No, I'm just kidding.\nAmazon or Google or Microsoft cloud would have quite different problems than\n\"white smoke\" from computers[^2].\n\n[^2]: Actually, this really happened me in a data center before the cloud when\na power supply burned out.\nWe rushed to use a fire extinguisher before the Halon system triggered.\n\n---\n\n\u003ca title=\"Changes\"\u003e\n\u003cimg src=\"./images/changes.png\" alt=\"Changes\"\nalign=\"right\" width=\"20%\" height=\"auto\"/\u003e\n\u003c/a\u003e\n\n## Recent significant changes\n\n(For detailed changes in the example code, browse the [commit\nlog](https://github.com/binkley/modern-java-practices/commits/master/).)\n\n- Move to a CC0 license from Public Domain.\n- Gradle: Bump to Gradle 8.9.\n- Migrate most of the `README.md` to the [GitHub project\n  wiki](https://github.com/binkley/modern-java-practices/wiki).\n  This is breaks up an overlong (14k+ words and growing) README into\n  digestible sections.\n- Earthly and Batect: Remove support for Batect as the author has archived\n  that project.\n  Please use _Earthly_ for local containerized builds.\n  So your local command line is:\n  ```bash\n  $ earthly +build-with-gradle\n  # OR\n  $ earthly +build-with-maven\n  ```\n  I'll be researching other options, and updating to show those and examples.\n  Advice remains the same: Run your local build in a container for\n  reproducibility, and have CI do the same to exactly repeat your local\n  builds.\n- JVM: Move to JDK 21.\n  This project has no sample code relying on recent/modern versions of Java or\n  the JVM; however, moving between versions _does_ need changes to build\n  scripts and supporting files.\n  Here is [the last commit using JDK 17](https://github.com/binkley/modern-java-practices/commit/039f6f45fade51da0c548bf5d61b8013423ab8b9)\n- Gradle: Build with Gradle 8.x.\n- Gradle: Bemove use of `testsets` plugin for integration testing in favor of\n  [native Gradle\n  support](https://docs.gradle.org/current/userguide/java_testing.html#sec:configuring_java_integration_tests).\n  This supports Gradle 8.\n\n---\n\n\u003ca title=\"Table of Contents\"\u003e\n\u003cimg src=\"./images/table-of-contents.png\" alt=\"Table of Contents\"\nalign=\"right\" width=\"20%\" height=\"auto\"/\u003e\n\u003c/a\u003e\n\n## Table of Contents\n\nThe writing for this project is fully moved to the [wiki\npages](https://github.com/binkley/modern-java-practices/wiki/).\nUse the sidebar navigation in the wiki to browse or jump to topics, or to\nfollow in a reading order.\nYou can also use the droplist control next to \"Pages\" for an alphabetical\nlisting (including subheaders within pages), and for a search box.\n\nLastly, the wiki pages are themselves a repo, and you can clone it using \n`git@github.com:binkley/modern-java-practices.wiki.git` as you can for any\nGitHub wiki.\n\n---\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](./CONTRIBUTING.md).\nPlease [file issues](https://github.com/binkley/modern-java-practices/issues),\nor contribute [pull\nrequests](https://github.com/binkley/modern-java-practices/pulls)!\nI'd love a conversation with you.\n\n---\n\n## Credits\n\nSpecial thanks to my co-author, [John Libby](https://github.com/jwlibby).\n\nAnd many thanks to all the contributions from:\n\n* [Dan Wallach](https://github.com/danwallach) for multiple email reviews and\n  discussions on security\n* [Kristoffer Haugsbakk](https://github.com/LemmingAvalanche)\n* [Sam Gammon](https://github.com/sgammon)\n* [Sergei Bukharov](https://github.com/Bukharovsi)\n\nAll suggestions and ideas welcome!\nPlease [file an\nissue](https://github.com/binkley/modern-java-practices/issues). ☺\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinkley%2Fmodern-java-practices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinkley%2Fmodern-java-practices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinkley%2Fmodern-java-practices/lists"}