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