-
-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use of :paths outside a project is not recommended #66
Comments
Hi Alex! Thank you for your interest in Polylith and creating this issue to help us make it even better. I’ll begin my response by quickly explaining the relevant parts of the high-level design of Polylith, and how that affects the various approaches we tried with Projects in a Polylith workspace are the way to configure deployable artifacts. Each project can be deployed as a jar file or as a Datomic Ions revision, etc. So the projects Components are encapsulated blocks of code, which can be assembled together in projects with other components, a base, and external dependencies. We do not see them as local libraries or dependencies, rather we see them as a living part of a single codebase. So that’s a quick recap of relevant parts of the documentation, and now I can explain what we’ve tried so far. First, instead of having one We also tried using the Using relative paths in the We would love to have a chat more about this with you and figure out how we can solve this problem, without introducing any new complexity or friction to the users of Polylith. Cheers, |
Thanks, that's a helpful overview. Given what you said, I think having a root deps.edn is probably what I would recommend in this case and is the best mapping. With respect to the Ion commands, I think maybe you gave up too quickly there. The tricky thing with the ion tools is that you are running the tool, so classpath-modifying options affect the tool itself, not the libraries being assembled by the tool. I believe the ion dev tools have a way to do this but I will follow up with the Datomic team and get back to you. |
In Polylith, the workspace is the root of all our code, which allows us to share code between all our projects, e.g.:
The development project lives at the root, while the other projects live under the projects directory. This keeps things simple and separated, and allows us to reuse all our building blocks (components and bases) in all our projects by specifying each of them in a single config file, which makes each This is a very simple and powerful way of organising code, and allows us to separate development from how things are executed in production, while giving us a single development experience with “living code” that we can change and get instant feedback from. To force people to merge all those project files into one single file would be painful, because they represent different artefacts and should naturally live in separate So to be able to give the users of Polylith the best possible experience, we would appreciate it if you would consider supporting the way Polylith currently structures the code. We understand that you have many other use cases to consider, and that Polylith is not in any kind of position to dictate any of your design decisions. However, we’re hoping that there’s a way to solve this issue, which keeps the simplicity and clarity of Polylith’s current structure intact, and still gives BR, |
It seems like you are trying to both have independent reusable pieces of code (what we'd call libraries usually) while also not using any of the tools we use to make code independent and reusable. (In Simple vs Easy terms, this seems very much on the side of "easy" rather than "simple".) Re:
You've already forced people to merge all of the project files in the deps.edn at the root (and in each project deps.edn). As you say, "they represent different artefacts and should naturally live in separate deps.edn files" - this same reasoning should apply to components and bases too, should it not? The components have no statement of dependencies so they cannot even be understood without some greater root, which I don't like at all. From the "living code" aspect, you seem to be trying to get away from building and consuming artifacts which is where a lot of the perceived "heaviness" of using multiple projects comes from, and I think that's a good goal and is in fact why we have local deps in deps.edn. They allow you to have these references to source-based projects without needing to make or consume artifacts. You seem resistant to making a deps.edn for those but a starting one for a component without dependencies is just: The tooling concern for the intent of "run all tests" I agree is not well served without additional assistance right now (I think we will make this better and are tracking this need at https://ask.clojure.org/index.php/9849/teams-common-dependencies-tooling-across-multiple-projects). In the meantime, you could make a polylith tool run by In summary, I strongly think your components and bases are mini-projects, should have deps.edn files, and should be referred to from your projects as local deps. I think this adds minimal additional work to polylith users and better factors things like dependency definition to reduce duplication. It's also more in line with where clj and deps.edn are going as tools and what ion-dev tools are likely to support. |
Hi Alex! Again, we greatly appreciate your messages and they really made us think outside of the box. The components in Polylith differ from libraries significantly. A library clearly states the dependencies it needs and it can be bundled and released under a version. However, a Polylith component is part of the whole codebase and what libraries it uses are only specified in the project(s) it is used in. Another important thing to note is that Polylith components only know about interfaces, and they are not aware of what concrete components they depend on. This decision is made only when it’s time to combine a component with other components into one or several projects. In other words, a component can’t live alone, isolated from other components, and this is the way they become isolated, decoupled, and reusable, Lego-like blocks of code. In summary, we still can’t think of components as mini-projects because they lack many of the characteristics that define a project. At first thought, we also considered having Another solution would be for us to develop our own Polylith configuration file. Instead of using Another benefit of this solution could be that the Polylith tool would be independent of build tools and could be used by users of Leiningen or Boot. If the user prefers, they can use Leiningen for their development environment, whereas Polylith tool will be using I have included a diagram below describing the proposed solution and we would like to hear your thoughts on this. Cheers, |
Seems like a reasonable solution. You could probably generate the deps.edn too. I still think it's weird that you have to restate the dependencies of every component in every project, rather than stating those in the component itself once. |
Hi again. Let me try to explain this by using an example. In the object oriented world, we can depend on an interface without knowing what concrete class it implements. This is how we decouple code and allow other parts of the codebase to decide what concrete class to instantiate, without affecting the user of the interface. If we had to force the user of the code to know the concrete class, then they wouldn’t be decoupled and the polymorphic mechanism wouldn’t work. Component interfaces use the same idea, that the code that uses an interface shouldn’t know the concrete component behind the interface. If we are forced to specify the concrete components it uses in each component, then it wouldn’t work either, in the same way it didn’t work in the OO example. Let’s say we have the component interface Because we can’t specify which concrete components to use for each component, it will not work to have a We hope this answered your question and if not, now could be the time to book a short meeting to dispel any ambiguities, because explaining things in text has its limitations. Cheers, |
What you're saying about interfaces and implementations makes sense but does not seem to match what I see in example projects, so maybe that's why I'm confused. For example, this database component has an interface that has no dependencies but uses java.jdbc and honey in it's implementation. When a project wants to use the database component, I don't understand how you can know to include java.jdbc other than by manually looking through all the components source code and guessing what dependencies you need to include. And you need to do that each time you make a project or change the components a project uses (and for the root deps.edn). If the interface and implementation were actually separate, and the implementation declared what its own deps were, then you could just specify the set of components to use and you would automatically get the right set of deps. |
You are absolutely right that specifying what libraries a component uses is not a bad idea at all. The good thing with it is that you are explicit about what libraries each component uses, and that was also how we implemented it in the Leiningen version. In this version we went for a more decoupled approach, you could say. When you start to use a new library in a component, you first add it to the When you later create a new project and add the The problem can be solved in many different ways, but this has worked very well for us, and allows us to focus on the development experience. |
Fixed in #94 |
Hi Alex! Today we finally released v0.2.0-alpha10 that includes this issue. I was just going to say that it has worked really well to let each brick keep track of its own sources and dependencies and that this change has made the tool even better! /Joakim |
Describe the bug
The polylith directory structure instructs users to create projects with a deps.edn with
:paths
outside the project itself:This is generally a bad idea. The intent of
:paths
is to describe paths in your own project. In the polylith setup, these are effectively local dependencies. In the future, use of paths that are not under the project root may emit a warning or even an error.deps.edn supports local dependencies using the
:local/root
coordinate attribute. Relative paths are supported there.You would also need deps.edn files under ../../components/user with
:paths ["src" "resources"]
etc of course.I can't fully assess what other impacts this may have on the polylith architecture, but using local deps is strongly preferred over referring to non-project paths. If for some reason this is not sufficient, I'd appreciate talking through why (I know there are some issues others have raised for monorepo style setups).
Alternately, using a deps.edn at the root of the entire project may also be an option, if you want to consider the entire thing as a single project.
The text was updated successfully, but these errors were encountered: