Capturing and Exploiting Design Pattern Variability in Mobile Application Generation Ramón Peralta
Universidad de San Jorge Zaragoza, Spain [email protected]
arXiv:2607.15099v1 [cs.SE] 16 Jul 2026
Abstract The increasing reliance on automatic code generation in mobile application development often leads to code that neglects fundamental design principles and architectural quality. In this work, we address this challenge by capturing and exploiting the inherent variability of software design patterns to systematically generate customizable and well-structured mobile applications. We propose the use of the Universal Variability Language (UVL) to explicitly model the structural and behavioral variation points of common design patterns, such as Singleton, Strategy, Observer, Adapter, and Factory Method. These models are integrated with reusable Jinja templates, enabling code generation in Swift. Our approach leverages Software Product Line (SPL) engineering principles, treating design patterns as configurable assets within a product line and supporting automated generation of custom design patterns. We also analyze the configuration space of the modeled patterns, offering insights into their variability complexity. By formalizing design pattern variability and embedding it into the generation process, our work bridges model-driven engineering with practical mobile development, promoting the production of maintainable, reusable, and architecturally sound applications.
CCS Concepts • Software and its engineering → Software product lines; Abstraction, modeling and modularity.
Keywords Design pattern, feature model, mobile application, product line, UVL, variability
1
Introduction
Mobile applications today are developed under increasing pressure to deliver rapidly, support multiple platforms, and adapt to evolving user expectations. To meet these demands, many developers turn to automatic code generation tools, especially those powered by large language models (LLMs) [25]. These tools can quickly produce code in languages such as Swift, Kotlin, or JavaScript. However, the generated code often lacks architectural quality and omits fundamental design principles [28]. In particular, the systematic application of well-established software design patterns (i.e., key reusable solutions to recurring design problems) has become less explicit in this new paradigm [29]. Design patterns, as introduced by Gamma et al. [17], have long served as foundational building blocks for software design, facilitating code reuse, flexibility, and maintainability. In the context of mobile development, design patterns are particularly valuable.
Jose-Miguel Horcas
ITIS Software, Universidad de Málaga Málaga, Spain [email protected] They help organize complex user interfaces [32], manage application state [42], user interactions [9], and support reusable business logic across platforms [30]. Nevertheless, with increasing reliance on automatic code generation, developers may no longer recognize when or how to apply these patterns correctly [30]. Moreover, design patterns do not only provide reusable solutions at the code level; they also reflect architectural choices that vary depending on the needs of each application. This idea connects naturally with the principles of Software Product Line (SPL) engineering [1, 31], which focuses on developing families of related software products by managing their commonality and variability. In an SPL, software artifacts are designed to be reused across products, with variation points that allow for customization. Feature models [11, 26] are commonly used to capture these options and guide the generation of concrete products. In the mobile development domain, where applications often need to be customized for different devices, brands, or user preferences, the combination of SPLs and design patterns provides a structured way to generate tailored applications from a shared architecture. In SPL engineering, existing work often considers design patterns as tools to implement variability in software systems. For example, the State or Strategy patterns are commonly used in SPLs to enable the selection of alternative behaviors [1, 7]. However, while patterns are often applied to handle variability, the variability internal to the patterns themselves has received comparatively little attention [36]. Before design patterns can be applied in a reusable and configurable way, we need to understand that they are not fixed templates. In practice, each design pattern has its own internal variability. For instance, the Observer pattern can be instantiated with one or many observers, and the notification can be synchronous or asynchronous. Similarly, the Singleton pattern has variants such as eager vs. lazy initialization, thread-safe vs. unsafe, or per-instance vs. global. This internal variability is often implicit in design pattern catalogs and tutorials [13, 17, 37]. As a result, developers applying these patterns manually (or through code generation) are left with an under-specified solution space. This makes automatic generation difficult to control, and pattern application prone to errors or misuse. This article addresses two key problems: (1) how can we explicitly model the variability of commonly used design patterns?; and (2) how can we automatically generate Swift code from such models to produce correct and customizable pattern implementations for mobile applications? To solve these problems, we propose the use of the Universal Variability Language (UVL) [3] to specify the variability of design patterns using feature modeling. UVL has become the de-facto standard for variability modeling in the SPL community in recent years [38]. UVL supports advanced constructs [40]
R. Peralta et al.
such as attribute-based constraints, typed features beyond Boolean such as numeric and string features, and clonable elements (aka feature cardinalities [8]), which are essential to accurately describe pattern variants. We then use a template-based code generation [41] approach to implement each pattern, supporting variability directly in the code generation process [23]. In a template-based approach, a text-based programming language (e.g., Swift, Kotlin, JavaScript, Python) is enriched with directives to automatically generate custom content. Specifically, we leverage the Jinja1 template engine due to its language-agnostic nature, which allows its integration with various mobile programming languages, including Swift, Kotlin, and Java. Furthermore, Jinja supports all UVL extensions by using powerful directives to manage variability [23]. These directives facilitate the substitution and replacement of elements, the assignment of values, and the use of control structures such as if/elif/else, for-loops, macros, and blocks. Our main contributions are as follows: • The explicit modeling of design pattern variability using UVL feature models, capturing both structural and behavioral variation points within each pattern. • The definition of reusable Jinja templates for each pattern, enabling scalable and customizable code generation in Swift for mobile applications. • The integration with existing SPL tools, such as UVengine2 [23], to support automatic configuration and generation of patternbased architectures tailored to user needs. • The systematic analysis of the configuration space of each design pattern, providing insight into the variability complexity and supporting informed decision-making during product derivation. By formalizing the variability inherent in design patterns, we lay the groundwork for tools that can assist developers (or even Artificial Intelligence assistants) in generating structured, reusable, and well-architected mobile applications. Our approach bridges the gap between model-driven engineering and practical code generation, ensuring that software quality and design best practices are not lost in the automation process. The rest of the paper is organized as follows. Section 2 introduces the main concepts about SPL and UVL. Section 3 presents our approach for modeling and mananing the variability of the design patterns, while Section 4 details the variability and implementation of each the design pattern. Section 5 evaluates our approach. Section 6 discusess related work and Section 7 concludes the paper.
2
Background
This section provides the foundational knowledge necessary to understand our work, focusing on the core principles of SPL engineering and the UVL language.
2.1
Software Product Line Engineering
SPL engineering is a paradigm for developing families of related software systems from a shared set of reusable assets in a planned and systematic manner [1, 31]. The central idea of SPLs is to balance the trade-off between the economies of scale achieved through mass production and the need for customization to meet specific market or customer demands. This is accomplished by explicitly managing 1 Jinja: https://palletsprojects.com/p/jinja/ 2 UVengine: https://uvengine.github.io/
two key concepts: commonality, which refers to the features and assets shared by all products in the line, and variability, which represents the points where products can differ. The SPL approach is typically organized into two main processes: Domain Engineering: This phase focuses on the development and maintenance of reusable assets for the entire SPL. It includes activities such as domain analysis (identifying common and variable features), domain design (creating a common architecture), and domain implementation (developing reusable components). Application Engineering: This phase involves deriving specific products from the reusable assets created during domain engineering. It consists of selecting a valid combination of features from the variability model, which then guides the configuration and assembly of the reusable assets to generate a final product.
2.2
The Universal Variability Language
The SPL engineering process is driven by the variability model (or feature model), which specifies the commonality and variability of the entire SPL. Over the years, multiple languages and formats have been proposed to define feature models; however, in recent years, the UVL language has emerged as the de-facto standard within the SPL community [3]. Listing 1 shows an example of a UVL model using its core Boolean level to represent the variability of a mobile application development process. Traditionally, feature models have been represented as feature diagrams, as illustrated in Figure 1, but UVL offers a concise and expressive syntax for defining feature models. MobileApp Platform
Development Native
Android
iOS
Kotlin
Flutter React
Legend:
Feature Feature
mandatory
Swift
Feature Alternative group
Storage
CrossPlatform
Local
Xamarin
Feature Or group
optional
Connectivity
Cloud
WiFi
5G
Bluetooth
NFC
Cross-tree constraints: Cloud ⇒ WiFi ∨ 5G (Android ∧ iOS) ⇒ CrossPlatform (Android ∧ ¬iOS) ⇒ Kotlin (¬Android ∧ iOS) ⇒ Swift
Figure 1: Diagram of the feature model of Listing 1. A UVL model consists of two main parts: the features section, which contains the feature tree, and the constraints section, which contains the cross-tree constraints. Features are organized in a tree-like hierarchy, definings relationships using keywords such as: mandatory to indicate that a child feature must be selected (e.g., the Platform feature); optional to indicate that a child feature may be selected (e.g., the Connectivity feature); or to indicate that at least one child feature must be selected in a group (e.g., Platform or Storage); and alternative to indicate that exactly one child feature must be selected within a group (e.g., Development). Crosstree constraints are propositional formulas with logical operators: ! (not), & (and), | (or), => (implies), <=> (equivalence), allowing further restrict valid feature selections (e.g., Cloud => WiFi | 5G). Furthermore, UVL also supports specifying feature attributes to include additional information about the features by attaching key–value properties to features, and group cardinalities [a..b] to specify the number of features that can be selected from a group. Other advanced variability constructs supported by UVL are typed features (Integer, Real, or String features) that require assigning a concrete value during configuration; and feature cardinalities (aka
Capturing and Exploiting Design Pattern Variability in Mobile Application Generation
clonable features), which allows creating multiple instances (clones) of a feature and configuring each clone and its subtree differently. Listing 1: Example of feature model in UVL. 1 features 2 MobileApp 3 mandatory 4 Platform 5 or 6 Android 7 iOS 8 Development 9 alternative 10 Native 11 alternative 12 Swift 13 Kotlin 14 CrossPlatform 15 alternative 16 Flutter 17 React 18 Xamarin 19 Storage 20 or 21 Local 22 Cloud 23 optional 24 Connectivity 25 or 26 WiFi 27 "5G" 28 Bluetooth 29 NFC 30 constraints 31 Cloud => WiFi | "5G" 32 (Android & iOS) => CrossPlatform 33 (Android & !iOS) => Kotlin 34 (!Android & iOS) => Swift
3
Approach for Modeling and Exploiting Design Pattern Variability
Building upon the foundations of SPL engineering [31] and Generative Programming [7], our work proposes a novel approach to address the challenge of creating well-architected and customizable mobile applications. The core idea is to treat design patterns themselves as reusable assets within an SPL, explicitly modeling and exploiting their inherent variability to systematically generate mobile application code. This shifts the focus from using design patterns as a static solution for implementing variability to treating them as a configurable, generative artifact. This approach aligns directly with the two core phases of the SPL engineering process introduced in Section 2, as illustrated in the conceptual flow depicted in Figure 2. The process begins in the Domain Engineering phase, where we formalize the variability of design patterns. This is the most crucial step and the main contribution of our work. We identify the structural and behavioral variation points of each pattern and encode them as UVL feature models. In parallel, we define reusable code generation templates for each pattern. In this context, each design pattern is treated as a reusable asset within the SPL, with its own internal variability explicitly captured in a UVL feature model. This makes it possible to configure and derive pattern implementations in a systematic and automated way. • Feature models: We define the configurable options of each design pattern using UVL. For example, for a specific pattern, we model its structural and behavioral alternatives, and the constraints between them, allowing for fine-grained control over its
Feature models (design patterns variability)
Implementation artifacts (design patterns templates) ... Singleton template
Domain Engineering
\begin{tikzpicture} \begin{axis} \begin{tikzpicture} ... \begin{axis} {% for plot in plots %} ... ... \begin{tikzpicture} {% for plot in%}plots %} {% endfor \begin{axis} ... ... class ... {{Name}} { {% \end{axis} {% for plot in%} plots %} private varendfor strategy: ... \end{tikzpicture} ... ... {% endfor %} {% for s\end{axis} in strats %} \end{tikzpicture} ... ... \end{axis} {% endfor %} \end{tikzpicture} init() {...} ... }
Observer template
mapping
Strategy template
selections
Configuration (design pattern customization) Bool
Application Engineering
Derivation (design pattern variability resolution)
Final product (design pattern applied)
Real Int
Int
Str
Figure 2: Our SPL approach to manage the variability of the design patterns. final implementation. These models serve as formal specifications of the pattern’s variability. • Implementation artifacts: For each design pattern, we create language-specific templates (e.g., written in Swift for iOS) that contain placeholders and Jinja directives based on the features of the UVL model. These templates are the blueprints for the final code, ready to be populated with specific feature selections. In the Application Engineering phase, a specific mobile application product is derived by selecting a valid configuration of features for each required design pattern. A developer or product manager selects the desired features from the feature model generating a configuration of the feature model (normally stored in a JSON file). The final step is the generation of the source code by instantiating the Jinja templates with the provided configuration. As the core engine for this phase, we use a generic variability resolution engine: UVengine [23], a tool for resolving the variability of UVL models over Jinja templates. The output is a complete, custom-tailored desing pattern ready to be incorporated in the mobile application. In the following section, we provide the details of how to formalize the variability of each design pattern in UVL and how to implement such variability using Jinja templates for Swift code.
4
Formalizing and Implementing Design Pattern Variability
This section focuses on the formalization and systematic implementation of the internal variability of design patterns as configurable assets within the SPL engineering process. First, we describe how to explicitly model the variation points and variants of each pattern using UVL [3]. Subsequently, we explain how this specification is translated into reusable implementation artifacts through parameterized code templates (using Jinja), which are capable of automatically generating concrete versions of the pattern in response to different application configurations.
4.1
Overview of Patterns Analyzed
We present the catalog of design patterns selected for variability modeling and automated code generation. We assign identifiers
R. Peralta et al.
to each pattern (e.g., DP1, DP2), in order to facilitate references throughout the following sections. The patterns chosen represent three classical groups (creational, behavioral, structural) and are among those most frequently used in mobile development. Namely, Singleton (DP1), Strategy (DP2), Observer (DP3), Adapter (DP4), and Factory Method (DP5). Each pattern exhibits distinct forms of internal variability, both in structural and behavioral aspects. This diversity allows us to generalize the feasibility and scalability of our approach. For each pattern, we systematically: (1) Identify the main variation points (e.g., instantiation strategy, interface alternatives, cardinality, etc.). (2) Capture alternatives, constraints, and dependencies in a UVL feature model. (3) Provide a reusable, parameterized Jinja code template that materializes the selected features. (4) Analyze the configuration space to determine the expressiveness and boundaries of their variability. This approach ensures not only a comprehensive exploration of variability (covering both fine-grained options and “macro” structural features), but also a uniform methodology for the subsequent sections, where each pattern will be formalized, implemented, and its configuration space evaluated (Sections 4.2–4.6). By covering a representative sample of patterns and modeling their variability explicitly, we lay the ground for future expansion to other patterns and domains. Table 1 summarizes the selected patterns and their main sources of variability, serving as a roadmap for the remainder of this section. Table 1: Overview of patterns and main sources of variability. Design Pattern
Structural Variability
Behavioral Variability
Key Constraints
DP1: Singleton
Initialization strategy. Number and type of strategies. Observer cardinality.
Thread safety, access method. Dynamic selection mechanism. Sync/async notification. Interface compatibility. Instantiation parameterization.
Eager vs lazy, valid combinations. Caching, setter/factory selection. One-to-many, notification mode. Inheritance or composition. Subclass responsibility, type safety.
DP2: Strategy DP3: Observer DP4: Adapter DP5: Factory Method
4.2
Adaptee binding mechanism. Product class alternatives.
DP1: Singleton Pattern Variability
The Singleton pattern is one of the most widely used in mobile application development to ensure the existence of a single instance of a class and to provide a global point of access to it. However, this pattern is not monolithic: it exhibits relevant internal variability that includes aspects such as initialization strategy, access method, and concurrency safety.
Class Name: defined as a String feature, allowing customization of the generated class name. Listing 2: Feature model of the Singleton pattern. 1 features 2 "Singleton Pattern" {abstract} 3 mandatory 4 Initialization {abstract} 5 alternative 6 Eager 7 Lazy 8 "Access Method" {abstract} 9 alternative 10 "getInstance()" 11 "Static Field" 12 optional 13 "Thread Safety" 14 String "Class Name" 15 constraints 16 Eager => !"Thread Safety" 17 "Static Field" => Eager
Additionally, two constraints are defined to ensure configuration validity: (1) if initialization is Eager, the Thread Safety option cannot be selected; (2) the Static Field access method is only valid in combination with Eager initialization. This model not only formalizes the available options but also prevents inconsistent configurations, ensuring correctness in the generated code. Listing 3: Jinja template excerpt for the Singleton pattern. 1 {# singleton . swift . j2 #} 2 {% if features . get (" Thread Safety ") %} import Dispatch {% endif 3 {% set class_name = features . get (" Class Name ", " Singleton ") %} 4 5 class {{ class_name }} { 6 {% if features . get (" Initialization ") == " Eager " %} 7 static let shared = {{ class_name }} () 8 {% elif features . get (" Initialization ") == " Lazy " %} 9 private static var _instance : {{ class_name }} ? 10 {% endif %} 11 12 private init () {} // Private constructor 13 14 {% if features . get (" Access Method ") == " getInstance () " %} 15 static func getInstance () -> {{ class_name }} { 16 {% if features . get (" Initialization ") == " Eager " %} 17 return shared 18 {% else %} 19 // Lazy initialization and Thread Safety options ... 20 {% endif %} 21 } 22 {% elif features . get (" Access Method ") == " Static Field " %} 23 static var instance : {{ class_name }} { 24 // Access through static property ... 25 } 26 {% endif %} 27 }
%}
Variability implementation. Listing 3 shows an excerpt of the Jinja template that implements the variability of the Singleton pattern in Swift. The template uses directives to activate or deactivate code fragments depending on the features selected in the UVL model. For instance, the Thread Safety option imports the Dispatch library (line 3) and introduces a synchronization queue Variability specification. The UVL model in Listing 2 captures to protect instance creation. The initialization mechanism is conthe main variation points of the Singleton pattern. It defines: trolled with conditionals: in Eager mode, the instance is created Initialization: either Eager (the instance is created at class statically (line 8), while in Lazy mode, it is delayed until the first loading time) or Lazy (the instance is created on demand). invocation (line 10). The access method can be implemented eiAccess Method: the instance can be retrieved through a getInstance() ther through a getInstance() function (lines 16–22) or through a method or via a static field. static property instance (lines 24–26). Finally, the class name is Thread Safety: synchronization can be added for concurrent sceparameterized via the UVL feature Class Name (line 4), enabling narios, but it is only applicable in the case of Lazy initialization. reuse in different contexts.
Capturing and Exploiting Design Pattern Variability in Mobile Application Generation
Variability analysis. The configuration space of the Singleton pattern is relatively small but sufficiently expressive to cover the main usage scenarios in mobile applications: 2 initialization options (Eager vs. Lazy); 2 access methods (getInstance() vs. Static Field); and the presence or absence of Thread Safety (restricted to Lazy initialization). Considering the defined constraints, the model produces a total of four valid configurations3 : Config 1. Config 2. Config 3. Config 4.
{ Eager, getInstance() } { Eager, Static Field } { Lazy, getInstance() } { Lazy, getInstance(), Thread Safety }
This analysis confirms that the UVL model captures the essential variability without introducing inconsistent combinations.
4.3
DP2: Strategy Pattern Variability
The Strategy pattern is widely employed in mobile application development as it defines a family of algorithms, encapsulates them, and enables their interchangeability, thereby allowing the algorithm to evolve independently of the clients that employ it. Nevertheless, this pattern is not monolithic: it exhibits significant internal variability that encompasses aspects such as the mechanism for selecting the strategy, the degree of coupling with the context, and performance considerations in resource-constrained environments. Listing 4: Feature model of the Strategy pattern. 1 features 2 "Strategy Pattern" {abstract} 3 mandatory 4 "Strategy Interface" {abstract} 5 alternative 6 "Abstract Class" 7 Interface 8 Protocol 9 "Strategy Selection" {abstract} 10 alternative 11 "Constructor Injection" 12 "Setter Method" 13 "Factory Method" 14 "Context Behavior" {abstract} 15 alternative 16 "Delegate to Strategy" 17 "Template Method" 18 optional 19 "Strategy Validation" 20 "Default Strategy" 21 "Strategy Caching" 22 String "Context Class Name" 23 String "Strategy Interface Name" 24 Integer "Number of Strategies" cardinality [2..10] 25 constraints 26 "Abstract Class" => !Protocol 27 Protocol => Interface 28 "Factory Method" => "Strategy Validation" 29 "Template Method" => "Abstract Class" 30 "Number of Strategies" > 1
Variability specification. The UVL model in Listing 4 captures the main variation points of the Strategy pattern. It defines: Strategy Interface: The abstraction of the strategy can be realized through an interface (if supported by the target language), a protocol (Swift’s interface mechanism), or an abstract class (an inheritance-based approach). Strategy Selection: The process of selecting and configuring strategies can be performed by means of constructor injection (the strategy is set at creation time), setter method (the strategy can be replaced during execution), or factory method (the strategy is created and selected through a factory). 3We exclude the String feature Class Name from the analysis since it does not affect
the configuration space.
Context Behavior: The context may either delegate directly to the strategy (simple delegation) or apply the template method (in which the context defines the overall structure of the algorithm while strategies implement specific steps). Strategy Validation: An optional feature enables validation of the strategy’s suitability prior to its execution. Default Strategy: An optional feature that provides a fallback strategy when no specific strategy is set. Strategy Caching: An optional feature that enables caching of strategy instances to avoid repeated instantiation, improving performance in scenarios with frequent strategy switches. Context Class Name and Strategy Interface Name: They allow customization of generated class and interface names. Number of Strategies: An integer feature with cardinality that specifies how many concrete strategy implementations will be generated (range 2–10). Additionally, several constraints ensure configuration validity: (1) Abstract Class approach is incompatible with Protocol; (2) Protocol requires Interface selection; (3) Factory Method requires Strategy Validation for proper error handling; (4) Template Method requires Abstract Class approach; (5) and Number of Strategies must be greater than 1. Listing 5: Jinja template excerpt for the Strategy pattern. 1 {# 2 {% 3 {%
strategy . swift . j2 #} set ctx_name = features . get (" Context Class Name ", " Context ") %} set strat_name = features . get (" Strategy Interface Name ", " Strategy ") %} 4 {% set num_strategies = features . get (" Number of Strategies ", 2) %} 5 6 // Strategy Protocol 7 {% if features . get (" Strategy Interface ") == " Protocol " %} 8 protocol {{ strat_name }} { 9 func execute () 10 } 11 {% else %} 12 ... // Class - based approach 13 {% endif %} 14 15 // Concrete Strategies ( {{ num_strategies }} implementations
generated ) 16 {% for i in range (1 , num_strategies + 1) %} 17 class ConcreteStrategy {{ i }} : {{ strat_name }} { 18 func execute () { print (" Executing strategy {{ i }} ") } 19 } 20 {% endfor %} 21 22 class {{ ctx_name }} { 23 private var strategy : {{ strat_name }} 24 {% if features . get (" Strategy Caching ") %} 25 private var strategyCache : [ String : {{ strat_name }} ] = [:] 26 {% endif %} 27 28 init ( strategy : {{ strat_name }} ) { self . strategy = strategy } 29 30 {% if features . get (" Strategy Selection ") == " Factory Method " %} 31 func setStrategy ( byType strategyType : String ) { 32 // Factory - based instantiation with optional caching 33 // Full implementation available at GitHub repository 34 } 35 {% endif %} 36 37 func executeStrategy () { strategy . execute () } 38 }
Variability implementation. Listing 5 shows a Jinja template excerpt for the Strategy pattern in Swift. The template begins by extracting configuration parameters from the UVL features (lines 2–4), setting default values for the context name, strategy interface name, and number of strategies. The Strategy Interface selection (lines 7–13) determines whether to generate a Swift protocol or
R. Peralta et al.
use a class-based approach, though the class-based implementation is abbreviated in this excerpt. The template generates concrete strategy implementations dynamically (lines 16–26) based on the Number of Strategies feature, creating the specified number of ConcreteStrategy classes that conform to the selected interface approach. Each generated strategy includes a simple execution method with pattern-specific logic. The Context class implementation (lines 29–71) varies based on the selected strategy selection mechanism. Constructor Injection is always supported through the init method (lines 35–37), while optional setter methods are generated when Setter Method or Factory Method selection is chosen (lines 39–43). The Factory Method approach (lines 45–66) includes string-based strategy instantiation with a switch statement that maps strategy names to concrete implementations. Performance optimization through Strategy Caching is conditionally included (lines 31–33, 47–52, 62–64), maintaining a dictionary cache of strategy instances to avoid repeated instantiation. Variability analysis. The configuration space of the Strategy pattern is moderately complex, reflecting the diverse architectural needs in mobile application development. The model supports 3 strategy interface approaches, 3 selection mechanisms, 2 context behaviors, and various optional features, combined with a configurable number of strategies (2–10). Considering the defined constraints, the model produces up to 120 distinct configurations. The constraints significantly reduce the theoretical configuration space by eliminating inconsistent combinations, such as Abstract Class with Protocol or Template Method without Abstract Class. As examples, we show three representative valid configurations:
subject for updated data), or Hybrid Model (combination of both approaches). Observer Management: Optional feature that provides sophisticated observer lifecycle management, including registration, deregistration, and observer validation. Async Notifications: Optional feature enabling asynchronous notification delivery, preventing UI blocking and improving performance in mobile applications. Filtered Notifications: Optional feature allowing selective notification based on observer interests or event types. Observer Priority: It enables prioritized notification ordering, ensuring critical observers receive updates first. Weak References: It implements weak reference patterns to prevent retain cycles and memory leaks in mobile applications. Event Types: It supports typed events and filtering capabilities. Subject, Observer, and Concrete Observer Name: They allow customization of generated class and interface names. Number of Observers: An integer feature with cardinality specifying how many concrete observer implementations will be generated (range 1-10). Listing 6: Feature model of the Observer pattern.
1 features 2 "Observer Pattern" {abstract} 3 mandatory 4 "Subject Type" {abstract} 5 alternative 6 "Abstract Subject" 7 "Protocol Subject" 8 "Observer Interface" {abstract} 9 alternative 10 Protocol 11 "Abstract Class" 12 "Notification Method" {abstract} Config 1. { Protocol, Interface, Constructor Injection, Delegate to Strategy, 13 alternative 14 "Push Model" 3 strategies } 15 "Pull Model" Config 2. { Protocol, Interface, Setter Method, Delegate to Strategy, Strategy 16 "Hybrid Model" Caching, 5 strategies } 17 optional Config 3. { Abstract Class, Factory Method, Template Method, Strategy Validation, 18 "Observer Management" Strategy Caching, 4 strategies } 19 "Async Notifications" 20 "Filtered Notifications" 21 "Observer Priority" 22 "Weak References" 23 "Event Types" 24 String "Subject Name" 25 String "Observer Name" 26 String "Concrete Observer Name" 27 Integer "Number of Observers" cardinality [1..10] 28 constraints 29 "Observer Priority" => "Observer Management" 30 "Filtered Notifications" => "Event Types" 31 "Async Notifications" => "Protocol Subject" 32 "Number of Observers" > 0
4.4
DP3: Observer Pattern Variability
The Observer pattern is extensively used in mobile application development to establish one-to-many dependencies between objects, allowing multiple observers to be automatically notified when a subject’s state changes. In mobile applications, this pattern is particularly valuable for implementing reactive user interfaces, data binding mechanisms, model-view synchronization, and event-driven architectures. It exhibits internal variability such as different notification strategies, observer management approaches, and performance optimizations for resource-constrained mobile environments.
Several constraints enforce valid configurations: (1) Observer Priority requires Observer Management selection; (2) Filtered Notifications requires Event Types for Efficiency. Without event Variability specification. The UVL model in Listing 6 defines types, all observers would receive all notifications, which would the main variation points of the Observer pattern: make the concept of “filtering” useless; (3) Async Notifications Subject Type: It can be implemented using an Abstract Subject requires Protocol Subject; (4) and The number of observers (inheritance-based approach with common functionality) or Protocol must be greater than 0. Subject (interface-based approach for maximum flexibility). Observer Interface: The observer abstraction can be defined as Variability implementation. Listing 7 shows a Jinja template a Protocol (Swift’s interface mechanism) or as an Abstract excerpt for the Observer pattern in Swift. The template begins by Class (when shared behavior among observers is needed). extracting configuration parameters from the UVL features (lines Notification Method: The communication mechanism between 2–3), setting default values for the subject name and observer subject and observers can follow Push Model (subject sends interface name. The Observer Interface is consistently impledata directly to observers), Pull Model (observers query the mented as a protocol (lines 5–12) with AnyObject conformance to
Capturing and Exploiting Design Pattern Variability in Mobile Application Generation
support weak references, a critical requirement for mobile applications to prevent memory leaks. Listing 7: Jinja template excerpt for the Observer pattern. 1 {# swift_observer . j2 #} 2 {% set subject_name = features . get (" Subject Name ", " Subject ") %} 3 {% set obs_name = features . get (" Observer Name ", " Observer ") %} 4 5 protocol {{ obs_name }} : AnyObject { 6 var observerID : String { get } 7 {% if features . get (" Push Model ") %} 8 func update ( data : [ String : Any ]) 9 {% elif features . get (" Pull Model ") %} 10 func update ( subject : {{ subject_name }} ) 11 {% endif %} 12 } 13 14 class {{ subject_name }} { 15 private var observers : [ {{ obs_name }} ] = [] 16 17 func attach (_ observer : {{ obs_name }} ) { 18 observers . append ( observer ) 19 } 20 21 func notify ( {% if features . get (" Push Model ") %} data : [ String :
Any ] {% endif %} ) { for observer in observers { // Notification method varies : Push / Pull / Hybrid models supported // Additional features : async delivery , filtering , priority ordering }
22 23 24 25 26 27 }
}
The notification method selection drives the core communication mechanism between subject and observers. In Push Model mode (lines 7–8, 21, 23–24), the subject actively sends data to observers through the update method with a data parameter. In Pull Model mode (lines 9–10, 25–26), observers receive minimal notification and must query the subject directly for updated information, providing more control over data access patterns. The Subject implementation (lines 14–30) maintains an array of observers and provides basic attachment and notification functionality. The notify method varies its signature based on the selected notification model: Push Model includes a data parameter (line 21), while Pull Model requires no additional parameters as observers access the subject directly. While this excerpt demonstrates the core variability implementation, the complete template includes additional features such as observer management, asynchronous notifications, and filtering capabilities based on the selected optional features from the UVL model. Variability analysis. The configuration space of the Observer pattern reflects moderate to high complexity, suitable for the diverse architectural requirements in mobile application development. The model supports 2 subject types, 2 observer interface approaches, 3 notification methods, and 6 optional features, combined with configurable observer counts (1–10). While the constraints reduce the theoretical configuration space by eliminating architecturally inconsistent combinations, such as asynchronous notifications without protocol-based subjects; the model still produces 648 distinct configurations. This configuration space addresses the spectrum of reactive programming needs in mobile development, from simple notification mechanisms to sophisticated event-driven architectures. Representative valid configurations include: Config 1. { Protocol Subject, Protocol, Push Model, 2 observers }. Config 2. { Protocol Subject, Protocol, Pull Model, Observer Management, Weak References, 5 observers }.
Config 3. { Protocol Subject, Protocol, Hybrid Model, Async Notifications, Filtered Notifications, Event Types, Observer Priority, 8 observers }.
4.5
DP4: Adapter Pattern Variability
The Adapter pattern is a structural design pattern commonly employed in mobile application development to enable interoperability between classes featuring incompatible interfaces. This approach is particularly advantageous within mobile applications for integrating third-party libraries, legacy codebases, external APIs, and platform-specific components that diverge from expected interface specifications. Notably, the Adapter pattern is not monolithic; it exhibits significant internal heterogeneity, encompassing various adaptation strategies, interface compatibility techniques, and data transformation procedures tailored to the diverse requirements encountered in contemporary mobile development scenarios. Listing 8: Feature model of the Adapter pattern. 1 features 2 "Adapter Pattern" {abstract} 3 mandatory 4 "Adapter Type" {abstract} 5 alternative 6 "Object Adapter" 7 "Class Adapter" 8 "Target Interface" {abstract} 9 alternative 10 Protocol 11 "Abstract Class" 12 "Adapter Implementation" {abstract} 13 alternative 14 "Full Implementation" 15 "Partial Implementation" 16 optional 17 "Method Mapping" 18 "Data Conversion" 19 "Error Handling" 20 "Multiple Adaptees" 21 String "Target Interface Name" 22 String "Adapter Class Name" 23 String "Adaptee Class Name" 24 Integer "Number of Methods" cardinality [1..10] 25 constraints 26 "Class Adapter" => "Abstract Class" 27 "Multiple Adaptees" => "Object Adapter" 28 "Partial Implementation" => "Error Handling" 29 "Number of Methods" > 0
Variability specification. The UVL model in Listing 8 captures the main variation points of the Adapter pattern. It defines: Adapter Type: The adaptation mechanism can be implemented using Object Adapter (composition-based approach that wraps the adaptee) or Class Adapter (inheritance-based approach using protocol extensions in Swift). Target Interface: It can be defined as a Protocol (Swift’s interface mechanism for maximum flexibility) or Abstract Class (when shared implementation is needed across adapters). Adapter Implementation: The completeness of interface adaptation can be Full Implementation (all target methods implemented) or Partial Implementation (selective method adaptation with error handling for unimplemented methods). Method Mapping: Optional feature that provides sophisticated mapping between target and adaptee method signatures, parameter transformations, and naming conventions. Data Conversion: Optional feature enabling automatic data type conversion between incompatible target and adaptee data types, essential for API integration scenarios.
R. Peralta et al.
Error Handling: Optional feature providing robust error handling mechanisms for adaptation failures, type conversion errors, and method invocation issues. Multiple Adaptees: Optional feature supporting adaptation of multiple incompatible classes through a single adapter interface, useful for aggregating legacy systems. Target Interface, Adapter Class, and Adaptee Class Name: String features allowing customization of generated class and interface names for different contexts. Number of Methods: An integer feature with cardinality [1..10] specifying how many methods will be adapted in the interface. Additionally, several constraints ensure configuration validity: (1) Class Adapter requires Abstract Class for inheritance-based adaptation; (2) Multiple Adaptees requires Object Adapter for composition flexibility; (3) Partial Implementation requires Error Handling for unimplemented method management; and (4) Number of Methods must be greater than 0. Listing 9: Jinja template excerpt for the Adapter pattern. 1 {# adapter . swift . j2 #} 2 {% set target = features . get (" Target Interface Name ", " Target ") %} 3 {% set adapter = features . get (" Adapter Class Name ", " Adapter ") %} 4 {% set adaptee = features . get (" Adaptee Class Name ", " Adaptee ") %} 5 6 protocol {{ target }} { 7 func request () {% if features . get (" Data Conversion ") %} -> String
if features . get (" Data Conversion ") %}
-> Int {% endif %} { 12 // Full implementation available at GitHub repository 13 } 14 } 15 // Object Adapter implementation 16 class {{ adapter }} : {{ target }} { 17 private let adaptee : {{ adaptee }} 18 19 init ( adaptee : {{ adaptee }} ) { self . adaptee = adaptee } 20 21 func request () {% if features . get (" Data Conversion ") %} -> 22 23 24 25 26 27 28 29 }
Variability analysis. The configuration space of the Adapter pattern reflects moderate complexity, addressing diverse integration challenges in mobile application development. The model supports 2 adapter types, 2 target interface approaches, 2 implementation completeness levels, and 4 optional features, combined with configurable method counts (1–10). Considering the defined constraints, the model produces up to 120 distinct valid configurations that takes care of architecturally inconsistent combinations, such as Class Adapter without Abstract Class or Multiple Adaptees without Object Adapter flexibility. Representative valid configurations include:
Config 1. { Object Adapter, Protocol, Full Implementation, Data Conversion, 3 methods } Config 2. { Class Adapter, Abstract Class, Partial Implementation, Error Handling, Method Mapping, 5 methods } Config 3. { Object Adapter, Protocol, Full Implementation, Multiple Adaptees, Data Conversion, Error Handling, 8 methods }
4.6
{% endif %} 8 } 9 10 class {{ adaptee }} { 11 func specificRequest () {%
Data Conversion, either performing type conversion from Int to String (lines 26–27, 35–36) or simple method delegation (lines 29, 38). While this excerpt demonstrates the fundamental adaptation mechanisms, the complete template includes additional features such as method mapping, error handling, and multiple adaptee support based on selected optional features.
DP5: Factory Method Pattern Variability
The Factory Method pattern occupies a central position in mobile software development when the objective is to delegate object instantiation to subclasses, thereby enhancing the architectural flexibility and extensibility of the system. However, its application presents diverse alternatives and differentiated decisions, each of which can have significant consequences for the final design. Listing 10: Feature model of the Factory Method pattern.
String
{% endif %} { {% if features . get (" Data Conversion ") %} let result = adaptee . specificRequest () return " Converted : \( result )" {% else %} adaptee . specificRequest () {% endif %} }
Variability implementation. Listing 9 shows an excerpt of the Jinja template that implements the variability of the Adapter pattern in Swift. The template uses conditional directives to generate different structural approaches based on the selected features from the UVL model. The template begins by extracting configuration parameters (lines 2–4), setting default values for the Target Interface Name, Adapter Class Name, and Adaptee Class Name. The target interface is consistently implemented as a protocol (lines 6–8), with the Data Conversion feature determining whether methods return specific types or void. The adaptee class represents the legacy component being adapted (lines 9–16), with Data Conversion controlling return type compatibility. The core adaptation logic switches between Object Adapter (lines 18–31) using composition with a private adaptee instance and initialization, versus Class Adapter (lines 32–41) using Swift protocol extensions for inheritance-based adaptation. The request method implementation varies based on
1 features 2 "Factory Method Pattern" {abstract} 3 mandatory 4 "Creator Type" {abstract} 5 alternative 6 "Abstract Creator" 7 "Concrete Creator" 8 "Product Interface" {abstract} 9 alternative 10 Protocol 11 "Abstract Class" 12 "Base Class" 13 "Factory Method" {abstract} 14 alternative 15 "Abstract Method" 16 "Default Implementation" 17 optional 18 "Product Registration" 19 "Parameter Passing" 20 "Error Handling" 21 "Generic Support" 22 "Lazy Loading" 23 String "Creator Class Name" 24 String "Product Interface" 25 String "Factory Method Name" 26 Integer "Number of Products" cardinality [2..10] 27 constraints 28 "Abstract Method" => "Abstract Creator" 29 "Default Implementation" => "Concrete Creator" 30 "Product Registration" => "Generic Support" 31 "Number of Products" > 1
Variability specification. The UVL model in Listing 10 captures the main variation points of the Factory Method pattern:
Capturing and Exploiting Design Pattern Variability in Mobile Application Generation
Creator Type: The pattern accommodates both an Abstract Creator that specifies the factory interface, and a Concrete Creator that provides the factory implementation. Product Interface: It is manifested as a Protocol, Abstract Class, or Base Class, enabling a spectrum of polymorphism and type abstraction suitable for different software requirements. Factory Method: There are two main options available for implementation: an Abstract Method (which requires subclasses to provide the instantiation logic) or a Default Implementation (the base class provides a default creation method). Optional Features: The model encompasses additional extensions such as Product Registration (enabling runtime registration of available products), Parameter Passing (the factory method can accept arguments that influence instance creation), Error Handling, Generic Support, and Lazy Loading. String and Integer Attributes: Configuration is further customized through Creator Class Name, Product Interface Name, and Factory Method Name (all string attributes). The number of products is set via the integer attribute Number of Products, with a minimum cardinality of two.
24–29) providing a default implementation that returns a concrete product instance. The createProduct method varies its signature based on Parameter Passing, either accepting type arguments (line 26) or requiring no parameters for simple instantiation.
Listing 11: Template excerpt for the Factory Method pattern.
5
1 {# factory_method . swift . j2 #} 2 {% set creator = features . get (" Creator Class Name ", " Creator ") %} 3 {% set product = features . get (" Product Interface ", " Product ") %} 4 5 protocol {{ product }} { 6 func operation () {% if features . get (" Parameter Passing ") %} ->
String {% endif %} 7 } 8 9 class ConcreteProduct : {{ product }} { 10 func operation () {% if features . get (" Parameter
Config 1. { Abstract Creator, Protocol, Abstract Method, Parameter Passing, 3 products } Config 2. { Concrete Creator, Base Class, Default Implementation, Error Handling, Lazy Loading, 5 products } Config 3. { Abstract Creator, Protocol, Abstract Method, Product Registration, Generic Support, Parameter Passing, Error Handling, 8 products }
Evaluation
We make our UVL models and Jinja templates publicly available and conducted experiments to analyse the variability complexity and the configuration space of the design patterns. In addition, we assess the development effort involved by comparing manual and generated implementations, illustrating this with a case study on the Singleton pattern.
Passing ") %} ->
String {% endif %} { 11 print (" ConcreteProduct : operation ") 12 {% if features . get (" Parameter Passing ") %} 13 return " result " 14 {% endif %} 15 } 16 } 17 18 {% if features . get (" Abstract Creator ") %} 19 class {{ creator }} { 20 func createProduct () -> {{ product }} { 21 fatalError (" Override required ") 22 } 23 } 24 {% else %} 25 class {{ creator }} { 26 func createProduct ( {% if features . get (" Parameter 27 28 } 29 } {%
Variability analysis. The configuration space of the Factory Method pattern reflects moderate to high complexity, addressing diverse object creation challenges in mobile application development. The model supports 2 creator types, 3 product interface approaches, 2 factory method implementations, and 5 optional features, combined with configurable product counts (2–10). Considering the defined constraints, the model produces 288 valid configurations that consider architecturally inconsistent combinations, such as avoiding Abstract Method without Abstract Creator or Product Registration without Generic Support flexibility. Representative valid configurations include:
5.1
Dataset Availability and Open Science
Following open science best practices, our UVL models dataset as well as the Jinja templates and all associated resources are publicly available online in GitHub: • Website and instructions: https://trran.github.io/UVL2Pat/ • GitHub: https://github.com/trran/UVL2Pat
5.2 Passing ") %}
type : String {% endif %} ) -> {{ product }} { return ConcreteProduct ()
Experimentation Setup
We use the tools flamapy [14] and FM Fact Label [21], that are part of the UVL ecosystem [15], to analyze the complexity and configuration space of the feature models specifed in UVL. Those are online web-based tools, and thus, not additional setup is required.
endif %}
5.3 Variability implementation. Listing 11 shows an excerpt of the Jinja template that implements the variability of the Factory Method pattern in Swift. The template uses directives to activate or deactivate code fragments depending on the features selected in the UVL model. The template begins by extracting configuration parameters from the UVL features (lines 2–3), setting default values for the Creator Class Name and Product Interface Name. The product interface is consistently implemented as a protocol (lines 5–7), with the Parameter Passing feature determining whether methods include return types or additional parameters. The core factory method implementation switches between Abstract Creator (lines 18–23) using fatalError("Override required") to enforce subclass implementation, versus Concrete Creator (lines
Results and Discussion
The complexity of a feature model can be characterized by its number of features and its number of valid products (configurations) [2, 5]. The goal is to analyze the complexity of the UVL models and the configuration space of the design patterns. Figure 3 summarizes the patterns according to the number of features captured in their UVL models, while Figure 4 compares them with respect to the size of their configuration spaces. From Figure 3, we observe that the variability of the patterns is almost evenly distributed. Except for simpler patterns such as Singleton, which exhibit nine features, the others patterns involve a richer feature set (from 18 to 21 different features), as they encapsulate more variation points related to roles, interactions, and optional extensions. Despite the number of features is similar along the
R. Peralta et al.
21 20
20
18
18
Number of Features
15
10
9
5
0 Singleton
Strategy
Observer
Adapter
Factory Method
Design Pattern
Figure 3: Comparison of patterns in terms of features.
(e.g., FriendsChatService, Message, and two view controllers) and approximately 130 lines of code. In contrast, the generated version focused exclusively on the structural essence of the pattern, with only 55 lines of code and built-in thread safety. Table 2 summarizes the comparison. The results show that our approach reduces boilerplate code by more than 50%, lowers cyclomatic complexity, and introduces configuration options (e.g., lazy initialization, thread safety) not present in the manual implementation. While domainspecific logic still requires manual coding, the proposed approach accelerates prototyping and ensures architectural consistency. Table 2: Development effort comparison of Singleton pattern.
648
Metric
Number of Configurations
600
Lines of Code (LOC) Number of Classes Cyclomatic Complexity Estimated Dev. Time Configurability Reusability
400
288
5.4
200
120
120
4 0 Singleton
Strategy
Observer
Adapter
Factory Method
Design Pattern
Figure 4: Comparison of the patterns’ configuration space. patterns, they present different type of features and variation points for each pattern (as shown in Section 4). This suggests that different patterns introduce different levels of modeling effort: some can be formalized with minimal feature hierarchies, while others require a more fine-grained specification to capture their inherent flexibility. Figure 4 further highlights the impact of variability on the configuration space. The Singleton pattern results in only four valid configurations due to its restricted options and constraints. The Factory Method and Observer patterns, on the other hand, generate a significantly larger configuration space (288 and 648 configurations respectively), which reflects their combinatorial variability when multiple roles and communication mechanisms are considered. The Strategy and Adapter patterns occupy an intermediate position: although their feature models are not as complex as Factory Method or Observer, their configuration spaces are still non-trivial due to the inclusion of optional features and multiple mapping options. These findings lead to several insights. First, the formalization of design patterns as feature models makes their variability explicit and comparable, which is often overlooked in traditional pattern catalogs. Second, the analysis of configuration spaces reveals the potential challenges in automated derivation: while some patterns can be generated with almost no configuration overhead, others may require careful selection of features to avoid overwhelming the developer with unnecessary options. Finally, the results confirm that our approach scales from simple to more complex patterns, showing that UVL and template-based generation are suitable for capturing and exploiting variability across the full spectrum of design patterns. Effort Analysis: Singleton Pattern case study. To further illustrate the benefits of our approach, we compared a manually implemented Singleton, inspired by a real-world chat service, with the automatically generated version produced by our UVL + Jinja pipeline. The manual implementation consisted of multiple classes
Manual (Chat)
Generated (UVL+Jinja)
∼130
∼55
6
≥ 10
3–4 h Fixed Limited to case
1 ≤3 15–20 min Parametrizable Generic
Threats to Validity
This work presents certain limitations that may affect the evaluation validity. First, the evaluation has focused on a reduced set of patterns and exclusively on one language (Swift). It remains necessary to broaden the empirical validation to include more design patterns such as Decorator, Proxy, or State, among others; as well as other programming languages used in mobile applications such as Kotlin, Java, or Dart. Another threat is the lack of a comparison between the effort and benefits relative to the automated generation of the patterns’ variants and the manual development of those variants.
6
Related Work
This section discusses prior research related to our work on modeling and exploiting design pattern variability for mobile application generation. We organize the discussion into two main areas: approaches that combine SPL with design patterns, and existing generative techniques in software development. Design Patterns and SPLs. The intersection of SPLs and design patterns has been explored primarily through patterns as variability implementation mechanisms in SPLs [1, 7]. The Strategy pattern implements behavioral variability, Decorator enables dynamic feature addition, Template Method varies algorithms through inheritance, and Observer facilitates feature addition/removal. However, our work addresses a different challenge: the internal variability within patterns themselves, which has received limited attention [36]. Our work, however, tackles a different problem: the variability within the patterns themselves. The intrinsic configurable nature of design patterns has been largely overlooked, with variations often being implicit in standard catalogs [13, 17, 37]. A notable exception is the work by Seidl et al. [36], who introduced the concept of variability-aware design patterns to bridge the gap between SPLs and design patterns. Their approach uses role models to capture a design pattern and its connection to an SPL feature model, allowing for systematic application and generation of pattern-based artifacts. Other related efforts include those that combine feature models with architectural patterns. Font et al. [12] proposed a method for building SPLs from conceptualized model patterns. Degueule et al. [10] developed a tooling solution that integrates architectural pattern catalogs with variability models in CVL (the obsolete
Capturing and Exploiting Design Pattern Variability in Mobile Application Generation
Common Variability Language) [18] to automatically synthesize architectural variants. While these works are highly relevant, they often rely on predefined pattern models and explicit metamodels. Our approach, by using a modern and extensible language such as UVL and template-based code generation, provides a flexible and scalable method to formalize and exploit design pattern variability. Moreover, UVL enables the automated analysis of the configuration space of the design patterns by using the tool support of the UVL ecosystem [16] such as flamapy [14], flamapyIDE [4], FeatureIDE [39], FM Fact Label [21], and UVengine [23]. Generative Programming and Mobile Application Development. The field of Generative Programming [7] focuses on creating software from high-level specifications. The implementation of SPLs and the automatic generation of products relies on different approaches. These methods can be broadly categorized into composition-based and annotation-based techniques [1, 19]. Compositional approaches, such as those used in Feature-Oriented Software Development (FOSD) [1], Aspect-Oriented Programming (AOP) [27], or Delta-Oriented Programming (DOP) [35], among others, rely on composing code fragments or assets to build a complete product. In contrast, annotation-based techniques use annotations or directives within a code base to mark variation points, which are then processed by a generator to create a specific product variant (e.g., preprocessors [24] or configuration parameters). Although the literature often recommends the use of compositional over annotationbased approaches due to their advantages in managing complexity and reusability [1], the industry has adopted annotative approaches because of their simplicity and lower entry barrier [19, 24]. A widely adopted and effective technique within this field is template-based code generation [41]. This approach enriches a base language with special directives to automatically produce customized content. While sharing similarities with annotation-based techniques, our approach leverages the power of the Jinja templates, which offer significant advantages over simpler annotative-based approaches. Unlike tools that are limited to basic #ifdef annotations [24] or simple parameter substitution [6], Jinja provides a rich set of directives for managing complex variability. This includes advanced control structures such as if/elif/else, for-loops, macros, and blocks, which enable sophisticated logic for substitution and replacement of code elements. Furthermore, Jinja’s language-independent nature makes it a highly versatile tool, capable of being used to generate code for any text-based language, including mobile applications. To effectively bridge the gap between our high-level variability models and the code generation process, our approach relies on UVengine [23]. This universal variability resolution engine is specifically designed to resolve UVL models over Jinja templates. Its utility has been demonstrated in practical scenarios across diverse domains and artifact types, such as: Visualization pipelines to generate data visualization charts with configurable visual components and datasets [20, 34]; Kubernetes configurations to derive deployment descriptors for microservices and containers, adapting resource constraints based on the Kubernetes feature model [22]; and Data migration processes to generate reusable transformation scripts in data migration between heterogeneous content management systems [33]. However, to the best of our knowledge, our work is the first to apply this specific generative approach to model and
exploit the internal variability of design patterns for the purpose of generating customized mobile application code. While automatic code generation is increasingly popular, especially with the rise of large language models (LLMs) [25], the resulting code often lacks architectural quality and adherence to fundamental design principles [28, 29]. Our work addresses this gap by providing a structured, model-driven approach that ensures the systematic application of design patterns, thereby promoting the generation of well-architected mobile applications. The specific context of mobile application development presents a unique challenge, as it requires a high degree of adaptability to different platforms (e.g., iOS, Android) and evolving user interfaces, while maintaining performance and code quality. By focusing on Swift and the generation of customizable design patterns, our work provides a concrete solution to the specific challenges faced by mobile developers who require scalable and maintainable solutions across different platforms and user expectations.
7
Conclusions and Future Work
In this work, we have addressed the following research question: How can the variability of design patterns be modeled and exploited to generate customized and architecturally robust mobile applications? Our principal contribution is the formalization of the internal variability of classic design patterns through the Universal Variability Language (UVL), combined with their integration into Jinja templates for the automatic generation of Swift code. This approach enables design patterns to be treated as configurable assets within an SPL approach, opening the door to mobile applications that are more flexible, maintainable, and adaptable. The analysis of the configuration space demonstrates that the variability of each pattern can be systematically and consistently captured, thus avoiding invalid configurations and ensuring correct implementations. This evidences the viability of bridging modeldriven engineering with practical mobile code generation, guaranteeing architectural quality even in the context of AI-assisted development or rapid code generation tools. For future work, we plan to expand our research in several directions: (1) expanding our catalog of supported patterns; (2) incorporating quality and maintainability metrics in the evaluation; (3) exploring integration with generative AI tools; and (4) applying this methodology to industrial-scale mobile development case studies.
Acknowledgments This work is supported by Mescyt, Universidad San Jorge, ITIS/Universidad de Málaga, and Sergio Jiménez González (Hotel Las Galias), to whom we are deeply grateful.
References [1] Sven Apel, Don S. Batory, Christian Kästner, and Gunter Saake. 2013. FeatureOriented Software Product Lines - Concepts and Implementation. Springer. doi:10. 1007/978-3-642-37521-7 [2] Ebrahim Bagheri and Dragan Gasevic. 2011. Assessing the maintainability of software product line feature models using structural metrics. Software Quality Journal 19 (09 2011), 579–612. doi:10.1007/s11219-010-9127-2 [3] David Benavides, Chico Sundermann, Kevin Feichtinger, José A. Galindo, Rick Rabiser, and Thomas Thüm. 2025. UVL: Feature modelling with the Universal Variability Language. J. Syst. Softw. 225 (2025). doi:10.1016/j.jss.2024.112326 [4] Francisco Sebastian Benitez, José A. Galindo, David Romero-Organvidez, and David Benavides. 2025. UVL web-based editing and analysis with flamapy.ide.
R. Peralta et al.
In 19th International Working Conference on Variability Modelling of SoftwareIntensive Systems (VaMoS). 121–125. doi:10.1145/3715340.3715436 [5] Paul Clements and Linda Northrop. 2001. Software Product Lines: Practices and Patterns. [6] Alejandro Cortiñas, Miguel R. Luaces, and Oscar Pedreira. 2022. spl-js-engine: a JavaScript tool to implement software product lines. In 26th ACM International Systems and Software Product Line Conference (SPLC), Vol. B. 66–69. doi:10.1145/ 3503229.3547035 [7] Krzysztof Czarnecki and Ulrich W. Eisenecker. 2000. Generative programming methods, tools and applications. Addison-Wesley. [8] Krzysztof Czarnecki, Simon Helsen, and Ulrich W. Eisenecker. 2005. Formalizing cardinality-based feature models and their specialization. Softw. Process. Improv. Pract. 10, 1 (2005), 7–29. doi:10.1002/spip.213 [9] Leonardo Filipe da Silva, Paulo Afonso Parreira Junior, and André Pimenta Freire. 2022. Mobile User Interaction Design Patterns: A Systematic Mapping Study. Information 13, 5 (2022). doi:10.3390/info13050236 [10] Thomas Degueule, Joao Bosco Ferreira Filho, Olivier Barais, Mathieu Acher, Jérôme Le Noir, Sébastien Madelénat, Grégory Gailliard, Godefroy Burlot, and Olivier Constant. 2015. Tooling support for variability and architectural patterns in systems engineering. In 19th International Conference on Software Product Line (SPLC). ACM, 361–364. doi:10.1145/2791060.2791097 [11] Alexander Felfernig, Andreas A. Falkner, and David Benavides. 2024. Feature Models - AI-Driven Design, Analysis and Applications. Springer. doi:10.1007/9783-031-61874-1 [12] Jaime Font, Lorena Arcega, Øystein Haugen, and Carlos Cetina. 2015. Building software product lines from conceptualized model patterns. In 17th International Software Product Line Conference (SPLC 2015). 46–55. [13] Eric Freeman, Elisabeth Freeman, Bert Bates, and Kathy Sierra. 2004. Head First Design Patterns (1 ed.). O’Reilly Media. [14] José A. Galindo, José Miguel Horcas, Alexander Felfernig, David FernándezAmorós, and David Benavides. 2023. FLAMA: A collaborative effort to build a new framework for the automated analysis of feature models. In 27th ACM International Systems and Software Product Line Conference (SPLC), Vol. B. ACM, 16–19. doi:10.1145/3579028.3609008 [15] José A. Galindo, David Romero-Organvidez, Megha Bhushan, José Miguel Horcas Aguilera, and David Benavides. 2024. Open Science principles in software product lines: The case of the UVL ecosystem. In 28th ACM International Systems and Software Product Line Conference (SPLC), Vol. A. 223. doi:10.1145/3646548.3674550 [16] José A. Galindo, David Romero-Organvidez, Megha Bhushan, José Miguel Horcas Aguilera, and David Benavides. 2024. Open Science principles in software product lines: The case of the UVL ecosystem. In 28th ACM International Systems and Software Product Line Conference (SPLC), Vol. A. 223. doi:10.1145/3646548.3674550 [17] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. 1995. Design patterns: elements of reusable object-oriented software. Pearson GmbH. [18] Øystein Haugen, Birger Møller-Pedersen, Jon Oldevik, Gøran K. Olsen, and Andreas Svendsen. 2008. Adding Standardized Variability to Domain Specific Languages. In 12th International Conference on Software Product Lines (SPLC). IEEE Computer Society, Limerick, Ireland, 139–148. doi:10.1109/SPLC.2008.25 [19] José Miguel Horcas, Alejandro Cortiñas, Lidia Fuentes, and Miguel R. Luaces. 2022. Combining multiple granularity variability in a software product line approach for web engineering. Inf. Softw. Technol. 148 (2022), 106910. doi:10. 1016/J.INFSOF.2022.106910 [20] José Miguel Horcas, José A. Galindo, and David Benavides. 2022. Variability in data visualization: a software product line approach. In 26th ACM International Systems and Software Product Line Conference (SPLC), Vol. A. 55–66. doi:10.1145/ 3546932.3546993 [21] José Miguel Horcas, José A. Galindo, Lidia Fuentes, and David Benavides. 2025. FM fact label. Sci. Comput. Program. 240 (2025). doi:10.1016/J.SCICO.2024.103214 [22] José Miguel Horcas, Mercedes Amor Pinilla, and Lidia Fuentes. 2025. The Kubernetes variability model. In 19th International Working Conference on Variability Modelling of Software-Intensive Systems (VaMoS). doi:10.1145/3715340.3715440 [23] José Miguel Horcas, Mónica Pinto, and Lidia Fuentes. 2025. UVengine: A Universal Variability Resolution Engine for Feature Models Using Template-Based Artifacts. In 29th ACM International Systems and Software Product Line Conference (SPLC), Vol. B. ACM, A Coruña, Spain. doi:10.1145/3748269.3748486 [24] Claus Hunsen, Bo Zhang, Janet Siegmund, Christian Kästner, Olaf Leßenich, Martin Becker, and Sven Apel. 2016. Preprocessor-based variability in opensource and industrial software systems: An empirical study. Empirical Software Engineering 21, 2 (2016), 449–482. doi:10.1007/s10664-015-9360-1 [25] Juyong Jiang, Fan Wang, Jiasi Shen, Sungju Kim, and Sunghun Kim. 2024. A Survey on Large Language Models for Code Generation. CoRR abs/2406.00515 (2024). doi:10.48550/ARXIV.2406.00515 arXiv:2406.00515 [26] Kyo C Kang, Sholom G Cohen, James A Hess, William E Novak, and A Spencer Peterson. 1990. Feature-oriented domain analysis (FODA) feasibility study. Technical Report. Carnegie-Mellon Univ Pittsburgh Pa Software Engineering Inst. https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=11231 [27] Gregor Kiczales, John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc Loingtier, and John Irwin. 1997. Aspect-oriented programming. In
European conference on object-oriented programming. Springer, 220–242. [28] Farooq Mulla. 2024. Choosing the Best Architecture for Mobile Applications. ResearchGate Publication, December (2024). [29] Tam The Nguyen, Phong Minh Vu, Hung Viet Pham, and Tung Thanh Nguyen. 2018. Deep learning UI design patterns of mobile apps. In 40th International Conference on Software Engineering (ICSE): New Ideas and Emerging Results. ACM, 65–68. doi:10.1145/3183399.3183422 [30] Daria Orlova and Esra Kadah. 2024. Flutter Design Patterns and Best Practices. Packt Publishing. [31] Klaus Pohl, Günter Böckle, and Frank van der Linden. 2005. Software Product Line Engineering - Foundations, Principles, and Techniques. Springer. doi:10.1007/3540-28901-1 [32] Lumpapun Punchoojit and Nuttanont Hongwarittorrn. 2017. Usability Studies on Mobile User Interface Design Patterns: A Systematic Literature Review. Advances in Human-Computer Interaction 2017, 1 (2017), 6787504. doi:10.1155/2017/6787504 arXiv:https://onlinelibrary.wiley.com/doi/pdf/10.1155/2017/6787504 [33] David Romero-Organvidez, David Benavides, José Miguel Horcas, and María Teresa Gómez-López. 2024. Variability in data transformation: towards data migration product lines. In 18th International Working Conference on Variability Modelling of Software-Intensive Systems (VaMoS). doi:10.1145/3634713.3634724 [34] David Romero-Organvidez, José Miguel Horcas, José A. Galindo, and David Benavides. 2024. Data visualization guidance using a software product line approach. J. Syst. Softw. 213 (2024), 112029. doi:10.1016/J.JSS.2024.112029 [35] Ina Schaefer, Lorenzo Bettini, Ferruccio Damiani, and Nico Tanzarella. 2010. Delta-oriented Programming of Software Product Lines. In 14th International Conference on Software Product Lines (SPLC): Going Beyond. Springer-Verlag, 77–91. http://dl.acm.org/citation.cfm?id=1885639.1885647 [36] Christoph Seidl, Sven Schuster, and Ina Schaefer. 2017. Generative software product line development using variability-aware design patterns. Computer Languages, Systems & Structures 48 (2017), 89–111. doi:10.1016/j.cl.2016.08.006 [37] Alexander Shvets. 2018. Dive into design patterns. Refactoring. Guru. [38] Chico Sundermann, Kevin Feichtinger, Dominik Engelhardt, Rick Rabiser, and Thomas Thüm. 2021. Yet another textual variability language?: a community effort towards a unified language. In 25th ACM International Systems and Software Product Line Conference (SPLC), Vol. A. 136–147. doi:10.1145/3461001.3471145 [39] Chico Sundermann, Tobias Heß, Dominik Engelhardt, Rahel Arens, Johannes Herschel, Kevin Jedelhauser, Benedikt Jutz, Sebastian Krieter, and Ina Schaefer. 2021. Integration of UVL in FeatureIDE. In 25th ACM International Systems and Software Product Line Conference (SPLC), Vol. B. doi:10.1145/3461002.3473940 [40] Chico Sundermann, Stefan Vill, Thomas Thüm, Kevin Feichtinger, Prankur Agarwal, Rick Rabiser, José A. Galindo, and David Benavides. 2023. UVLParser: Extending UVL with Language Levels and Conversion Strategies. In 27th ACM International Systems and Software Product Line Conference (SPLC). ACM, Tokyo, Japan, 39–42. doi:10.1145/3579028.3609013 [41] Eugene Syriani, Lechanceux Luhunu, and Houari A. Sahraoui. 2018. Systematic mapping study of template-based code generation. Comput. Lang. Syst. Struct. 52 (2018), 43–62. doi:10.1016/j.cl.2017.11.003 [42] Luciana A.M. Zaina, Renata P.M. Fortes, Vitor Casadei, Leornardo Seiji Nozaki, and Débora Maria Barroso Paiva. 2022. Preventing accessibility barriers: Guidelines for using user interface design patterns in mobile applications. Journal of Systems and Software 186 (2022), 111213. doi:10.1016/j.jss.2021.111213