Sprint 4 Deliverable - ISIS-3510-Grupo-35/Application-Backend GitHub Wiki
Table of contents
Selected problem
We selected a problem we as students have experienced in the past and even more so in recent years, as the amount of university students reaches all time highs; available parking spots around campus. It's becoming harder to find good parking lots where the price is reasonable and you feel safe leaving your car there. There are some prefered parking lots by students, which means that by 8am, all parking spots in this location are already taken, and have been for some time, with students arriving as early as 6am in order to park here. We noticed that if a student had class later in the day (at 11 am for example) it would be imposible for him to get a parking spot there. The alternative options people know about are already taken as well because the amount of students, professors, faculty members and different people that gather on campus. So, how is someone supposed to know different parking lots available around campus, the amount of spots avaible at a certain time in campus, and how much they cost if its not trying them one by one? Author: Tomas Angel
Proposed solution
Our solution, is to create a mobile app in which a person can visualize ALL of the available parking lots around campus along witht he amount of spots avaible at the moment they search for options. We would also include a detailed description of the cost of the parking lot and the amount of time the daily fee covers for a person and how much it costs per minute. Alongside our solution, we would like to give students the option of booking a parking spot at a location in a certain range of time. For example, on tuesdays I would like to park at the Santo Domingo building, and I would do so from 11am until 9pm. This booking would have to be payed up front to avoid people that never show up after a reservation. In a country such as Colombia, people aren't always true with their word, and so, if someone who booked a parking slot doesn't show up 15 minutes after the time he was supposed to be there, the slot will be open for someone else to grab it without having a refund option. Author: Tomas Angel
Value proposal
Our app provides a convenient and efficient solution for campus parking by offering reserved spots for regular users, including students and faculty. Users benefit from guaranteed parking availability and the ability to plan their visit in advance, reducing the stress and time spent searching for parking. Additionally, parking lot owners gain targeted exposure through our platform, with advertising opportunities that enhance their visibility to potential customers. Author: Tomas Angel
Revenue model
The revenue model for the app is centered around premium privileges, as its primary function is to simplify parking for regular campus visitors, including students and faculty. To access reserved parking spots, users will need to pay a fee for this privilege. Our model involves charging a nominal fee to users who wish to reserve a spot in advance at their preferred parking lot. Additionally, we plan to generate revenue through advertising partnerships with parking lot owners. The visibility of their parking lot in the app will be proportional to the amount they invest in advertising. Lastely, as we aim to have an app for the campus university, we could show ads of the restaurants in the area in order for people to find new places to eat. This three sources of income would be sufficient for the app to run, but our prime source would be to pay for a parking spot before hand. Author: Tomas Angel
Collected data
The data we were able to collect in the development of the sprints were stored on Google Firebase, a backend service to develop mobile apps. For Unipark (our app), we established 5 collections in total, including Occupation (to know a parking lots occupancy and avalailable spots), Parking lots (with all the important information fo them such as address, plain fee, price per minute, opening hours, and more), Reservations (relating a user witha a parking spot, the hours he will be using it and the total cost of it), Reviews (to know people's experience using a parking lot), and finally the users of the app (with a registered email). The information gathered here helps to develop the business questions we've implemented and those that will stay in the backlog while we continue to develop the app, as we aim to eventually launch a funtional product useful for people. Author: Tomas Angel
Business questions
Sprint 2
- Type 1: How often do users experience slow load times when searching for available parking spots? This targets performance issues related to the speed of retrieving parking spot data, a crucial aspect of user experience that can indicate server or database lag.
- Type 2: Which parking spots have a rating higher than 4.5 around a given location?
This is a Type 2 question as it is useful for users and is answered directly within the app. To answer it, a filtering process must be performed by the analytics engine. - Type 3: What percentage of users utilize the app's online reservation system to book parking spots in a day? This information is useful to analyze if the users are using the functionality or if it should be removed.
- Type 2: In which parking lots around the user's location is it necessary to leave keys? This is a Type 2 question as it is of interest to users and should be answered by querying the analytics engine to identify parking spots that meet the given condition. Flutter - Juan Manuel Perez
Sprint 3
- Type 2: How many people are benefiting from last minute free slots at parking lots during normal business hours? As part of our solution, parking spots that were reversed but the person didn't show up within the first 15 minutes of the established time of the reserve will be free for anyone to grab. With this question, we would like to know how many people use the notification system informing theres a free parking spot in normal business hours from 8AM until 5PM. Is it a feature people are using to make a reservation? Or do they just keep looking around in case they don't find any available slots? Author: Tomas Angel
- Type 3: What percentage of users utilize the app's online reservation system to book parking spots in a day? This information is useful to analyze if the users are using the functionality or if it should be removed.
- Type 5: Which parking lots around campus are most frequently booked during peak hours (e.g., 6:30 am to 9:30 am), and how can we optimize pricing or introduce incentives to encourage students to use alternative parking lots during these times?
- Type 2: Which parking spots have a rating higher than 4.5 around a given location? This is a Type 2 question as it is useful for users and is answered directly within the app. To answer it, a filtering process must be performed by the analytics engine. Author: Ingrith Barbosa
Sprint 4
- Type 5: Which parking lots around campus are most frequently booked during peak hours (e.g., 6:30 am to 9:30 am), and how can we optimize pricing or introduce incentives to encourage students to use alternative parking lots during these times? Author: Tomas Angel
- What percentage of users utilize the app's online reservation system to book parking spots in a day? This information is useful to analyze if the users are using the functionality or if it should be removed.
- How frequently do users update or modify their reservations? This question is aimed at analyzing user engagement with the flexibility of the booking system, providing insights on whether additional features or adjustments are needed to improve usability.
Implemented Features:
Sprint 2:
Log in Log out Create a user as a driver Search locations on the map View parking spots near the location See parking spot details Filter by highest-rated parking spots
Sprint 3:
View the user profile Make a reservation in a parkinglot See the detials of common parking lots in some universities while offline Notification system to alert a user there are no more parking spots available for a specific parking lot
Sprint 4:
See the details of a reservation Add budget Modify reservation
Eventual Connectivity:
For the UniPark app, we designed connectivity solutions that address the challenges of intermittent and poor network conditions, as users may experience fluctuating connectivity on campus. Our goal was to ensure that the app remains usable even when connectivity is inconsistent, so users can rely on it to find parking spaces in real-time. It's important to note that the app also needs live feedback in order to work, which means that connectivity is a very big deal for us, however, we evaluated the following connectivity scenarios for the app:
Eventual Connectivity Scenarios:
Title/ID | Offline Mode |
---|---|
Event description | User is using the app and connection is lost |
System response | When the app detects no network connection, it switches to offline mode. In this state, users can still view previously loaded parking data from the local cache, allowing them to make informed parking choices based on recent availability. However, they won't be able to reserve spots or receive real-time updates until the connection is restored. The app also has some default data preinstalled, which means that the information of the most common parking lots is already downloaded with the app in case there is no connection. |
Possible Antipatterns | Blocked application, Non-informative message , Lost content (Blank map, user content) |
Caching and retrieving strategy | Network falling back to cache |
Storage type | Local > Private > Storage > Cache |
Stored data type | Core Data (for essential information like parking spot details, prices, and user preferences), UserDefaults (for lightweight data like most recent parking lot view). |
Title/ID | Intermittent Connectivity |
---|---|
Event description | The user moves between buildings, underground areas, or is in locations where the connection is not stable |
System response | For situations where network connection is sporadic, the app operates in a "sync-on-availability" mode. Data is queued locally, and the app periodically attempts to sync reservations or status updates with the backend when connectivity resumes. This allows users to initiate actions that the app will complete once a stable connection is detected. |
Possible Antipatterns | Blocked application, Non-informative message , Lost content (Blank map, user content), Non-existent result notification |
Caching and retrieving strategy | Network falling back to cache |
Storage type | Local > Private > Storage > Cache |
Stored data type | Core Data, Temporary Queue Data Structure |
Title/ID | Low Bandwidth/Slow Network |
---|---|
Event description | Users experience a slow network |
System response | The app prioritizes lightweight data requests, loading essential information (e.g., available spots, prices) while deferring non-critical updates like reviews. The interface will notify users with a loading indicator and delayed content messaging. |
Possible Antipatterns | Blocked application, Non-informative message , Non-existent result notification |
Caching and retrieving strategy | Network falling back to cache |
Storage type | Local > Private > Storage > Cache |
Stored data type | Core Data, In-Memory Cache |
Local Storage Strategies:
Our local storage strategies ensure that key information is available even without a network. We use core data and UserDefaults for managing local data:
-
Core Data for Persistent Data:
- Core Data stores essential data like available parking spots, prices, parking lot details, and user preferences. This way, the app has cached data ready, even if offline. Data is periodically synced in the background to keep it updated. Part of the app has some parkinglots preloaded so users can still view them in case there is no connectivity but they still need to know the information of a parkinlot.
-
UserDefaults for Lightweight Data:
- Simple settings and most recently viewed parking lots, are stored in UserDefaults. This ensures that user-specific configurations persist without taking up much space.
-
SharedPreferences for User Credentials:
- We saved the user credentials to the FireBase API, so if the users close the app, if they initialy logged in successfully they dont need to login again.
Multi-Threading Strategies:
To manage multi-threading effectively, we rely on Grand Central Dispatch(GCD) and Swift’s async/await syntax for asynchronous operations:
-
Grand Central Dispatch (GCD):
- GCD is used to handle background tasks like data sync with the server or saving data in Core Data. This avoids blocking the main thread and ensures a responsive user interface. For example, data fetches are handled in the background, then displayed on the main thread once complete. The GCD also manages the queue's of requests made while having connectivity and when there is no connectivity.
-
Async/Await for Promises:
- For network calls or database operations where completion handlers are required, we use Swift’s async/await syntax, which simplifies managing promises and sequential async operations. This allows smooth chaining of operations, such as fetching parking data, caching it, and then displaying it without blocking the main thread.
-
Async/Await for Futures:
- For network calls or database operations where completion handlers are required, we use Flutter’s async/await syntax, which simplifies managing promises and sequential async operations. This allows smooth chaining of operations, such as fetching parking data, caching it, and then displaying it without blocking the main thread.
Caching Strategies:
Our caching strategy is implemented to reduce network requests and enhance speed, using a combination of in-memory caching and Core Data caching:
-
In-Memory Caching:
- Recent or frequently accessed data, like a user’s current parking lot selection, is stored in memory. This allows instant access without querying Core Data or making network calls. We use a simple dictionary cache to store data temporarily.
-
Core Data Caching:
- Core Data serves as a persistent cache for data fetched from the network, ensuring data is available when offline and reducing redundant API calls. This data is periodically refreshed in the background, ensuring users see near-real-time data while minimizing bandwidth usage.
-
Image Fallback to network:
- When an image is requested, the system first checks the local cache. If the image is not available in the cache (cache miss), the system then makes a request to the origin server or a predefined backup network source to retrieve the image. Once the image is retrieved from the network, it is usually added to the cache so that subsequent requests can be served faster and reduce future reliance on the network.
Micro-optimizations and profiling tools
Swift
Profiling before micro-optimizations
It’s important to mention that we experienced severe problems with the first version of the app we had. Which is why we decided to make a second version. In repositories there is the first version of our app called ‘Aplicacion-Swift’, but for this sprint we worked on the one that says ‘Aplicacion-SwiftV2’. After running the app with the Instruments (Apples own profiling tool), we were able to notice several things from the CPU usage, GPU usage, the different calls it makes to local storage and the repository, and more. The profiling was made on a real device. We simulated the use of the app for a minute, interacting with different views and making different calls to the back end like logging into the app and logging out. The following image is from the Activity monitor instrument.
For starters, we can see from the image above the CPU usage during the entire test. There is a spike in the CPU usage when the app is starting, as it looks for the information in the device and then falls for backend updates. This could explain the peak usage of 350.2% of the CPU total load. After that, the usage comes down for a while but then it has another spike although not as big as when the app first starts. This happened during the log out and log in of the app. The lowest it came down to was 31.7% of the CPU total load. The following image is from the Thermal State instrument:
This instrument tells if the device is at normal operating temperatures, and there's no need for any corrective action on the app by overheating. The thermal state of the phone is always staying in normal which is already a good sign. The following image is from the Allocations instrument:
‘Allocations’ analyzes the memory life-cycle of the process allocated blocks. It tracks the size and number of all heap and anonymous virtual memory (VM) allocations and organizes them by category. From what is seen on the image, there is some sort of jigsaw pattern in the heap use, having spikes in use, maintaining it, and then dropping it. There is however, on spike bigger than the rest and this happened while interacting with the map, probably because there is a need for the app to load more places in the map as you navigate through it to different spots. The highest usage here, was 200.4 mB, which is considerable for a phone and could improve. The following image is from the GPU instrument:
The GPU instrument analyzes the graphic performance of the app, including how much does some elements overlap with each other. The image above presents several segments in which the GPU is in full use for several parts. This specially happened during the use of the map and exploring the surroundings of it as well. A cool feature from the profiling tool is the analysis done for the chip the phone has, which in this case is the A14. It breaks the analysis done in 3 aspects; the vertex stage which processes the individual vertices of a 3D model, the fragment stage which processes fragments or potential pixels on the screen that result from rasterizing the primitives (like triangles) defined by vertices, and the compute workloads which refer to general-purpose computations on the GPU that don't necessarily fit into the traditional rendering pipeline (vertex and fragment). From what the graph shows, there is a lot of room for improvement on the GPU as it can sometime be overdrawing for some of the views in the app.
Last but not least, we use different strategies for handling threads, such as promises and the Grand Central Dispatcher. This can be seen from the Time Profiler which is the instrument that helps profile the different threads. The image shows a generally good use of the threads but there are occasional spikes on the different CPU’s that are being used when interacting with the map. This is the main concern done from this first profiling and an aspect in which we will start to implement micro-optimizations.
Micro-Optmizations
The first component to edit and implement a micro-optimization was in the 'ListingMapView' which was the main cause of the CPU load and heap to increase significantly.
Here we centralizes the animation logic and it improves readability as the animation is used several times along different views as well.
The second micro-optimization is on the map markers for each location. In the original implementation, the Map view uses a ForEach loop with id: .self to identify each item in the listings array. While this approach works if the Listing model conforms to both Identifiable and Hashable, it can introduce ambiguity. By relying on the entire object (\ .self) for identification, the code becomes less type-safe and harder to maintain if the data model evolves. Additionally, the inline logic for creating Marker elements is tightly coupled with the ForEach loop. This not only clutters the Map code but also makes it harder to reuse marker-related functionality elsewhere in the app.
The optimized version addresses these issues by explicitly tying the ForEach loop to the id property of the Listing model. This ensures that the loop identifies each item directly by its unique identifier, improving type safety and reducing potential ambiguity. Moreover, the creation of the Marker elements is encapsulated in a separate MarkerView component. This modular approach separates concerns, making the main Map view easier to read and maintain while allowing marker-related logic to evolve independently. By extracting the marker creation logic into a reusable MarkerView, the code gains flexibility and scalability. If the app requires customizations to the markers, such as adding icons, styles, or interactions, these changes can now be made in one centralized location without modifying the Map code. This separation not only improves readability but also streamlines the development process, making the codebase more robust and easier to extend in the future. Ultimately, these changes enhance both the maintainability and usability of the ListingMapView component.
The third micro-optimization is done on the profile view, as the rendering of components was slow while making the different calls to the server. The explicit initializer in the ProfileView struct can be removed. Since the authManager property is already defined as a parameter with @ObservedObject, SwiftUI automatically generates a suitable initializer. Removing the explicit init reduces boilerplate code.
We also reused the ProfileOptionRowView for Common Options The profile option rows can be created dynamically using an array of option details. This reduces repetition and allows easy modifications if more options are added later.
We separated it into its own component by doing the following:
Makes the code more scalable and avoids hardcoding repetitive UI elements.
Flutter
We used the Flutter Profiler tool to analyze the app performance. Throughout the course we tried to use the most type of micro-optimizationd and best practices. So when analyzing the code we didn´t had to make many micro-optimizations. The results of our profiling where the following:
Login View:
UI:
The shader compilation in the earlier chart is the primary cause of the significant spike and associated jank. This often occurs during the first render of certain elements or when new shaders are created dynamically at runtime. Specifically becuase the image that is been rendered comes from src from a png. This can be an improvement to the code as the image is only used at this starting page.
Memory:
The memory chart shows a moderate total memory usage of 81.65 MB, with an RSS (Resident Set Size) of 135.35 MB, indicating additional overhead beyond explicit allocations. The Dart/Flutter memory is relatively low at 6.37 MB, while native memory (14.37 MB) and graphics memory (14.09 MB) suggest preloaded assets or system-level integrations. The code memory is notably high at 30.95 MB, which could be due to debug symbols or extensive compiled instructions. Both Raster Layer and Raster Picture show 0 B, indicating no active graphical rendering. Java and stack memory are minimal, at 4.11 MB and 528 KB, respectively. Overall, the app appears idle with no significant rendering or memory spikes but shows areas for potential optimization, particularly in code memory and native integrations.
Threads:
Regarding the use of threads, the only use of threads is in the main thread as we only uses Futures.
Map View:
UI:
The Map view loads after the login, as we can see on the UI Performance graph we can see that the times are below 17 ms which are expected on a Flutter app.
Memory:
In terms of the memory we can see a slightly increase in the memory consumption, this is caused because after the loginm there is a load of the the information of the parking lots, we can see it increases to 271.32 MB.
Threads:
Regarding the use of threads, the only use of threads is in the main thread as we only uses Futures.
Search and reservation:
UI:
On the UI of the Search and reservation we can see that the bars that are red and show alerts are caused because of the loading and rendering of images, even though it causes an alert this is an async process that has a loasing screen on the list view tile. Therefore the user just experiences lag on the load of the image, but can use the app normally.
Memory:
The memory we can see that increases as it has a cache of the images and it increases to 293.94, but we can see that when we change of view to reservations as they are cahced there isnt request made and the memory lowers.
Threads:
Regarding the use of threads, the only use of threads is in the main thread as we only uses Futures.
List of implemented features
Currently, the application has the following functionalities:
- Log in
- Log out
- Create a user as a driver or parking lot owner
- Search locations on the map
- View parking spots near the location
- See parking spot details
- Filter by highest-rated parking spots
- View the user profile
- Make a reservation in a parkinglot
- Se the details of a reservation
Functionality that uses one sensor of the phone
The application for Android and iOS uses the phone’s GPS to locate the user on the map. To access the location, the corresponding authorization is requested, indicating that it is necessary to show nearby parking spots and ensure the correct functioning of the application.
Functionality that answers type 2 question
To answer one of the type 2 questions, we added the functionality to filter the list of parking spots by those that are highest rated. This filter allows users to view only parking spots with a rating higher than 4.5. This result is displayed directly in the application and can be accessed by the client without needing to perform additional operations.
Functionality that is considered smart feature
Flutter:
- Show Pop-up if near the parking spot to save the car and when near pop up showing to leave.
Funtionality that allows users authentication
The functionality that enables user authentication is achieved through the Firebase Authentication platform. It allows users to create an account with an email and password and access the application's features using these credentials.
Funtionality that uses external services
As an external service, we use Firebase, a mobile application development platform by Google that offers powerful features for building, managing, and improving applications. Some of the standout features of the Google Firebase platform include databases, authentication, push notifications, analytics, file storage, and more. Specifically for our application, we have deployed the database in Firebase Firestore, utilize the authentication service, and will address business questions through the analytics engine it provides. Show the location of the parking lots on the map as a marker. Additionally, to display the map and locate the user and parking lots in the Android application, we used the GCP platform, which provides access to the Google Maps API.
Ethics video
Click here to access the ethics video