Top 5 SAP Fiori Best Practices for Developers

Top 5 SAP Fiori Best Practices for Developers

SAP Fiori has revolutionized enterprise user experience by delivering intuitive, role-based applications that enhance productivity and user satisfaction. However, developing high-quality Fiori apps requires more than just technical skills—it demands adherence to best practices that ensure performance, usability, and maintainability.

In this blog post, we’ll explore the top five SAP Fiori best practices that every developer should follow. Whether you’re building custom Fiori apps or extending standard SAP applications, these guidelines will help you create seamless, scalable, and user-friendly solutions.

Follow SAP Fiori Design Guidelines for Consistency

SAP Fiori’s strength lies in its consistent, intuitive design language. Deviating from these guidelines can lead to confusion, poor usability, and a fragmented user experience. Adhering to SAP’s design principles ensures that your app feels like a natural extension of the Fiori ecosystem.

Use SAP Fiori Elements for Faster Development

SAP Fiori Elements provides pre-built templates (List Report, Object Page, Overview Page, etc.) that accelerate development while maintaining design consistency. Instead of building everything from scratch, leverage these templates to reduce development time and ensure compliance with SAP’s UX standards.

Actionable Steps:

  1. Choose the right template based on your use case (e.g., List Report for data exploration, Object Page for detailed views).
  2. Customize annotations in your OData service to define how data is displayed (e.g., @UI.lineItem for table columns, @UI.facet for sections).
  3. Extend with custom logic only when necessary—avoid overriding core behaviors unless absolutely required.

Example:

<Annotation Term="UI.LineItem">
    <Collection>
        <Record Type="UI.DataField">
            <PropertyValue Property="Value" Path="ProductID" />
            <PropertyValue Property="Label" String="Product ID" />
        </Record>
        <Record Type="UI.DataField">
            <PropertyValue Property="Value" Path="ProductName" />
            <PropertyValue Property="Label" String="Product Name" />
        </Record>
    </Collection>
</Annotation>

This annotation defines how a table should display product data in a Fiori Elements app.

Implement Responsive and Adaptive Design

Fiori apps must work seamlessly across desktop, tablet, and mobile devices. SAP’s Flexible Column Layout (FCL) and Dynamic Page are key components for responsive design.

Best Practices:

  1. Use the Flexible Column Layout for master-detail scenarios (e.g., a list of orders on the left, order details on the right).
  2. Leverage SAPUI5’s responsive controls (e.g., sap.m.Table, sap.m.List) that automatically adjust to screen size.
  3. Test on multiple devices using SAP’s Device Preview in SAP Web IDE or Chrome DevTools.

Example:

<FlexibleColumnLayout id="fcl" layout="{/layout}">
    <beginColumnPages>
        <Page title="Orders" showNavButton="true">
            <List items="{/Orders}">
                <StandardListItem title="{OrderID}" description="{CustomerName}" />
            </List>
        </Page>
    </beginColumnPages>
    <midColumnPages>
        <Page title="Order Details" showNavButton="true">
            <ObjectHeader title="{OrderID}" number="{TotalAmount}" />
        </Page>
    </midColumnPages>
</FlexibleColumnLayout>

This snippet demonstrates a responsive two-column layout for an order management app.

Maintain Visual Hierarchy and Accessibility

A well-designed Fiori app should guide users naturally through tasks while ensuring accessibility for all users.

Key Considerations:

  1. Use SAP’s typography and color schemes (e.g., sap_fiori_3 theme) to maintain consistency.
  2. Follow WCAG (Web Content Accessibility Guidelines) by:

– Providing keyboard navigation support.
– Using semantic HTML (<button>, <nav>, <main>).
– Ensuring sufficient color contrast (test with tools like [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)).
3. Prioritize content with clear visual hierarchy (e.g., primary actions in blue, secondary in gray).

Example:

<Button
    text="Save"
    type="Emphasized"
    press=".onSave"
    ariaLabel="Save order details" />

This button follows Fiori’s design language while being accessible via screen readers.

Optimize Performance for Faster Load Times

Slow Fiori apps frustrate users and reduce productivity. Performance optimization should be a top priority from the start.

Minimize OData Calls with Smart Data Loading

Excessive OData calls degrade performance, especially in large enterprise environments. Use batch requests, $expand, and $select to reduce round trips.

Best Practices:
1. Use $select to fetch only required fields:

GET /sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder?$select=SalesOrder,CustomerName,TotalNetAmount

2. Leverage $expand to retrieve related data in a single call:

GET /sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder?$expand=to_Items

3. Implement client-side caching with sap.ui.model.odata.v4.ODataModel (for OData v4) to avoid redundant calls.

Example:

// Enable batch requests in OData v4
var oModel = new sap.ui.model.odata.v4.ODataModel({
    serviceUrl: "/sap/opu/odata/sap/API_SALES_ORDER_SRV/",
    groupId: "$auto",
    autoExpandSelect: true
});

This configuration reduces server round trips by batching requests.

Lazy Load and Code Splitting

Loading all JavaScript upfront slows down initial rendering. Instead, use lazy loading to load only what’s needed.

Implementation Steps:
1. Split your app into components and load them dynamically:

sap.ui.define([
       "sap/ui/core/UIComponent",
       "sap/ui/core/mvc/XMLView"
   ], function(UIComponent, XMLView) {
       return UIComponent.extend("my.app.Component", {
           init: function() {
               UIComponent.prototype.init.apply(this, arguments);
               this.getRouter().initialize();
           },
           createContent: function() {
               return XMLView.create({
                   viewName: "my.app.view.Main",
                   async: true // Enables lazy loading
               });
           }
       });
   });
  1. Use sap.ui.core.ComponentContainer to load components on demand.
  2. Minify and bundle your code with UI5 Tooling (ui5 build --all).

Optimize Images and Static Assets

Large images and unoptimized assets increase load time. Follow these best practices:

  1. Use compressed image formats (WebP instead of PNG/JPG).
  2. Lazy-load images with loading="lazy":
<Image src="image.webp" width="200px" loading="lazy" />

3. Serve assets via a CDN (if possible) to reduce latency.

Example:

<h2>Convert images to WebP using cwebp (Google's WebP converter)</h2>

cwebp -q 80 input.png -o output.webp

This reduces image size by ~30% without noticeable quality loss.

Ensure Robust Security and Compliance

Security is non-negotiable in enterprise applications. Fiori apps must protect sensitive data and comply with corporate policies.

Implement Role-Based Access Control (RBAC)

Fiori apps should restrict data access based on user roles. Use SAP’s authorization objects (PFCG roles) to control visibility.

Steps to Implement RBAC:

  1. Define roles in SAP GUI (Transaction PFCG) and assign them to users.
  2. Use @AccessControl annotations in your OData service to restrict data:
<Annotations Target="API_SALES_ORDER_SRV.A_SalesOrder">
       <Annotation Term="Common.SemanticKey" Path="SalesOrder" />
       <Annotation Term="AccessControl.Authorization">
           <Record>
               <PropertyValue Property="Required" String="S_SALES_ORDER" />
           </Record>
       </Annotation>
   </Annotations>

3. Hide UI elements dynamically based on user permissions:

var bHasAccess = sap.ushell.Container.getService("UserInfo").hasRole("SALES_MANAGER");
   if (!bHasAccess) {
       this.byId("deleteButton").setVisible(false);
   }

Secure OData Services with SAP Gateway

OData services must be protected against unauthorized access and injection attacks.

Best Practices:
1. Enable CSRF protection in SAP Gateway:

POST /sap/opu/odata/sap/API_SALES_ORDER_SRV/$batch
   X-CSRF-Token: Fetch
  1. Use HTTPS (not HTTP) for all communications.
  2. Sanitize user inputs to prevent SQL injection (SAP Gateway does this by default, but validate in custom code).

Example:

" In your OData service implementation (SEGW)
METHOD salesorder_get_entityset.
    DATA: lt_filter TYPE /iwbep/t_mgw_select_option.

    " Validate input parameters
    io_request->get_filter( IMPORTING et_filter_select_options = lt_filter ).

    " Process only if user has authorization
    AUTHORITY-CHECK OBJECT 'S_SALES_ORDER'
        ID 'ACTVT' FIELD '03'
        ID 'SALESORG' FIELD iv_sales_org.
    IF sy-subrc <> 0.
        RAISE EXCEPTION TYPE /iwbep/cx_mgw_not_auth.
    ENDIF.
ENDMETHOD.

Comply with Data Privacy Regulations (GDPR, CCPA)

Enterprise apps must protect personal data and allow users to manage their information.

Key Actions:
1. Implement data masking for sensitive fields (e.g., credit card numbers):

<Text text="{ path: 'CreditCardNumber', formatter: '.formatCreditCard' }" />
formatCreditCard: function(sNumber) {
       return sNumber ? "---" + sNumber.slice(-4) : "";
   }
  1. Provide a "Delete My Data" option (if applicable) via OData DELETE operations.
  2. Log data access for audit trails (use SAP’s Audit Log or a custom solution).

Enhance Maintainability with Clean Code

Poorly structured code leads to technical debt, making future updates difficult. Follow clean code principles to keep your Fiori app maintainable.

Use Modularization and Reusable Components

Avoid monolithic controllers by breaking logic into reusable modules.

Best Practices:

  1. Split controllers into smaller files (e.g., BaseController.js, OrderController.js).
  2. Create custom controls for repeated UI patterns:
sap.ui.define([
       "sap/ui/core/Control"
   ], function(Control) {
       return Control.extend("my.app.controls.CustomHeader", {
           metadata: {
               properties: {
                   title: { type: "string", defaultValue: "" }
               }
           },
           renderer: function(oRm, oControl) {
               oRm.openStart("div", oControl);
               oRm.style("font-size", "20px");
               oRm.style("font-weight", "bold");
               oRm.openEnd();
               oRm.text(oControl.getTitle());
               oRm.close("div");
           }
       });
   });

3. Use sap.ui.core.Fragment for reusable UI fragments:

<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m">
       <Dialog title="Confirmation">
           <content>
               <Text text="Are you sure?" />
           </content>
           <buttons>
               <Button text="Yes" press=".onConfirm" />
               <Button text="No" press=".onCancel" />
           </buttons>
       </Dialog>
   </core:FragmentDefinition>

Implement Proper Error Handling and Logging

Uncaught errors crash the app and frustrate users. Implement robust error handling and logging.

Best Practices:
1. Use try-catch blocks in JavaScript:

try {
       var oData = await this._getOData();
   } catch (oError) {
       sap.m.MessageBox.error("Failed to load data: " + oError.message);
       this._logError(oError);
   }
  1. Log errors to a backend system (e.g., SAP Solution Manager, ELK Stack).
  2. Provide user-friendly error messages (avoid technical jargon).

Example:

_logError: function(oError) {
    var oLogEntry = {
        timestamp: new Date().toISOString(),
        message: oError.message,
        stack: oError.stack,
        user: sap.ushell.Container.getUser().getId()
    };
    // Send to backend (e.g., via OData)
    this.getModel().create("/ErrorLogs", oLogEntry);
}

Document Your Code and APIs

Undocumented code is hard to maintain. Use JSDoc, XML comments, and README files to explain functionality.

Best Practices:
1. Document controllers with JSDoc:

/
    * Fetches sales orders from the backend
    * @param {string} sSalesOrg - Sales Organization ID
    * @returns {Promise} Resolves with sales order data
    */
   async _getSalesOrders(sSalesOrg) {
       // Implementation
   }

2. Add XML comments for views:

<!--
       This fragment displays a confirmation dialog.
       Usage: <core:Fragment fragmentName="my.app.fragments.ConfirmDialog" type="XML" />
   -->

3. Maintain a README in your project root explaining:
– App architecture.
– Key dependencies.
– Deployment steps.

Test Thoroughly Before Deployment

Rigorous testing ensures bug-free, reliable Fiori apps. Skipping testing leads to production failures and unhappy users.

Automate Unit and Integration Testing

Manual testing is time-consuming and error-prone. Use automated testing frameworks like QUnit, OPA5, and UIVeri5.

Testing Strategies:
1. Unit tests with QUnit:

QUnit.module("Sales Order Controller");
   QUnit.test("Test _calculateTotal", function(assert) {
       var oController = new my.app.controller.SalesOrder();
       var fTotal = oController._calculateTotal([{ Amount: 100 }, { Amount: 200 }]);
       assert.strictEqual(fTotal, 300, "Total should be 300");
   });

2. Integration tests with OPA5:

opaTest("Should see the order details", function(Given, When, Then) {
       Given.iStartMyApp();
       When.onTheOrderList.iPressTheFirstOrder();
       Then.onTheOrderDetails.iShouldSeeTheOrderDetails();
   });

3. End-to-end tests with UIVeri5 (for cross-browser testing).

Perform Cross-Browser and Device Testing

Fiori apps must work consistently across browsers and devices.

Testing Checklist:
1. Test on:
– Browsers: Chrome, Firefox, Edge, Safari.
– Devices: Desktop, tablet, mobile (iOS & Android).

  1. Use SAP’s Device Preview in SAP Web IDE.
  2. Leverage cloud-based testing tools (e.g., BrowserStack, Sauce Labs).

Example:

<h2>Run UIVeri5 tests on multiple browsers</h2>

ui5 serve --accept-remote-connections &
uiveri5 --conf conf.js --browsers chrome,firefox

Conduct User Acceptance Testing (UAT)

Real users uncover issues that developers miss. Involve business users early in testing.

UAT Best Practices:

  1. Define test scenarios (e.g., "Create a sales order with 5 items").
  2. Use a UAT checklist to track feedback.
  3. Iterate based on feedback before final deployment.

Example UAT Checklist:

Test Case Expected Result Pass/Fail
Create order with invalid customer Error message appears
Edit order and save Changes persist
Delete order Order removed from list ❌ (Bug: Confirmation dialog missing)

Conclusion

Building high-quality SAP Fiori apps requires more than just coding skills—it demands adherence to design principles, performance optimization, security, maintainability, and rigorous testing. By following these top five best practices, you’ll create Fiori apps that are fast, secure, user-friendly, and easy to maintain.

Start implementing these practices today, and your Fiori apps will stand out in the enterprise landscape!