4 ms·
Wow, that's a crazy structure. I like it. Conceptually, Obvious is language-independent, but for now it's only implemented in Ruby. It would be pretty easy to i
by programminggeek 14y ago
Wow, that's a crazy structure. I like it. Conceptually, Obvious is language-independent, but for now it's only implemented in Ruby. It would be pretty easy to implement elsewhere in Java, Scala, Python, or whatever.
That being said, in each instance you could use the Obvious approach to structure each app. If you were using the same language in each place, you could theoretically reuse the "app" structure in multiple places, so that your same business rules and validations would exist in each instance.
For the structure you describe, if you were willing to do Website B in something that worked with the JVM, you could write your "app" in Java or Scala and package it as a JAR file. So, you could use Jython to run your python code on the JVM. Then, you could reuse your app library in each project.
Assuming your app is a JAR file, your structure would look like this:
REST API - Scala for delivery -> App JAR -> NoSQL plug
Website - Java, Scala, Jruby, or Jython for delivery? -> App JAR -> API plug or MySQL plug
Android - Java for delivery -> App JAR -> SQLite db plug & API plug
If you were able to run the whole thing on the JVM you could place them all in one project, or separate projects, it's really up to you. And yes, the REST API would act as a delivery mechanism for system A and a plug for systems B and C.
- ttiurani 14y agoThe motivation for the two server backend is that I currently have one working standalone B and will build a second B soon to serve a closely related purpose, and really don't want to duplicate the work or the data. That's why a backend server that stores common data and also most of the heavy business logic looks like the best solution at the moment. Obvious seems like a very good fit for all the B's (closely related Python websites). But I don't know about Scala backend though: do you have thoughts on packaging of different deliveries for static languages in Obvious? Because if there is only one folder structure, you typically (with Maven) get only one JAR. To get many JARs the folder structure quickly turns into: app/actions/common/src/main/scala app/actions/featureset1/src/main/scala app/actions/featureset2/src/main/scala delivery/plug1/src/main/scala delivery/plug2/src/main/scala etc. which isn't very pretty nor obvious (sic!). The other option I can think of is to have one big JAR that always has every plug and delivery baked in with a folder structure like: src/main/scala/[Obvious folders] and plugs and deliveries would then need to be activated runtime with configuration files. But that also seems sub-optimal: I don't want to have any code in production I'm not going to use. Am I missing something?
- programminggeek 14y agoCan't you put the whole app folder into one JAR? Also, you could put all the jacks and plugs into a a separate JAR. So, you have two JAR files to include into each project. I think you could have each JAR have src/main/scala/[Obvious folders] type structure, so for your app.jar you could have src/main/scala/app and src/main/scala/external for the external.jar. You can make it as granular as you need, but the more you break things up, the more packaging overhead you'll incur.
- ttiurani 14y agoThe problem with one JAR is that you will then have to configure runtime in production which delivery is used and also, if there are alternative plugs (or jacks), what set of plugs you activate. That would have to be done with an external config file or database row, command line parameters or some super GUI. The problem is that those are really dangerous configuration options, because changing any of them, results in catastrophic failure: e.g. someone might accidentally change a plug configuration option to another value, and your MySQL turns into MongoDB which you don't have. That makes you want to _not_ have one JAR and then keep your fingers crossed that it is configured right. Optimally things should just work (tm) in production without any configuration. (Not to mention if you try to sell your software, you can not sell just one package because just by changing the configuration from delivery1 to delivery2 you get the second product for free.) With dynamic languages what you presumably would want to do is just zip the right files and that's that (although you still need system tests that verify that the zip has the right stuff in it), but with static languages it's more tricky. One way to get that would be to have A-core.jar that has all code that is common to every installation, and then A-installation1.jar with the right delivery and plugs for the first installation, and A-installation2.jar for files for the second installation etc.. Because in the installation JARs there would be only one delivery, and only one plug per jack (and one jack per contract), things would work without any additional configuration. Now the problem with Maven is that you can't easily get many JARs from one src/main/scala. Or can but things get complicated when start releasing stuff to repositories. Which results in the really messy directory structure I outlined above, or then you would have to figure out some other directory structure that would work better. Of course the best would be to hack Maven to work around the "one JAR per src/main/scala" limitation. Or write a maven-obvious-plugin. :) The backstory here is that packaging tools easily mandate directory structure. Directory structure in turn directs source packages (inverted URL in Java), and source packages tend to influence the architecture. The cool thing in Obvious is that by making the directory structure itself reflect the architecture, code is automatically steered towards good practices. Of course you can create a great code architecture with any directory structure, but in many cases _where_ you can put stuff, influence _what_ you put in there. So in some cases, it's actually the supposedly trivial packaging of sources that is a culprit for bad decisions. Which IMO makes packaging also non-trivial from an architecture standpoint.