A developer needs a database.
The cloud provider offers an extensive API covering:
- engine versions
- instance classes
- storage types
- encryption keys
- subnet groups
- network controls
- maintenance windows
- backup retention
- high-availability modes
- deletion protection
- monitoring integrations
One response is to expose all those fields directly:
database:
engine: mysql
engineVersion: "8.x"
instanceClass: provider-specific-medium
storageType: provider-specific-storage
allocatedStorage: 100
backupRetentionPeriod: 14
publiclyAccessible: false
deletionProtection: true
subnetGroupName: bfstore-prod-database
securityGroupIds:
- sg-example
The developer has complete control.
They also need to understand the provider’s database service, network design, security model, backup behaviour and naming conventions before creating an ordinary application dependency.
Another response is to avoid the managed service entirely.
The organisation chooses a generic database deployment that can run in the same form everywhere.
The interface becomes simpler and more portable.
The platform team now owns:
- database installation
- patching
- high availability
- storage
- backups
- failover
- upgrades
- monitoring
- recovery
The provider-native service has disappeared.
Its operational responsibilities have not.
There is a third option.
The platform can expose a smaller product contract:
apiVersion: platform.bfstore.dev/v1alpha1
kind: ServiceDatabase
metadata:
name: catalog
spec:
engine: mysql
profile: transactional-v2
environment: production
availability: multi-zone
recoveryTier: critical-v1
The implementation can still use the provider’s managed database service.
The application team chooses the properties that materially affect its service.
The platform owns the translation into provider-specific infrastructure.
Provider-native architecture does not require a provider-shaped developer experience.
The cloud API remains available to the engineers operating the platform.
Application teams use a product interface built around the outcomes they need.
Native capability and developer usability are not opposing choices.
They become compatible when the abstraction sits at the correct boundary and the promise behind it is precise.
Provider-native is an implementation choice
A platform abstraction is sometimes treated as concealment.
The argument goes:
The provider API is the real API.
Anything placed above it hides important detail.
The provider API is the implementation interface.
It does not follow that every developer should use it directly.
Most organisations already place layers above cloud APIs:
- infrastructure modules
- command-line tooling
- policy checks
- deployment pipelines
- service templates
- documentation
The question is not whether an abstraction exists.
The question is whether it is useful, accurate and operable.
DEVELOPER INTENT
│
▼
PLATFORM PRODUCT
│
▼
PROVIDER-NATIVE IMPLEMENTATION
A useful interface:
- exposes meaningful choices
- applies safe defaults
- explains consequences
- reports status
- preserves ownership
- allows deeper inspection
An unhelpful interface merely renames provider fields:
spec:
cloudDatabaseSettings:
providerDatabaseClass: medium
providerSubnetGroup: private-data
providerBackupWindow: "02:00-03:00"
The YAML belongs to the platform.
The cognitive load still belongs to the developer.
Build a versioned platform contract
A platform should abstract decisions, not vocabulary alone.
Suppose a provider offers six storage classes.
A developer requesting a transactional database may not care which product name is selected.
They may care about:
- expected workload
- availability
- durability
- recovery
- cost
- maintenance impact
The platform can expose those decisions through a product contract:
spec:
profile: transactional-v2
availability: multi-zone
recoveryTier: critical-v1
The platform maps that request to native settings:
transactional-v2
multi-zone
critical-v1 recovery
│
▼
provider database class
multi-zone topology
encrypted storage
backup retention
point-in-time recovery
deletion protection
monitoring
This is useful only when the profile means something precise.
For example:
Profile:
transactional-v2
Availability:
multi-zone
Recovery targets:
RPO 15 minutes
RTO 60 minutes
Backup retention:
35 days
Last restore drill:
2025-10-12
Demonstrated recovery:
18-minute recovery-point gap
52-minute recovery time
Known limits:
one writable primary
regional dependency
Not every property needs to appear in the developer’s request.
It should be available through documentation, status or the operating view.
The platform interface may be small, but the promise behind each field must be precise, versioned and testable.
Profiles need lifecycle rules
A profile is an organisational API.
Its implementation will change.
Suppose transactional-v2 moves to a new storage model or provider service.
That change might cause:
- replacement
- downtime
- cost increase
- changed recovery behaviour
- migration risk
The platform should therefore define:
- profile version
- upgrade policy
- migration impact
- deprecation period
- whether changes apply to existing resources
- how users accept breaking changes
A profile should not silently become a different product while retaining the same name.
Safe defaults should remain ordinary
A developer requesting object storage should not need to remember:
- block public access
- enable encryption
- add ownership metadata
- configure lifecycle policy
- enable audit events
- choose an approved region
The platform can apply those decisions automatically:
apiVersion: platform.bfstore.dev/v1alpha1
kind: ObjectStore
metadata:
name: product-images
spec:
profile: application-assets-v1
environment: production
The native implementation may include:
public access:
blocked
encryption:
enabled
ownership:
catalog-team
lifecycle:
application-assets-v1
audit:
enabled
placement:
approved production region
A policy boundary can reject attempts to weaken mandatory controls.
This is not hiding security.
It is making security the ordinary result.
Preserve the native capabilities that improve the outcome
Provider-managed services can remove operational work the organisation would otherwise perform itself.
For a managed database, that may include:
- infrastructure replacement
- automated backups
- maintenance orchestration
- replication
- failover mechanisms
- service monitoring
- control-plane integration
The provider still introduces native limits and failure modes:
- quotas
- regional availability
- maintenance behaviour
- control-plane outages
- service deprecation
- proprietary recovery paths
- pricing constraints
The platform contract should either absorb those differences or expose the consequences that matter.
Managed does not mean ownerless.
CLOUD PROVIDER
operates underlying service machinery
PLATFORM TEAM
defines and operates the service product
APPLICATION TEAM
uses the capability correctly
and owns service behaviour and data
Native identity can improve the experience
A supposedly portable approach may distribute:
access key
secret key
to applications in every cloud.
The configuration looks consistent.
The operating model is weak.
Applications and teams now need to manage secret storage, rotation, expiry, copying, revocation and accidental exposure.
A provider-native workload identity model can issue temporary, scoped credentials based on runtime identity.
The platform can offer a consistent request:
cloudAccess:
- capability: object-read
resource: product-images
The implementation translates this into the provider’s native trust and permission model.
The developer outcome remains understandable:
This service may read
the product-images resource.
Its authority is temporary.
No static cloud credential
is stored in application configuration.
This creates platform-level consistency in how authority is requested and governed.
It does not necessarily make application code portable.
PLATFORM PORTABILITY
consistent request, provisioning
and governance model
APPLICATION PORTABILITY
the same application API and code
work across implementations
A service may still use provider-specific SDKs, data semantics or failure behaviour.
The platform should promise only the portability it actually delivers.
Network abstractions should describe reach
Application teams do not need to assemble virtual networks, route tables, firewalls and private endpoints directly.
They do need to express communication intent.
network:
exposure: internal
dependencies:
- name: catalog-database
protocol: mysql
direction: outbound
- name: telemetry
protocol: otlp
direction: outbound
egressProfile: restricted-v1
The contract may also need to describe:
- cross-region communication
- data classification
- public fallback
- tolerated dependency failure
The platform translates the intent into native routing, firewall policy, endpoints and DNS.
The abstraction should explain the resulting behaviour:
- the service is not publicly reachable
- only approved dependencies can be contacted
- outbound internet access is restricted
- denied communication leaves evidence
The developer should understand the network contract.
They should not need to choose every route-table entry.
Abstraction must remain inspectable during failure
A platform becomes unhelpful when it hides everything behind:
The platform handles it.
Provider-native implementation should remain visible in layers.
Product view
ServiceDatabase:
catalog
Profile:
transactional-v2
Availability:
multi-zone
Status:
ready
Operating view
Private:
yes
Encrypted:
yes
Recovery target:
critical-v1
Last restore drill:
2025-10-12
Demonstrated recovery time:
52 minutes
Implementation view
Cloud:
AWS
Region:
eu-west-2
Native resource:
managed relational database
Composition:
service-database-aws-v3
Diagnostic view
Authorised operators can access:
- provider resource identifiers
- native events
- network configuration
- service logs
- provider-specific failure details
SIMPLE USER INTERFACE
│
▼
OPERATING PROPERTIES
│
▼
NATIVE IMPLEMENTATION
│
▼
DETAILED DIAGNOSTICS
Abstraction reduces the starting depth.
It does not need to destroy the ladder.
Status should translate without pretending certainty
Provider APIs return errors shaped around their own resource model.
A platform request may fail because:
- quota is exhausted
- a region lacks capacity
- an identity lacks permission
- a dependency is missing
- a selected feature is unavailable
Weak status:
Error:
InvalidParameterCombination
Stronger status:
State:
blocked
Capability:
ServiceDatabase
Reason:
requested multi-zone capacity
is temporarily unavailable
in the selected region
Action:
platform retrying automatically
Owner:
platform-database
The native error should remain attached for diagnosis.
Some provider failures will not translate cleanly.
In that case, the platform should say so:
State:
blocked
Impact:
database provisioning cannot continue
Reason:
unknown provider failure
Correlation:
req-18472
Owner:
platform-database investigating
Translation should add meaning without hiding uncertainty.
Developer experience includes the failure path
A platform may make creation delightfully simple:
Create database:
one form
Then failure requires:
open cloud console
find native resource
identify account
search provider logs
decode error
message platform team
The happy path is abstracted.
The failure path is provider-hostile.
A complete platform product should provide:
- visible progress
- translated status
- correlation identifiers
- relevant logs
- retry information
- remediation
- ownership
- escalation
Developers should not need a cloud archaeology qualification to understand whether the platform is retrying or waiting for their action.
Make limits and alternatives explicit
A product interface cannot support every provider feature.
Specialised needs should leave the standard path deliberately.
Additional product tier
A recurring need becomes a supported profile:
availability: regional-critical-v1
Provider-specific product
A workload deliberately selects a native capability:
kind: AwsStreamingAnalytics
Governed override
An authorised user changes a narrow implementation property:
maintenance:
window: sunday-morning
Overrides should be:
- typed
- narrowly scoped
- validated
- auditable
- visible in support status
- promoted into product fields when they recur
A generic provider-settings map recreates the raw API through a side door.
Fully custom path
A team owns a specialised implementation outside the standard platform product.
STANDARD PATH
platform owns implementation
EXTENDED PATH
shared ownership
CUSTOM PATH
workload team owns more
provider-specific operation
The platform should distinguish:
unsupported
from:
forbidden
and:
supported through a different product
Portability should name the required property
Using a provider-native service creates dependency.
That dependency should be understood rather than denied.
“Portable” may refer to different things:
DATA PORTABILITY
Can state be exported
in a usable format?
APPLICATION PORTABILITY
Can the application use
another implementation?
CONTROL-PLANE PORTABILITY
Can the capability be provisioned
through another provider?
OPERATIONAL PORTABILITY
Can teams monitor, recover
and support the replacement?
IDENTITY AND NETWORK PORTABILITY
Can trust and communication
be rebuilt safely?
Not every capability needs every form of portability.
For each product, the platform can record:
- provider
- data format
- export path
- migration constraints
- required movement time
- tested recovery route
- criticality
- exit-plan level
Provider native does not have to mean permanently trapped.
It means portability is designed and tested at the level justified by the service.
Ownership and expertise make the abstraction credible
Provider documentation explains the underlying service.
Platform documentation should explain the organisational product:
- who should use it
- which profiles exist
- what each version promises
- which limits apply
- how credentials are delivered
- how cost changes
- who owns failure
- which provider-specific differences remain
- how upgrades and exits work
The platform should link to native documentation where deeper provider behaviour matters.
PLATFORM DOCUMENTATION
how our product behaves
PROVIDER DOCUMENTATION
how the managed service works
Both are useful.
They answer questions at different layers.
The platform team still needs native expertise.
Somebody must understand provider identity, lifecycle, networking, quotas, pricing, backup behaviour, failure modes and upgrade paths.
APPLICATION TEAM
understands the platform contract
PLATFORM TEAM
understands the product
and its native implementation
A thin layer over a poorly understood cloud service is not a platform product.
It is a confidence wrapper.
The contract becomes trustworthy when its owners test the promises it makes.
A bfstore provider-native path
Suppose the bfstore review service needs:
- a MySQL database
- Kafka access
- private networking
- workload identity
- telemetry
The application declaration may be:
apiVersion: platform.bfstore.dev/v1alpha1
kind: Application
metadata:
name: review-service
spec:
runtime: go
protocol: grpc
exposure: internal
database:
profile: transactional-mysql-v2
availability: multi-zone
recoveryTier: standard-v1
messaging:
consumes:
- order.completed
publishes:
- review.submitted
cloudAccess:
- capability: review-storage-read
network:
dependencies:
- name: review-database
protocol: mysql
- name: telemetry
protocol: otlp
The AWS implementation may provide:
- native workload identity
- a managed MySQL service
- private networking
- provider-specific storage
- cloud audit events
- OpenTelemetry integration
An Azure or Google Cloud implementation may use a different resource graph.
The platform contract remains coherent, but not necessarily identical in every property.
The product should publish which promises are portable and which differences remain provider-specific.
REVIEW SERVICE INTENT
│
▼
VERSIONED BFSTORE CONTRACT
│
▼
AWS-NATIVE IMPLEMENTATION
│
▼
VISIBLE STATUS AND EVIDENCE
No one needs to pretend the implementation is provider neutral.
The developer also does not need to assemble it manually.
Questions I now ask
Outcome
Which outcome does
the developer need?
Choice
Which decisions materially
affect the service?
Contract
What exact, versioned promise
does the platform make?
Native value
Which provider capability improves
security, reliability or operation?
Understanding
Can behaviour, cost, limits
and failure be understood?
Inspection
Can operators reach
the native evidence?
Escape
Which alternative path
and ownership model apply?
Portability
Which portability property
must be tested?
These questions separate a useful provider-native platform from a cloud console wearing a developer-portal hat.
The mental model I am keeping
My earlier model was:
PROVIDER NATIVE
developers use provider APIs directly
The stronger model is:
DEVELOPER INTENT
│
▼
VERSIONED PLATFORM PRODUCT
│
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
SAFE DEFAULTS MEANINGFUL CHOICES GUARDRAILS
│ │ │
└─────────────────┼─────────────────┘
▼
PROVIDER-NATIVE FULFILMENT
│
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
IDENTITY NETWORK DATA
│ │ │
└─────────────────┼─────────────────┘
▼
STATUS AND EVIDENCE
│
▼
TESTED PRODUCT PROMISE
Provider-native architecture becomes developer-hostile when the platform exposes raw cloud complexity without helping users make sense of it.
It can become equally hostile when an abstraction hides every consequence and turns failure into a support ticket.
The useful middle is a platform product that preserves native capability while translating it into:
- meaningful choices
- precise contracts
- safe defaults
- visible behaviour
- understandable status
- clear ownership
Developers do not need every provider field. They need a reliable way to request an outcome, understand its important properties and diagnose where the promise has failed.
The cloud-native implementation can remain rich.
The developer interface can remain small.
Those ideas are not in conflict.
The platform’s job is to build the bridge between them without painting over the signposts.