v4 work #153
dcarbone
announced in
Announcements
v4 work
#153
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Hello those out there.
Firstly, I want to thank those of you who have contributed to this project over the years. Having not directly worked on a FHIR project in nearly 10 years now, I rely on you all providing feedback for when particular parsing or formatting patterns need improvement.
That said, I also recognize there is quite a bit about the original v0-v3 line that leave a lot to be desired.
TLDR:
If you just want to see the current output from v4 as I work on it, I'll be pushing updates to the v4.x branch of php-fhir-generated.
Current Pain Points and Proposed Solutions
Here are some of the high-level pain points, as I see them:
1. Constructing classes
When I first designed this library, I prioritized serialization & unserialization above all else. This led to the current generated type constructor definition, which has a singular parameter of an array. This made it "easier" to implement construction from JSON, but made it quite annoying to actually define types manually. This pattern:
is not user friendly, nor something I would tolerate using in my own work. I had never intended the constructor to be the way to define classes, which is why I made setters fluid:
This is a much "nicer" pattern, but still less than ideal.
Solution: Named Parameters
Thankfully, PHP 8.0 introduced named parameters. This has allowed me to redefine the constructors of types to contain individual parameters per field, including those of their parent classes:
I've also made it much easier to define "primitive container" types, directly with a value rather than having to define the full class:
I feel this is much nicer API for humans. It should also provide a (hopefully measurable) improvement to performance if your code constructs types often.
2. "Root" namespace bloat
The current implementation of the builder puts all "Core" classes, i.e. the Autoloader, the TypeMap, the ResponseParser, any / all interfaces, enums, traits, etc., all in the "root" namespace of the output. Unfortunately, this is also where FHIR primitives and "root" type classes are placed.
This is messy and bad.
Solution: Complete Rewrite.
The updated output from v4 separates "core" classes from "FHIR" classes, meaning they are no longer fighting each other for symbol names.
The result of this can be seen over in the v4.x branch of php-fhir-generated.
3. Each Version is a silo.
When I originally wrote this lib (before even open-sourcing it), there was only DSTU1. DSTU2 came out right a the tail end of my work within the FHIR ecosystem, and I was presented with a problem: I hadn't designed the builder to handle multiple versions nicely. I had also made the assumption that most people would only need to directly work with a single version in a given codebase, but that seems to not really be the case.
This means, in short, that rendering this library with multiple FHIR versions results in a single library that basically contains 2+ "sub" libraries, each containing a duplicate of "core" classes.
Solution: Complete Rewrite.
I had wanted to do this for a very long time now, but never had the time to do it. Thankfully (?), I was part of a RIF in early December 2024, and the lack of a job meant I had, for the first time in a decade, a sustained period of time where I could dedicated a significant amount of my day to improvements.
As a reminder, I do not get paid for producing this library. I don't work for an institution that uses FHIR. Any / all updates are done because I like producing tools for people to use.
The output from this lib now defines a set of common interfaces that are implemented by each generated version, with the ultimate end goal to enable better "sharing" of information between versions. Eventually I'd like to create a series of "middle" interfaces for like types, enabling a DSTU2 Patient to be quickly "updated" to an R5 Patient. Common interface for the "Identifier" type. Common Primitives. These are all things I'd like to do, but will not get to with the first v4 release. They are now, however, possible.
4.
generate.php
This script was original added by a community member, and I in no way mean to disparage their contribution. It was welcome, and is the primary way in which users seem to interact with this library (or so it seems).
But, there are problems.
Firstly, I made the poor decision to have it default to re-downloading FHIR sources every time its run. This was a horrible idea, and I believe contributed to the FHIR maintainers blocking the UserAgent string defined by the original implementation. It also lead people to using the provided example configuration as the only configuration, meaning they were just downloading and generating everything every time.
Secondly, it slightly obfuscates the actual usage of this library. In the multi-year gap between updates, I quite literally forgot my own code and ended up just hacking really bad ideas into the execution path used by the generate script to get features out there. I didn't spend the time to think whether it was a good idea or not. The ultimate result was a really messy, unpleasant experience for those not using the generate script, and an abusive execution path for those using the generate script.
Solution: Neuter the script and clean up library execution path
The first phase of this is simply to neuter the
generate.php
script. This may be very annoying for some, but basically we will both ultimately be happier if you just fetch the schema for the version(s) you actually care about and only configure the builder for those.To that end, the
generate.php
script has been vastly trimmed down. It no longer does any fetching of anything, and merely provides a thin CLI "wrapper" around constructing and running the Builder.Long term, I'd like to produce an actual CLI utility using Symfony's Console component, but that is very low on the priority list.
I have also drastically cleaned up the execution path to generate code. You no longer have to do a bunch of looping and w/e other nonsense I used to require, you can now simply do this:
5. Testing
The current suite of tests are not good enough. They rely too heavily on external sources being maintained to function, and in turn make the test output unreliable.
There were also zero tests of the the actual Builder, only its output.
Solution: Multi-facted
Ultimately this is a bit of a Sisyphean feat. It is unlikely I will ever be able to account for all permutations and variations of FHIR server implementations and their variable spec adherence.
I also have very little interest in having every test require some massive Java thing to be spun up per run.
To that end, I have created a little test project over at php-fhir-test. For the moment, it just contains a little test web server that provides a basic "FHIR-like" API, without the need for a database or anything heavier. This will be added to the test suite, enabling me to have a "real" FHIR server to query against without having to rely on 3rd parties keeping their servers up and consistent.
Beta Was this translation helpful? Give feedback.
All reactions