Let's talk about
Continuous Delivery
Continuous Delivery is the ability to get changes of all types into production, or into the hands of users, safely and quickly in a sustainable way.
Continuous Delivery is the ability to get changes of all types into production, or into the hands of users, safely and quickly in a sustainable way.
Deploy != Release
Why?
The classic edition
Why?
The classic edition
I. Reduced deployment risk
Why?
The classic edition
II. Believable progress
I'm done! I swear...
Why?
The classic edition
III. More feedback, faster time to market
It's great!
Why?
The classic edition
IV. Enforces high-quality standards
Why?
The classic edition
IV. Enforces high-quality standards
-
Stable codebase
-
Trunk-based development or short-lived branches
-
Easy to release-rollback
-
DevOps culture: good observability, traceability
Why?
XUND edition
Why?
XUND edition
Deployment Issues
Our deployable unit
Why?
XUND edition
Can I see it?
OC! In my machine
Why?
XUND edition
DevOps culture
Observability Issues
The Shadow in The Dark
Spécialité de XUND
AAAAA!
The Medical Device!
Where are we?
Stable codebase
Trunk-based development or short-lived branches
Easy to release-rollback
DevOps culture: good observability, traceability
?
?
?
?
Where are we?
Stable codebase
Trunk-based development or short-lived branches
Easy to release-rollback
DevOps culture: good observability, traceability
Where are we?
Stable codebase
Trunk-based development or short-lived branches
Easy to release-rollback
DevOps culture: good observability, traceability
Easy to release
and rollback
Easy to release
and rollback
-
Low-Risk Incremental Changes
- Only backward-compatible changes
-
Release individual changes
-
Decouple Deployment and Release
- Blue-green deployment
- Dark Launching
-
Feature Toggles
- Optimize for Resilience
Easy to release
and rollback
-
Low-Risk Incremental Changes
- Only backward-compatible changes
-
Release individual changes
-
Decouple Deployment and Release
- Blue-green deployment
- Dark Launching
-
Feature Toggles
- Optimize for Resilience
Easy to release
and rollback
Feature Toggles
Quick & Safe deploy
Deploy half-baked code
Try & Show in production
Feature Toggles
if (await FeatureFlags.isOn("patientIntent")) {
...
}
const { value: isPatientIntentEnabled } = useFeatureFlag(
'patientIntent',
false,
);
...
{isPatientIntentEnabled && <PatientIntent />}
Feature Toggles
FeatureFlags.isOn(
"patientIntent",
{
userId: "ad233-2d34",
environment: "development",
version: "2.32.1"
},
false
))
Feature Toggles
How does it work?
Feature Flag Service
CDN
Add/remove flags
Segment
Deprecate and alert
Cache
Cache
XUND Frontend
XUND Backend
Feature Toggles
How & Where to put?
- Hide from UI (toggle the component)
- Make backward compatible API / Schema changes
- Do not add to paths which shouldn't be reached (eg. UI already hid, no call to API)
- Add close to the change
- Test both execution paths
- Do not toggle refactors (except "dramatic" ones)
XUND Frontend
XUND Backend
Feature Toggles
What do you think?
Feature Toggles
Patient Intent
Feature Toggles
Patient Intent
WebApp
CH Ext BE
CH DB
CH Ext FE
- 3 new tables
- WebApp config change
Admin UI to save/edit questions and answers
- API to save/edit Q/A
- API to save answers
Show Patient Intent questionare
Feature Toggles
Patient Intent
const { value: isPatientIntentEnabled } = useFeatureFlag(
'patientIntent',
false,
);
{isPatientIntentEnabled && <PatientIntent />}
WebApp side
<FlagProvider sdkKey={window.xundEnvironment.flagApiKey}>
...
</FlagProvider>
Feature Toggles
Patient Intent
Client Hub External Backend / Answer API side
Nothing to flip as
/external/patient-intent
is a new API
Feature Toggles
Patient Intent
{ isPatientIntentEnabled &&
<WebAppReportPatientIntentFieldsGroup />
}
Client Hub External Frontend side
Feature Toggles
Patient Intent
export const convertToWebAppEdit: ...) = async (props) => {
[...]
const patientIntentData = await FeatureFlags.isOn("patientIntent") ? {
scReportPatientIntent: data.scReportPatientIntent,
icReportPatientIntent: data.icReportPatientIntent,
} : {}
return {
apiKeyId: data.apiKeyId,
partnerId,
[...],
...patientIntentData
}
}
Client Hub External Backend side
Feature Toggles
Patient Intent
export type WebAppEdit = Omit<
WebApp,
'createdAt' | 'updatedAt' | 'id' | [...]
> & {
scReportPatientIntentQuestion?: PatientIntentQuestionEdit | null
icReportPatientIntentQuestion?: PatientIntentQuestionEdit | null
}
Client Hub External Backend side
Feature Toggles
Integrity didn't find all problems
Feature Toggles
Integrity didn't find all problems
export const bulkCheckIllnessSymptomGroupRelations = async (
relations: IllnessSymptomGroupRelation[],
): Promise<ScIcIntegrityCheckError[]> => {
return [
...(await bulkCheck...PublicationScores(relations)),
...(await bulkCheckUnlockedIllnessesWithLockedSymptoms(relations)),
...(await bulkCheckBodyTagQuestionsOnSymptom(relations)),
]
}
export const bulkCheckIllnessSymptomGroupRelations = async (
relations: IllnessSymptomGroupRelation[],
): Promise<ScIcIntegrityCheckError[]> => {
return [
...(await bulkCheck...PublicationScores(getRelationIds(relations))),
...(await bulkCheckUnlockedIllnessesWithLockedSymptoms(relations)),
...(await bulkCheckBodyTagQuestionsOnSymptom(relations)),
]
}
Before the MR
After the MR
export const bulkCheckIllnessSymptomGroupRelations = async (
relations: IllnessSymptomGroupRelation[],
): Promise<ScIcIntegrityCheckError[]> => {
const publicationErrors = await FeatureFlags.isOn("fixPublication") ?
await bulkCheck...PublicationScores(getRelationIds(relations))
await bulkCheck...PublicationScoresOld(relations)
return [
...publicationErrors,
...(await bulkCheckUnlockedIllnessesWithLockedSymptoms(relations)),
...(await bulkCheckBodyTagQuestionsOnSymptom(relations)),
]
}
With Feature Flag
Feature Toggles
Integrity didn't find all problems
CD @ XUND
By drawain
CD @ XUND
- 21