Question
Evgeny Shvarov · Jun 20, 2017

InterSystems Caché Project Files and Folders

Hi, Community!

How do you store the source files of your Caché project? What is the directories structure? What are the benefits?

I prefer the following structure:

/cls/package/subpackage/class.cls

/mac/package/routine.mac

/int/package/routine.int

/inc/macro.inc

/dfi/folder/sample.pivot.dfi

Example

Benefits: 

  • folders are packages.
  • easy to understand what type of sources are in the project.

What is your approach?

20
2 1 4 889
Log in or sign up to continue

Replies

cls/My/Deep/Class.cls

I don't think subdirectories should be applied for routines, originally routines aren't supposed to have submodules or subpackages and dots might be part of their name. Also if you need some complexity, you wouldn't prefer using routines but classes to keep things organized.
 

I DO NOT recommend using src, unless you want to mix both back-end and front-end code. 
Or you want to keep the server code in a separated repository.
Here is a scaffolding based on React for better understanding.

my-app-project /
   package.json
    server
          cls
          mac
          int
          csp <- this is our build path, nothing should be added manually because everything is handle by the bundler.

    scripts /

         test.js
         build.js
        dev.js
   config /
         webpack.config.dev.js
         webpack.config.prod.js
         webpack.config.test.js
   src /

         components
               Header
                   index.js
                   Header.js                   
                   HeaderSearchBar.js
               Footer

                   index.js
                   Footer.js
                   FooterCopyright.js
                AppContainer
                    index.js
                   AppContainer.js
          containers
                App.js
           tests
               components

                  Header
                      Header.js                   
                      HeaderSearchBar.js
                  Footer
                      Footer.js
                      FooterCopyright.js
                   AppContainer
                       index.js
                   AppContainer


                              
You can use folders to separate both client and server codes inside the same project. You can even structure your project

using a monorepo approach if you want to keep multiple application modules together.
                  

Now since React will be using webpack's hot module reloading along with webpack-dev-middleware that builds everything within the memory, your Caché server should only work following SPA conventions and providing consumable data.

There's a catch though, whenever the developer builds a new version (using webpack.config.prod), it's mandatory to delete the older bundle and import the project back to Caché to keep the source in sync on the server and the project.
     

Hi, Rubens!

Thank you for the wide answer, very interesting.

I agree with you on "no subfolders for routines" and separate folder for server-side code. 

May I wonder what are you using as IDE (Studio? Atelier? Something else?) and how do you import/export your code with Caché.

 

I develop using a mix of Caché Studio with Visual Studio Code.
I use Visual Studio Code for dealing with front-end code, while using Caché Studio for back-end.

I don't use Caché Studio to edit static files.
 

I'm actually doing experiments using my Port library for managing export/import operations.

 

About how I keep the server code close to it's client counterpart is quite simple. By default Port exports project following the template /CacheProjects/{NAMESPACE}/{PROJECT}, so instead of depending on it, I overwrite that path to /my-repo/server.

From this point exported files will follow:

/my-repo/server/cls/My/Class.cls

/my-repo/server/cls/Another/Deep/Package/Whatever.cls

/my-repo/server/int/myroutine.int
/my-repo/server/mac/myroutine.mac

/my-repo/server/dfi/mydef.dfi

/my-repo/server/int/myinclude.inc

And so on, for every recognized Caché file format.

Now notice that I didn't said anything about static files. That's where a module bundler like Webpack is used to orchestrate the client-side workflow.

Now Caché only needs to send readable data back to the SPA (preferably JSON using %CSP.REST).

When the project repo  reaches a milestone. I build a release to actually export the files to the path, like this:
 

/my-repo/server/web/app/bundle-[chunkhash].js

/my-repo/server/web/app/bundle-[chunkhash].css


Since  [chunkhash] is unique per build, the consumer shouldn't have any issues with browser cache.

Now there's an issue: the bundled files still aren't inside the CSP folder, so I need to import the project back to Studio using Port.
Files are imported using UDL instead of XML. But Port always keep a project XML up-to-date along with the UDL code.

As you can see I can work with Caché code AND Client-code, alternating between both editors, thus keeping their own development scope, even though their code remain inside the same repo.

I think the most important part of source control file structure is mirroring package structure in Studio, since that is the view we spend the most time with. That said it looks something like this:

root/
    Package1/
              Class.cls
              Class2.cls
              Routine.mac
              Include.inc
     Package2/ 
              Class.cls
              Class2.cls
              Routine.mac
              Include.inc

Additionally:

  1. Web app should be stored in a separate repository.
  2. If there's docs/dictionaries/etc, then all sources should be in a /src folder instead of repository root.
  3. All libs/modules/etc should be moved into their separate repositories each and plugged in as a submodules.
  4. Builds, if any should not be stored in a repo but rather meta-managed (releases).
  5. Commit messages and granular commit history is one of the most helpful things when analysing project history, enforce commit message style (title is the most important i.e. PART/SUBPART - thing done in a commit).