Design Principles—Modern App Development

Best practices that govern application architectures.

 

Open all Close all

    • Use low-code platforms if possible; if not, use mature programming languages and lightweight frameworks

      Overview
      The programming languages and frameworks that you adopt to build your app play a pivotal role in your app’s successful delivery and maintenance over time. Language and framework choices have long-term consequences for how you scale your business, operate your app, and deliver high-quality features to your customers. Changes to either language or framework are typically expensive. Supporting parallel ecosystems of multiple languages and frameworks adds complexity and reduces agility.

      The choice of language and framework has an impact on a range of factors, including delivery speed, stability and strength of the existing ecosystem, operational readiness, and production performance. Use low-code platforms where possible so that you can focus on solving your business problems instead of confronting the complications of traditional development. If your app’s requirements are more complex, choose mature languages and lightweight frameworks.

      Principle details
      Low-code platforms enable you to build, test, and deploy enterprise apps faster than traditional manual coding. These platforms are well suited for building opportunistic apps in collaboration with business stakeholders as well as data reporting and analysis apps. Low-code platforms also enable you to extend SaaS apps and modernize legacy apps. This approach helps you avoid complications when you want to add new capabilities, such as data visualization, data collection, data analytics, security, accessibility, performance, and globalization. A low-code platform significantly alleviates these complications and dramatically reduces the amount of code you maintain.

      However, if your app has more sophisticated requirements, choose a mature programming language coupled with a lightweight framework. When choosing a programming language, select one that provides you with key benefits, such as:

      • Security
      • High performance and efficiency
      • Tooling support
      • Extensive, up-to-date documentation
      • An ecosystem of libraries
      • Compliance to a test suite or reference implementation
      • A strong community

      Newer languages tend to have a higher rate of change in their language design and corresponding ecosystem and libraries. A higher rate of change means that it is more difficult to evaluate risk and more expensive to make subsequent changes.

      When choosing a framework, select one that is open source. Open source frameworks are under constant peer review, which means that the features are close to what most developers want because they contribute to the frameworks’ creation and maintenance. Bugs are found and fixed quickly. You also want to select a lightweight framework that consumes few resources, such as CPU, memory, network bandwidth, or file handles.

      Use an app framework that balances improving task focus (business logic over boilerplate and scaffolding) with flexibility (allowing you to support current and future feature needs). Adopt a framework that provides easy-to-consume, sensible, and uncontroversial defaults for common features, such as logging, telemetry, security, configuration, as well as for common patterns, such as building REST APIs.

      Oracle recommendations
      Oracle APEX is a low-code platform that provides you with high-level components, such as forms, charts, and UI widgets. APEX also provides common design patterns through an intuitive graphical development environment. Apps developed using APEX can access local data via SQL and integrate with external services using REST APIs. Additionally, you can publish the functionality you develop in APEX as REST APIs for external consumption.

      If a low-code platform is inappropriate for your app, adopt Java as your programming language. Java provides a stable and broad set of capabilities for most common app use cases and has a healthy ecosystem of trusted and stable libraries and frameworks for developing modern apps. Java's focus on simplicity and readability coupled with its excellent support for developer tooling—including static analysis tools and testing frameworks—reduce software maintenance costs and the risk of bugs in production apps.

      Use GraalVM to develop and run your app. GraalVM is a JDK distribution that couples the stability of Java with best-in-class performance through dynamic runtime optimization, frequent and proactive patching of security vulnerabilities, and low-cost performance analysis and diagnostic tooling, such as Java Flight Recorder.

      Build your app with an API-first approach using either Graal Development Kit for Micronaut or the Helidon framework. Both approaches provide scaffolding that significantly reduces the time to deliver your app and easy-to-use patterns for common use cases, such as REST APIs, based on a set of simple, uncontroversial framework choices for common activities, such as logging, telemetry, and storage. Additionally, both approaches support high-performance services, through support for nonblocking I/O with idiomatic reactive APIs, and low latency, through support for high-performance network libraries.

      • Choose Helidon MicroProfile for apps that are closely aligned with the enterprise Java ecosystem, for example, CDI, JAX-RS, or JPA. Helidon's standards-first support for modern Java enterprise patterns through MicroProfile simplifies the porting of existing Java EE apps to microservices.
      • Choose Graal Development Kit for Micronaut (GDK) or Helidon SE or Helidon SE for apps that aren’t dependent on the existing enterprise Java ecosystem. GDK's compile-time application scaffolding increases app performance at runtime and enables framework-level checking, which can eliminate many security and quality issues relating to reflection and runtime configuration.

      Both Helidon and GDK have built-in support for GraalVM native image, which enables you to build memory-efficient and compact apps.

    • Build your app as a suite of services that communicate via REST APIs

      Overview
      Split your app’s features or tasks into independent, loosely coupled services that work in conjunction with each other. Design each service with a limited functional scope that focuses on one feature or capability. In comparison to a traditional monolithic architecture, this approach improves app maintenance, feature development, testing, deployment, and scalability.

      Take a contract-first REST API design approach to provide clear and understandable interfaces for communicating with and between services. An API contract provides the necessary mechanism for teams to collaborate and consume functionality without depending on the internal details of a service’s implementation. For example, a service can be wholly owned by a development team that can freely improve on its implementation without having to coordinate code dependencies with other development teams.

      Principle details
      Begin with a contract-first approach by specifying the REST API of a service. Then prototype an implementation of the API to let your stakeholders, such as the teams who will use it, try it out. When everyone agrees on the details of the API, independent teams can work in parallel to implement the service and other services that will consume it.

      Define your policy enforcements for security and service level agreements early in your product lifecycle to ensure that everyone is clear on all aspects of the service contract.

      Treat your API specification as code and manage it in a version control system along with your source code and policy configurations.

      Oracle recommendations
      Specify your API using the implementation-agnostic format OpenAPI and store it in a repository provided by Oracle Cloud Infrastructure (OCI) DevOps.

      Implement your services using a lightweight open source approach, such as Graal Development Kit for Micronaut or Helidon.

      Deploy your services on serverless platforms, such as Oracle Container Engine for Kubernetes or Oracle Functions, for ease of deployment, scalability, and cost efficiency.

      Use Oracle Cloud Infrastructure API Gateway to create protected and governed private or public endpoints from the API specification.

      Use Oracle Cloud Infrastructure Service Mesh to simplify and secure communication between services hosted in your Oracle Container Engine for Kubernetes cluster. OCI Service Mesh also allows you to observe all network traffic between your services via the metrics and logs emitted by its proxy component that runs as a sidecar on application pods.

    • Package and deploy your app as containers

      Overview
      A container packages code and its dependencies as one unit, so an app runs quickly and reliably across multiple computing environments. A container image is a file that, when executed, will create and start a container on a computing environment.

      Compared to traditional virtual machines, containers are smaller, require fewer resources, and have faster start times. They are also platform independent and can run apps anywhere. To take advantage of these benefits, decompose your app into services that each perform a discrete business function and package each service as a container. For legacy apps, gradually replace each existing function in your app with a containerized service until the whole app is refactored.

      Principle details
      Packaging application code and dependencies into a single executable unit (a container image) means that a container is extremely portable. By combining this portability with infrastructure abstraction, containers bring operational consistency to your app. Whether your app is running on-premises on a physical server or in the cloud on a virtual machine, it produces the same results every time.

      Through this consistent reproducibility and predictability, containers simplify DevOps processes and enable your development teams to deploy your apps faster. By providing process-level isolation, and because they’re frequently replaced, containers simplify and expedite the processes associated with remediating software vulnerabilities. Breaking down apps into modular containerized services also makes them very robust. An error or failure in an individual service doesn’t bring down your entire app, and you can update or patch each service independently from the rest of the app.

      Unlike a virtual machine, a container doesn’t come with an operating system of its own; instead, it shares the operating system of its host. As a result, containers are smaller in size and faster to start than virtual machines. Most container images are tens of megabytes in size compared to virtual machines that can be several gigabytes, and their start times are in seconds instead of the minutes it takes to start virtual machines.

      The best way to run and scale your app with modularized services in containers is to deploy one service per container. This approach isolates services from each other, which eliminates downtime and enables independent scaling for each service.

      Although you can deploy containers manually, it’s better to use container management software that integrates with your continuous integration and continuous deployment tools.

      Oracle recommendations
      Use Oracle Cloud Infrastructure Registry (Container Registry) to store your container images and Oracle Cloud Infrastructure Container Engine for Kubernetes (OKE) to run and manage your containers. These fully managed services are tightly integrated with OCI platform capabilities, are available in all Oracle Cloud regions, and meet regulatory standards, such as PCI, ISO, SOC, HIPAA, and FedRAMP.

      In addition to storing container images in Container Registry, you can store manifest lists (sometimes called multi-architecture images) to support multiple architectures, such as ARM and AMD64. To identify and mitigate potential security vulnerabilities, enable image scanning on all images uploaded to Container Registry. You should also sign your container images to ensure that only authorized and trusted images are deployed to OKE.

    • Automate build, test, and deployment

      Overview
      Continuous integration (CI) and continuous deployment (CD) are a set of tools and procedures that development teams use to deliver code changes frequently and reliably. CI/CD best practices include code reviews, guidance for unit testing, integration testing, code check-ins, filing tickets, and deploying applications to development and test environments.

      Continuous integration describes a practice in which developers frequently integrate their code changes into the main branch of a shared repository. The developers’ changes are validated by creating a build and then running automated tests against the build. The tests ensure that your app is not broken whenever new changes are integrated into the main branch.

      The advantages of continuous integration include:

      • Fewer bugs get shipped to production because automated tests identify regression failures early
      • Integration issues are solved early, making the build process easier
      • Errors are detected and located faster and more easily (as each change is typically small)

      Continuous delivery is a step beyond continuous integration; after passing the appropriate tests, a build is automatically delivered to a testing and/or production environment. The goal of continuous delivery is to always have a codebase ready for deployment to a customer production environment.

      Additional advantages of continuous delivery include:

      • Automation of complex deployments means that your team spends less time preparing for a release
      • More frequent releases, accelerating your customer feedback loop
      • Faster iteration because there is less pressure on decisions for small changes

      Continuous deployment goes one step further than continuous delivery; every change that passes all the tests is automatically deployed to your customer production environment. There is no human intervention—only a failed test can prevent a new change to be deployed to production. With no human intervention, continuous deployment relies heavily on well-designed test automation.

      Additional advantages of continuous deployment include:

      • Increased speed of development because there’s no need to pause for releases
      • Increased customer satisfaction thanks to enhanced quality and a continuous stream of improvements

      CI/CD provides best practices for storing, integrating, deploying, and maintaining code to automate how you build your apps. These best practices include the following:

      • Apply the "shift-left" paradigm and focus on detecting and preventing issues as early as possible in the software development lifecycle (SDLC). For example, monitor the third-party dependencies of your app for vulnerabilities during continuous integration.
      • Use a Git-based code repository to store all your code assets.Use an immutable artifact service to store derived assets.
      • To implement continuous integration, merge all code into a “release candidate” branch at least once a day. When you merge code into that branch, ensure that builds are automatically triggered. As part of the build pipeline, run all unit tests and immediately fix any pipeline failures before undertaking further development in the release candidate branch. Use security scans on the code to detect vulnerabilities. Don’t store any artifact that has a vulnerability issue. Fix all vulnerabilities in the release candidate branch before further development.
      • To implement continuous deployment, automatically deliver release candidates to a test environment or use canary deployments. When test deployments pass, automatically promote them to full production. If test deployments fail, immediately resolve the issues before undertaking further development in the release candidate branch. Use security features as part of deployments to prevent unauthorized and vulnerable artifacts from being deployed on the infrastructure.
      • In the production environment, use monitoring tools to assess the health of the deployed apps and detect any post-deployment vulnerabilities. If any issues are detected, implement automatic rollback to the previous version. Perform security checks in the post-deployment environment and immediately resolve any issues that are detected.

      Oracle recommendations
      Use the DevOps service to automate deployment of your cloud native apps. First, store the code in a DevOps code repository and create a release branch. Work in small increments to make changes to the release branch and reconcile issues in the branch daily to ensure its stability. Then use the triggers functionality in the code repository to automatically start a DevOps build pipeline.

      Use a single DevOps build pipeline to build all artifacts associated with the code repository. If the build fails, configure the build pipeline to wait for approval before it completes. The approval request should go to the committer who triggered the build, and they should resolve the issue with a new code commit and then approve the completion of the build. For successful builds, configure the build pipeline to automatically deliver the artifacts to the Oracle Cloud Infrastructure Artifacts Registry service and to automatically trigger a DevOps deployment pipeline.

      Add Application Dependency Management to detect security vulnerabilities (CVEs) in application dependencies during a build stage in an OCI DevOps build pipeline. This way, you will be able to detect and remediate potential CVEs as soon as they become known.

      Use Resource Manager to create all your infrastructure environments in a maximum-security zone to automatically benefit from deployment security. By using Resource Manager, you can use infrastructure as code to automate infrastructure creation across all your regions in a consistent manner. Then you can configure the DevOps deployment pipeline to always deploy to the resources that you have created in the security zone.

      Create a single DevOps deployment pipeline that deploys all the artifacts created from a single build pipeline. Organize deployment environments, such as OCI region, availability domain, and fault domain. Configure the pipeline with a canary, rolling, or blue-green deployment strategy. Also configure it to trigger tests automatically. Enable OCI Monitoring and Application Performance Monitoring on your application and infrastructure to detect issues.

      If no issues are detected and tests complete successfully, configure the deployment pipeline to automatically deploy the artifacts to the next environment in the deployment strategy until the artifacts are fully deployed in all production environments. When deploying to the production environment, configure the pipeline to deploy to all fault domains in an availability domain one at a time. Deploy to each availability domain in a region one at a time, and then, to each region one at a time. Continue to use OCI Monitoring and Application Performance Monitoring on the application and infrastructure to quickly detect issues. Set up alerts, and if any key metrics suddenly drop during deployment, automatically fail the deployment and trigger a rollback to the previous version.

    • Use managed services to eliminate complexity in app development and operations

      Overview
      A managed service provides specific functionality without requiring you to perform maintenance tasks related to optimizing performance, availability, scaling, security, or upgrading. With a managed service, you can focus on delivering features for your customers instead of worrying about the complexity of operations.

      A managed OCI service provides a scalable and secure component for cloud native development. Use managed services to develop and run your app and store its data; you get best-in-class solutions without needing expertise in each domain to build and operate your app.

      Principle details
      Managed services enable you to create highly available, scalable, agile, and performant applications with security, compliance, and resiliency.

      Managed services abstract the complexity of your app’s underlying components, making it easy to store and retrieve data or create and run your app. The services integrate with toolsets that provide automated building, testing, and deployment of your app. Managed services improve productivity and reduce time to market.

      Managed services centralize and automate various infrastructure management tasks, removing human error and the need for specialized skills. The underlying infrastructure is kept up to date and secure, and the services enable you to monitor and track modifications or access, which ensures the confidentiality and integrity of your app and data.

      Managed services are highly available and scalable, meeting the needs of your app, and you pay only for what you use. You can start small and scale without experiencing any degradation in performance or reliability.

      Oracle recommendations
      We recommend the following cloud services:

      • Oracle Autonomous Database to manage data for data warehousing or transaction processing. Autonomous Database offers in-memory, NoSQL, and SQL databases with an autonomous advantage to reduce management overhead.
      • Oracle Cloud Infrastructure Container Engine for Kubernetesto create, run, and manage your containers.
      • Oracle Functions to create, run, and scale apps that run for short durations in a secure and isolated manner, without managing any infrastructure.
      • Oracle API Gateway to create protected and governed private or public endpoints from your API specifications.
      • Oracle Cloud Infrastructure Object Storage to safely and securely store or retrieve an unlimited amount of unstructured data of any content type. It scales seamlessly, without experiencing any degradation in performance or service reliability.
      • Oracle Cloud Observability and Management Platform services integrate with all the above services to enable visibility into logs, metrics, and events.
      • Oracle Application Express (APEX) to quickly build low-code, modern, data-driven applications. APEX can maximize availability and scalability to handle the changing demands of your low-code app. It provides automated management, consistent high performance, automatic scaling, and easy administration.

      These services are highly available, high performing, and elastic. Their underlying infrastructure is managed and patched to ensure that your app remains secure.

    • Keep app tier stateless

      Overview
      An app’s state can consist of many elements, including data caches, a user’s preferences, personalization, messages exchanged between services, the position in a multiple-step workflow, app deployment, runtime configuration, and a user’s session (for example, the page a user last visited or the size and items in a user’s shopping cart). If the state of your app is lost, it can result in loss of data, a malfunction in your app, a suboptimal user experience—and sometimes, a complete app failure.

      If you store your app’s state on local file systems or in the memory of a single host, then it might be lost if your app experiences outages, such as restarts or localized disk failures. Instead, save the state in external persistence stores. Use as few persistence stores as possible; ideally, just one to provide data consistency.

      Principle details
      The elements of an app’s state are traditionally stored as multiple artifacts in various formats, such as serialized objects, JSON or XML documents, or text files. If these elements are stored across multiple persistence stores, such as external file systems, message stores, object stores, multiple databases, or elastic block storage, then it’s possible for the different data stores to get out of sync and result in state inconsistencies. An app must also implement transactions, joins, and idempotency to ensure data consistency when the state needs to be updated as a unit.

      By scattering elements of an app’s state across multiple stores, the opportunities increase for security vulnerabilities. Lifecycle operations—such as adding and removing nodes, patching, backup and recovery, and replication for disaster and recovery—become extremely complex and require special consideration to keep state consistency across different stores.

      As a result, a better approach is to store all the app’s state and its data in a single database, if possible. Data stays consistent in a single store and is easier to manage. With this approach, app instances can be replaced. This especially helps with modern app architectures, such as elastic microservices or ephemeral instances where an instance exists only for serving a single or a few requests. Adding a node is simplified because a new node can get the latest copy of the state—and removing a node doesn’t result in losing the state entirely. Patches can be applied in a rolling fashion just by replacing the executable(s). A node can be restored from backups and acquire the state from the database. State can be consistently replicated as a unit to different regions for disaster recovery. Having a consistent state in different regions can ensure there won’t be any functional problems in your app after a failover or switchover.

      Oracle recommendations
      If your app uses a database, use the same database to store its state. A database provides better availability, integrity, and security than alternatives, such as files or in-memory representations. Ideally, use a multi-model database (which can store different formats) to store all the elements of your app’s state. Using a multi-model database instead of multiple single-purpose data stores also lets you easily achieve and maintain consistency across all the elements of your app state. (Note: Although it’s permissible to store cached state in the app, the app must be designed to use the database as the source of truth and be able to recreate its state from the database.) Oracle Database is an ideal fit for this purpose. It stores different formats and provides predictable performance, so storing your app’s state in it doesn’t degrade the performance of your app.

      If your app doesn’t use a database, use other durable persistence stores, such as Oracle Cloud Infrastructure Object Storage, to store the state. If the app state can’t be kept in a single data store, design your app to store the state in multiple data stores that can be kept in sync and recovered as a consistent unit after failure.

      Here are some recommendations for storing state in an Oracle Database.

      • User session object state: Use JSON object/relational mapping, such as JPA, or relational tables.
      • Local data caches: For data cached in the app tier, the source of truth should be database. The caches should be rebuilt at app startup time or as needed. Updates to the caches should use the write-behind method, which updates the back-end database. Other instances of cache in app instances should be notified of the changes so that the caches can be refreshed.
      • App configuration data: These are artifacts, such as connection endpoints, limits, logging levels, log destinations, and port numbers that are typically stored as JSON documents, XML files, or properties files. Use the appropriate data type to store this data in a database.
      • Interprocess communication or remote process calls: Typically, application microservices and components communicate with each other using messages. Use Oracle Database transaction queues to make such messages durable and to ensure that messages survive and are processed if an outage occurs.
      • Text (such as audit log records): Apps generate log files, such as audit logs and diagnostic logs. Use Oracle Text functionality to centrally store such logs.
      • Performance monitoring: Apps generate metrics or time-series data for performance monitoring purposes. Use Oracle Database time-series data or JSON data functionality to store such data.
      • Workflow state: Some workflow engines store an app’s state locally, and the failover of such workflows can result in a lost state. Use the workflow engine in the database to avoid such issues. At minimum, configure workflow engines to use the database as a persistence store for its state.
    • Use a converged database with full-featured support across all data

      Overview
      Your app might use data in a variety of formats, such as tabular (relational), unstructured, XML, JSON, spatial, or graph. Traditionally, this variety required a different kind of database for each data format. For example: a relational database for relational data, a document store for unstructured data, or a graph database for hierarchical linked data. However, the use of multiple databases often leads to additional operational complexity and data inconsistency. Instead, use a single, multi-model database to store, index, and search multiple types and formats of data.

      Take advantage of database functionality to simplify your app logic. For example, use SQL for queries, joins, and analysis; use transactions to guarantee consistency and isolation; and use built-in machine learning algorithms and analytics capabilities to avoid unnecessary data transfers. To protect sensitive data, use the database’s security features and access control, and use replication to improve the availability, scalability, and resiliency of your apps.

      Principle details
      Use a multi-model database to store different types of data, such as JSON documents, property graphs, and relational data. Advanced multi-model databases offer full-featured support for any type of data stored in the database. You can store a new JSON document, insert relational rows, and update a property graph all within the same ACID transaction. You can use SQL statements to join, filter, and aggregate across these different types of data—this provides the strong consistency and concurrency guarantees that you’re accustomed to from relational databases. Along with offering this rich set of features, a multi-model database can also be used as a single-purpose data store—accessed using APIs other than SQL, such as REST APIs, document store APIs, and graph APIs.

      A key advantage of using a multi-model database is its reusability. Although data might be of different types and shapes, the underlying technology to manage that data doesn’t change. This means that you don't have to learn multiple database technologies and understand how to use and tune each one for each type of data. And because the technology remains constant, you don’t have to rewrite your app code. Also, a multi-model database improves the resiliency of your app by reducing data fragmentation, thus making backup and recovery easier.

      Oracle recommendations
      Use Oracle Autonomous Database, a multi-model converged database, to store, manage, and analyze all your data. Ease the maintenance of your app by using views to expose the data in tables so that the underlying schema can be changed without affecting your existing apps. Use edition-based redefinition so that you can upgrade your app with no downtime. Use Oracle Data Safe to implement and evaluate security controls, mask sensitive data, and audit data accesses. Use Oracle Data Guard as a highly scalable read cache for your data and to maintain a consistent backup for disaster recovery.

      Oracle Autonomous Database performs operational tasks with no impact or interruption to its workload. This means that you don't need to add complex compensational logic to the app to handle scaling or failover scenarios. The database manages resources, such as CPU and storage, independently and provides elastic bidirectional scalability.

    • Instrument end-to-end monitoring and tracing

      Overview
      A single user request can follow a complex path across the multiple services or microservices that make up a modern app. End-to-end tracing follows the journey of each request from its source into the depths of your infrastructure and helps you to debug the root cause of a problem. Monitoring is generally used as a diagnostic tool, alerting your developers when your app isn’t working as expected.

      Developers, administrators, and security officers must maintain an authoritative and timely understanding of your app’s health, performance, operational state, and possible security incidents. This understanding ensures that your app’s function and performance meet expectations during its lifecycle; it can also streamline incident diagnosis and application recovery. Comprehensive, end-to-end monitoring and tracing should be straightforward to implement and manage without adding complexity to your app.

      Principle details
      Your app can fail to behave as expected in numerous ways. For example, it can perform poorly or just fail outright. Unlike a traditional monolithic app, an app built from microservices presents additional diagnostic challenges because of multiple interactions between its components.

      Tracing is the best way to quickly understand what happens to a user request as it travels through the microservices and other components, such as infrastructure, that make up your app. Use end-to-end tracing to collect data on each user request and then review the data to see where your app may be experiencing bottlenecks and latencies. For example, a request may pass back and forth through multiple microservices before being fulfilled. Without a way of tracing the entire journey of a request, there is no way to determine the root cause of its failure.

      Monitoring is generally much more directed, improving your understanding of how your app behaves by instrumenting your app and then collecting, aggregating, and analyzing metrics. End-to-end monitoring also allows intelligent and automated integration with tools that dynamically adjust resource capacity and coordinate responses to unexpected events.

      Having a clear, accurate, and timely understanding of an app’s operational state and history is not just about measuring an end user's experience. You may also need to maintain compliance with regional or national jurisdictions which might require the ability to generate on-demand, detailed activity reports or attestations about the handling of specific, sensitive data elements.

      In general, monitoring solutions should be compatible with third-party tools and align with your environment’s administrative tools in particular. It’s important to maintain design flexibility and avoid vendor lock-in.

      Oracle recommendations
      Build comprehensive monitoring and tracing capabilities into your app from the outset and keep them consistent throughout its lifecycle. The capabilities should not add any complexity to development, testing, and deployment and be easy to implement and manage. Where possible, adopt solutions that extend to accommodate the diversity of platforms that you currently use and might deploy in the future.

      OCI services, such as Monitoring, are designed to provide out-of-the-box support for monitoring. Also, you can extend many OCI services to your app components by using a consistent deployment and management experience through supported APIs and SDKs. For example, you can add automated monitoring metric collection or log capture with centralized storage for all your virtual machines and apps.

      During development and testing, you can configure services to only collect basic debugging or performance testing information. As your app approaches production deployment, increase the scope, frequency, and traceability of information collected by making simple updates to existing configuration parameters.

      Oracle Cloud Infrastructure Service Mesh automatically captures a variety of communication metrics and logs for services running in Oracle Container Engine for Kubernetes. You can use this data to track the health of your services in the mesh and improve application performance.

      Use robust, centralized data collection for your entire cloud tenancy environment to provide a single location for analysis, coordinated investigation, and alert generation. Service Connector Hub enables flexible, consistent, and customizable responses to events. OCI Logging Analytics enables efficient analysis and investigation of all your cloud (and external) event logging systems. You can also use OCI Service Connector Hub, Functions, and Notifications to transform ingested metrics and logs into actionable alerts. And you can take advantage of our integrations with third-party products and services, such as Splunk and Grafana.

      The following OCI services help you consolidate your logging, monitoring, and tracing across the environments that host your app: Logging, Monitoring, Logging Analytics, Application Performance Monitoring, OS Management, Database Management, and Java Management Service. These fully managed services are integrated with common OCI infrastructure resources and provide supported mechanisms to integrate your custom app resources.

    • Eliminate single point of failure through automated data replication and failure recovery

      Overview
      A single point of failure is one component of an app which, upon failure, renders your entire app unavailable or unreliable. When you develop an app to be highly available and reliable, use automated data replication to ensure that the failure of a single component does not lead to data loss.

      Data replication across machines and the use of redundant networking protects you against routine machine and network failures. Replicating your data in data centers (or “availability domains”) across multiple geographical regions protects you against localized disasters, such as fires, earthquakes, floods, or hurricanes.

      Principle details
      For your app to achieve high availability, you must ensure that the data on which your app depends remains available when failures occur. The key to the high availability of data is redundancy via automated data replication.

      Replication is the process of copying and maintaining database objects, such as tables, in multiple databases that make up a distributed database system. Changes applied at one site are captured and stored locally before being forwarded and applied at each of the replicas located at remote locations.

      Replicated databases can function in two different modes: active-passive and active-active. In active-passive mode, there is a single primary replica and one or more secondary replicas; only the primary replica participates in app data processing. In active-active mode, all replicas participate in data processing. Active-active mode provides better resource use and higher availability because no primary-secondary failover is needed.

      Redundancy ensures that data replicas fail independently. Machine or disk failures are typically independent, but a network or power failure might cause a group of machines to fail simultaneously. To protect against such incidents, network and power infrastructure should also be redundant, and data replicas must be carefully placed across different machine and locations that can’t fail together.

      Oracle recommendations
      OCI data centers are carefully engineered to eliminate single points of catastrophic failure. A typical data center or availability domain contains multiple independent failure units known as fault domains. Two independent fault domains can’t fail together. Likewise, a single region might have multiple availability domains which are geographically separated to ensure that two of them can’t fail at the same time.

      Use OCI storage services, such as Block Volumes, Object Storage, and File Storage, to replicate data across fault and availability domains so that no single point of failure can impact the availability of your app’s data. Take advantage of the resilient fault isolation built into OCI by using Container Engine for Kubernetes to deploy your app across multiple fault and availability domains. Oracle Autonomous Database, Data Guard, and GoldenGate provide active-active hardware and software replication for high availability as well as zero-downtime patching and upgrades. Use these managed services for highly available data without the need to build and maintain your own storage infrastructure.

    • Implement automated defense in depth to secure your app and its data

      Overview
      Defense in depth is an approach where multiple, independent, redundant security controls act as layers of defense for an app. The layers are designed to provide security even if one of them fails, for example, a firewall combined with intrusion detection.

      However, the manual management and configuration of security controls can be complex, opaque, and error prone—individually and collectively. Instead, secure your app and its data by using automated security controls.

      Principle details
      Defense in depth manages risk by using diverse controls that cover the physical, technical, administrative, operational, personnel, and procedural elements of security. Their independence means that they provide a deep defense that handles failures, exploits, or other security vulnerabilities. The controls are designed to approach risks in different ways and provide logging, auditing, and other features to ensure that attempted security violations are detected and reported to appropriate stakeholders.

      Rather than having to manually configure a complex set of security controls, use simple and prescriptive automated controls to secure your app. Automated security controls eliminate human error (a root cause of many security incidents) and help you secure your app and its data without requiring you to become a security expert.

      Oracle recommendations
      Implement easy-to-use automated security controls in all stages of your app lifecycle, including development, build, test, deployment, and runtime. Verify users, permissions, and access policies at each step in the lifecycle and ensure that access is granted only when appropriate. Detect security issues that are introduced early in the software development lifecycle. Early detection ensures that your app is deployed in production with security architecture best practices and that operational security issues caused by misconfigurations or disclosed vulnerabilities are detected and mitigated.

      OCI offers multiple automated security services to secure your app and its data. Here are some recommendations for using OCI services:

      • Use a web application firewall (WAF) to limit traffic from unknown locations. For transport layer security (TLS), use certificates for load balancers and autorotation. Enable the WAF on every load balancer that serves HTTPS content. Enable Oracle-managed rules and tune for false positives. Limit traffic from countries that you don't do business with using geo-IP access rules. Use threat intelligence in your WAF to block Tor nodes
      • Use Oracle Cloud Infrastructure Identity and Access Management (OCI IAM)for an identity-first approach to security that enables easy onboarding and management of users. Use OCI IAM on your app’s front end to authenticate users with strong authentication methods while maintaining an optimal user experience through context-aware adaptive security, optional social or federated logon, or password-less authentication (depending on requirements). Support regulatory requirements by enabling users to manage their consent for terms of use and by supporting data residency requirements. Use OCI IAM on the back end to restrict access to your app’s components as needed. Enforce authentication for administrators through strong multifactor authentication (MFA) options. Enforce strong security policies that allow access only through explicitly granted permissions. Separate responsibilities so that access is limited to those who need it.
      • Encrypt data at rest with keys stored in OCI Vault, backed by hardware security modules. You might prefer to use separate encryption keys for each service, but align OCI Vault entities with compartments. Rotate master encryption keys at least annually and data keys every three months. Use a private vault in production and replicate keys in secondary regions. Create backups and store them in Oracle Cloud Infrastructure Object Storage in a separate region. Secure encryption keys and restrict access to keys only to those authorized by the app owner.
      • Use built-in security principals to authorize compute instances to perform actions on other OCI services.
      • Enforce the principle of minimum reachability to endpoint isolation by using the network security groups feature in OCI virtual cloud networks (VCNs). Enable NetFlow logging on every VCN. Monitor DNS logging for cryptomining activity or command and control server activity.
      • Launch your app in a secure-by-default configuration by using Oracle Security Zones. Use maximum security zones for compartments with private subnets. Ensure that operator access to any compute instances in private subnets goes through Oracle Cloud Infrastructure Bastion.
      • Enable Oracle Cloud Guard and resolve or accept and disable all problems. Enable notification on drift and treat new problems with urgency.
      • Enable Oracle Data Safe to secure Oracle Databases by monitoring users and access. Data Safe also scans the databases for security best practices and alerts on divergences.
      • Periodically scan instances and containers for known security issues by using Oracle Cloud Infrastructure Vulnerability Scanning Service.
      • Use OCI Service Mesh to authenticate and encrypt the communication between services in your Oracle Container Engine for Kubernetes (OKE) cluster. OCI Service Mesh also allows you to configure access policies to control inter-service communication and validate external requests.