Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/simonberner/githubfollowme
An iOS16+ App to get and show followers from GitHub :octocat:
https://github.com/simonberner/githubfollowme
async-await codable combine feature-flags ios roadmap screen-enum-pattern swift5 swiftui uikit webkit xctest xcuitest
Last synced: 7 days ago
JSON representation
An iOS16+ App to get and show followers from GitHub :octocat:
- Host: GitHub
- URL: https://github.com/simonberner/githubfollowme
- Owner: simonberner
- License: mit
- Created: 2022-04-13T07:31:50.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-07-29T11:35:10.000Z (over 1 year ago)
- Last Synced: 2023-07-29T12:38:56.185Z (over 1 year ago)
- Topics: async-await, codable, combine, feature-flags, ios, roadmap, screen-enum-pattern, swift5, swiftui, uikit, webkit, xctest, xcuitest
- Language: Swift
- Homepage:
- Size: 6.77 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
GitHub Follow Me
Hello and welcome!
This is another portfolio App of mine and reflects my current iOS development skills with Swift and SwiftUI.
You are welcome to have a look at my project. Feedback is highly appreciated and creating a [new issue](https://github.com/simonberner/githubfollowme/issues/new) makes you an ace. π---
## Contents
* [Functionality](#functionality-)
* [Screens](#screens-)
* [Tour](#tour-)
* [Tech Stack](#tech-stack-)
* [Take-Me-Home Project](#take-me-home-project-)
* [Architecture](#architecture-)
* [Libraries](#libraries-)
* [Device Requirements](#device-requirements-)
* [How to run](#how-to-run-%EF%B8%8F)
* [Common Take-Me-Home Project Tasks](#common-take-me-home-project-tasks-)
* [Beyond the scope](#beyond-the-scope-)
* [What interviewers might be looking for](#what-interviewers-might-be-looking-for-)
* [Tips for the interviewee](#tips-for-the-interviewee-)
* [Learnings](#learnings-)
* [Testing](#testing-)
* [Worklog](#worklog-)
* [Improvements and Ideas](#improvements-and-ideas-)
* [Junior, Mid, Senior, Lead, Principal, Architect?](#junior-mid-senior-lead-principal-architect-)
* [Blogs](#blogs-)
* [Credits](#credits-)---
## Functionality πΌ
The functionalities of this App are not rocket science. But still, they show in a nice way, how one can use the GitHub API
to build some cool stuff.
- Search for all the followers of a specific GitHub user.
- View the profile of a selected follower.
- Get all the followers of a selected follower.
- Show the GitHub Profile of a selected follower in an embedded web view.
- Add/remove a follower as a favorite to/from a list of favourites.
- Get and show all the followers of a selected favorite.
- Give your unique vote on a next upcoming feature! Currently only available in a debug build (I am experimenting with feature flags at the moment).## Screens πΊ
| Main View Light | Main View Dark |
| :---: | :---: |
| | || Followers View | Detail View | Favorites View |
| :---: | :---: | :---: |
| | | |## Tour π¦
![Tour](AppScreenshots/gfm-tour.gif)## Take-Me-Home Project π¨π½βπ»
A usual take-me-home project should not take you longer than 2 - 5 hours of work. Based on that, only some parts of this App can be taken as an example
for how a Take-Me-Home Project for a iOS Developer position could look like.
To develop the full App as part of the interview process, is way off the trail, but at least some parts of it should be feasible doing.
Depending on the [experience level](#junior-middle-senior-expert-lead-architect-) of a candidate, the scope can be cut down or enlarged accordingly.## Tech Stack π‘
- Xcode 14.3.1
- Swift 5.8.1
- [SwiftUI](https://developer.apple.com/documentation/swiftui)
- [Codable](https://developer.apple.com/documentation/swift/codable)
- [Combine](https://www.avanderlee.com/swift/combine/)
- [WebKit](https://developer.apple.com/documentation/webkit)## Architecture π
This App is build with the [MV State Pattern (State Pattern/Model View pattern)](https://azamsharp.com/2022/08/09/intro-to-mv-state-pattern.html) in mind.
- It is an architectural design pattern, also called the: ModelView Global State Pattern
- GFMService class is the Aggregate Root which provides the global state and is used by all the views to get the data they need.
- There are no separate view models per screen when using the MV State Pattern.
- To make the GFMService accessible easily in all views, a gfmService instance is injected as an @EnvironmentObject in the GFMTabView.
- The biggest complain, when building large Apps with tons of views is, that when using @EnvironmentObjects since it is a global state, if the state gets updated then a lot of views will be needlessly rendered. We can easily avoid that by slicing the global state into smaller pieces. You can read about it [here](https://azamsharp.com/2022/07/01/slicing-environment-object.html).\
### A word on MVVM
- If we would use the MVVM pattern for this App, we would create an @ObservedObject/@StateObject viewModel for every view. [But just don't, don't use MVVM for SwiftUI!](https://azamsharp.com/2022/07/17/2022-swiftui-and-mvvm.html)
- SwiftUI does not need MVVM pattern, actually MVVM acts as an anti-pattern when building SwiftUI applications.
- With its @State, @EnvironmentObject, @StateObject property wrappers (also called view model bindings), a View in SwiftUI also acts as a View Model.## Libraries π
- [Roadmap](https://github.com/AvdLee/Roadmap)## Device Requirements π±
This App runs on an iPhone with iOS 16+## How to run βΆοΈ
This App is not available on the AppStore or through TestFlight. You have to build it yourself on your machine.
1. Fork or clone this repo
2. Open the .xcodeproj project file in Xcode
3. Build the project
4. Choose an iOS16+ simulator
5. Start the active scheme by clicking the βΆοΈ button in the menu bar of Xcode
6. After the App has started on the chosen iPhone simulator: Enjoy!
7. If you want to have a SwiftLint in place for the code, have a look [here](https://github.com/realm/SwiftLint#installation)PS. You also may need to have a look at your 'Signing & Capabilities' of the App Target
## Common Take-Me-Home Project Tasks π
- Do some small design
- Make a network call to an API
- Retrieve the data and parse the JSON (e.g. from a GraphQL query)
- Display the data in a pretty UI
- Apply some design patterns
- Add some Unit-Tests
- Write a great README (like this one here π)
### Beyond the scope
The following things can/will impress, but are in most cases way beyond the scope of a take me home project:
- Error handling -> add custom alerts
- Error handling -> handle each possible HTTPURLResponse code
- Logging ([OSLog](https://developer.apple.com/documentation/oslog))
- [SwiftLint](https://github.com/realm/SwiftLint)
- Caching of images (which have to be downloaded)
- An extensive suite of Unit-Tests
- UI-Tests
### What interviewers might be looking for
- The given time frame for building such an App, is not what matters most
- What are the persons's first steps for building the app?
- Are there any design drawings present?
- App-Icon? (Might be a nice final touch and give you some extra creativity points)
- Does the project include a README (with some screens of the App)?
- How does the UI look like? -> Apple design guidelines
- Are the given tasks completed?
- Does the App actually do what it is supposed to do?
- Design Patterns?
- Upload in TestFlight?
- No crashes (handling of optionals?)
- Testing: Unit-Tests? How well are the test activities documented? Real-Device Testing?
- Is [Automatic Reference Counting](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html) taken into account for instances of classes?
(Structs an enums are value types!)
- Is [premature optimization](https://stackify.com/premature-optimization-evil/) taken into account? (e.g. spending a huge amount of time for building super performant image caching)
- (Premature optimization is spending a lot of time on something that you may not actually need.)
- Validating user feedback needs to come first, before spending an enormous amount of time trying to figure out
how to scale when millions of users are using the App.
- Is the project/codebase cleaned-up at the end of the development (before it was turned in)?
- Are there any 3rd party libraries in use? If yes, what is the reason behind that?
- After you have handed in your project, the interviewer might get back to you for a second part of the interview
and ask some specific questions about the work you have done. Here some example questions:
- What did you struggle with most when building this project? How did you overcome it?
- Why did you implement the App the way you did?
- Why did you put this piece of code here and not there?
- What are your learnings in building this App?
- How and what would you improve in the future?
- What would you next work on?
- Have you already some future Testing-Strategy in mind?
- What are some edge case you haven't covered yet?
- How would you go about proper error handling and alerting?
- What are you most proud of in this project?
### Tips for the interviewee
- Have a look at [10 Traits Employers Look for When Hiring Software Engineers](https://www.codewars.com/post/10-traits-employers-look-for-when-hiring-software-engineers)
- Try to articulate as best as you can the reason why you implemented something the way you implemented it
- Show that you are able to explore different solutions
- There is no 'perfect way' of implementing something, only good ways where you have to choose one to go with
- Show that you are able to look back with a critical eye at your code/solutions and improve things in the future
- Tell that you are happy to learn from your team mates, having discussions, reviews and that you consider feedback as learning opportunities
- I know that you know that one: Learning, Learning, Learning is key
- Premature Optimization: show in your commit history, that you are not striving right from the beginning to write the most clean, perfect, refactored code too soon before
you even have your functionalities working.
- Knowing what is going on in the code you write, is key.
- [Code comments and Unit-Tests](https://youtu.be/1NEa-OcsTow?t=344) are there for a reason and you might have to justify yourself why you don't (or you do) add them.## Learnings π¬
### Dashes and Hyphen
- [Never use a hyphen where an 'en dash' or an 'em dash' is required.](https://www.thepunctuationguide.com/hyphen.html)
- [en dash is slightly wider than the hyphen](https://www.thepunctuationguide.com/en-dash.html)
- [Do not mistake the em dash (β) for the slightly narrower en dash (β) or the even narrower hyphen (-)](https://www.thepunctuationguide.com/em-dash.html)
### Swift
- [Type erasure](https://www.donnywals.com/understanding-type-erasure-in-swift/) enables us to hide implementation details in our code.
- [Type Erased Async Sequences in Swift](https://iosexample.com/type-erased-async-sequences-in-swift/)
- Ternary operator can easily remembered as: W ? T : F (What ? True : False)
- [Computed Properties vs Methods](https://www.avanderlee.com/swift/computed-property/#computed-properties-vs-methods-in-swift-when-to-use-which)
- [Dates: Formatter API replaces the DateFormatter from iOS15 onwards](https://www.donnywals.com/formatting-dates-in-swift-using-date-formatstyle-on-ios-15/)
- [Dates: New Way to Format Dates in Swift (5.5)](https://www.youtube.com/watch?v=5I1ghMpU4rs)
- [Closures explained](https://www.donnywals.com/closures-in-swift-explained/)
### SwiftUI
- [GeometryReader?](https://swiftwithmajid.com/2020/11/04/how-to-use-geometryreader-without-breaking-swiftui-layout/)
- Lets you calculate the device screensize
- Caution: it fills all the available space, and usually, this is not something you want to achieve.
- [Downloading and Caching images in SwiftUI](https://www.avanderlee.com/swiftui/downloading-caching-images/)
- [SwiftUI performance tips](https://martinmitrevski.com/2022/04/14/swiftui-performance-tips/)
- [How to present a new view using sheets](https://www.hackingwithswift.com/quick-start/swiftui/how-to-present-a-new-view-using-sheets)
- Caution: The order of the applied view modifiers matters, because each of them returns a new view!
- [@StateObject vs @ObservedObject])(https://www.avanderlee.com/swiftui/stateobject-observedobject-differences/)
- Use the state object property wrapper to ensure consistent results when the current view creates the observed object. Whenever you inject an observed object as dependency, you can use the @ObservedObject.
- Observed objects marked with the @StateObject property wrapper donβt get destroyed and re-instantiated at times their containing view struct redraws.
- Use the @StateObject property wrapper to ensure consistent results when the current view creates the observed object.
- Whenever you inject an observed object as a dependency, you can use the @ObservedObject.
- [SwiftUI Search: Getting Started](https://www.raywenderlich.com/26924502-swiftui-search-getting-started)
- [EnvironmentObject](https://www.avanderlee.com/swiftui/environmentobject/#do-i-need-to-forward-environment-objects)
- [Why You Shouldnβt Use @EnvironmentObject in SwiftUI](https://betterprogramming.pub/why-you-shouldnt-use-environmentobject-in-swiftui-a527d5c2bd)
- [Open an URL in Safari](https://www.hackingwithswift.com/quick-start/swiftui/how-to-open-web-links-in-safari)
- [Search Bar in SwiftUI](https://www.appcoda.com/swiftui-searchable/)
### Regular Expressions
- [Create and Test regex](https://regexr.com/)
- [Regular Expression in Swift](https://www.advancedswift.com/regular-expressions/)
### NSPredicate
- [Examples Cheatsheet](https://nspredicate.xyz/)
### SwiftLint
- [How to use SwiftLint with Xcode](https://developerinsider.co/how-to-use-swiftlint-with-xcode-to-enforce-swift-style-and-conventions/)
- [Rule Directory](https://realm.github.io/SwiftLint/rule-directory.html)
- [.swiftlint.yml configuration](https://github.com/realm/SwiftLint#configuration)
### Architecture
#### What?
- Design patterns are abstract ways of arranging code meant to be applied to your unique codebase and requirements.
- Design patterns are not templates you have to squeeze your code into!
- Design patterns are just guidelines to help you make your code:
- Easy to understand
- Well organized
- Maintainable and easy to expand/extend/build upon it in the future
- People are often to focused on: "OMG, which design patter do we have to use? [What architecture do you use for your SwiftUI app?](https://twitter.com/dejadu13/status/1523679164397920258)
- [Viper](https://www.raywenderlich.com/8440907-getting-started-with-the-viper-architecture-pattern), MVVM?"
- [Singleton](https://developer.apple.com/documentation/swift/cocoa_design_patterns/managing_a_shared_resource_using_a_singleton)
- Convenient to have just one single global thing to share (e.g. NetworkManager, SessionManager)
- Cons because everyone can access (and maybe change it)!
- MVVM, MVC, VIPER
- [TCA - The Composable Architecture](https://dzone.com/articles/composable-architecture?edition=731522)
- [Reinventing MVC for SwiftUI with Boutique](https://build.ms/2022/06/22/model-view-controller-store/)
- Coordinator Pattern
- [TCA (The Composable Architecture)](https://www.coletiv.com/blog/an-example-of-swift-ui-and-the-composable-architecture/)
- [Getting Started With The Composable Architecture](https://www.raywenderlich.com/24550178-getting-started-with-the-composable-architecture)
- Elm?
- [Circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern)
#### Patterns
- [MV State Pattern - A Better Way of Building SwiftUI Apps](https://azamsharp.com/2022/08/09/intro-to-mv-state-pattern.html)
- [SwiftUI VODOO Architecture](https://swiftuivoodo.com/)
- [FLUXOR](https://github.com/FluxorOrg/Fluxor)
- [Awesome iOS architecture](https://github.com/onmyway133/awesome-ios-architecture#data-source)
- [SOLID Principles in Swift](https://pyartez.github.io/architecture/solid-principles-in-swift-liskov-substitution-principle.html)
- [Point free](https://www.pointfree.co/)
- [iOS Architecture Patterns](https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52)
- [iOS Design Patterns](https://www.raywenderlich.com/ios/paths/iosdesignpatterns)
- [Best architecture for SwiftUI + Combine](https://iosexample.com/best-architecture-for-swiftui-combine/)
#### MVVM architecture
- Keeps the code loosely coupled
- Increases testability (from a Unit/Integration Test perspective)
- The ViewModel role is to prepare the data NOT making network calls!
- [MVVM is NOT a good choice for SwiftUI!](https://azamsharp.com/2022/07/17/2022-swiftui-and-mvvm.html)
- [SwiftUI does not need MVVM pattern, actually MVVM acts as an anti-pattern when building SwiftUI applications!](https://azamsharp.com/2022/07/17/2022-swiftui-and-mvvm.html)
### UIKit vs SwiftUI
- What is called view in SwiftUI, are called ViewControllers in UIKit
### Codable
- [JSON Parsing in Swift explained with code examples](https://www.avanderlee.com/swift/json-parsing-decoding/)
- [Codable is an API to encode and decode data to/from a serialized format like JSON](https://www.swiftbysundell.com/basics/codable/)
- Encode to JSON
- Decode from JSON
- One can use camelCase for var names in a struct. Thankfully, both JSONEncoder and JSONDecoder provide a keyDecodingStrategy or .keyEncodingStrategy to .convertToSnakeCase.
### Guard
- [Make your intent much clearer by using the keyword: 'guard'. Use it to tell what you want, rather than the reverse.](https://www.hackingwithswift.com/new-syntax-swift-2-guard)
### Commenting code
- [The Art of Commenting in Swift](https://www.vadimbulavin.com/the-art-of-commenting-in-swift/)
### Concurrency
- Definition: Perform asynchronous and parallel operations.
- WWDC22 Apple video: [Eliminate data races using Swift Concurrency](https://developer.apple.com/videos/play/wwdc2022/110351)
#### Tasks
- perform a specific job sequentially from start to end
- are running asynchronous
- are self-contained, each task has its own resources and runs independently from all others
- [The power of task view modifier in SwiftUI](https://swiftwithmajid.com/2022/06/28/the-power-of-task-view-modifier-in-swiftui/)
#### [Actors](https://www.avanderlee.com/swift/actors/)
- Actors provide a way to isolate state that can be accessed by different tasks.
- Only one task can execute on an actor at a time, other tasks must wait their turn
- Actors are reference types but unlike classes they isolate all their internal mutable state to prevent concurrent access
- Actors execute the highest-priority work first
- Non-isolated code is code that does not run on any actor at all! Functions within actors can be explicitly marked as 'nonisolated'
- Non-isolated async code executes on the global cooperative pool
- Most of our Swift-Code is non-isolated synchronous code that is executed wherever it is called
- [Understanding Actor isolation](https://www.avanderlee.com/swift/nonisolated-isolated/)
#### @MainActor
- Is the main thread where all the interactions with the UI occurs
- Isolation to the main actor is expressed by using the @MainActor attribute
- Lots of UI framework code and app code needs to run on it
- BUT it can only run a single job at a time
- Don't put too much or long running code on to the main thread, as it will slow down your UI!
#### Async await
- [Available from Swift 5.5](https://www.hackingwithswift.com/swift/5.5/async-await)
- Before Async await: @escaping closures outlive the life of a func (because they have to wait for certain async code)
### UIKit - UICollectionViewDiffableDataSource (iOS13+)
- Is a new way to handle data for CollectionViews
- Takes a snapshot of your data before you make any changes
- When you then make new changes, it takes another snapshot and does all the diffable magic in the background and animation
- enums are hashable by default
- [Diffable Data Sources are a great new addition to UIKit](https://www.avanderlee.com/swift/diffable-data-sources-adoption/)
- [Diffable Data Source with two example apps](https://github.com/alexpaul/Diffable-Data-Source)
- [UICollectionView and SwiftUI?](https://stackoverflow.com/questions/56466306/uicollectionview-and-swiftui)
- [CollectionView in SwiftUI with LazyVGrid and LazyHGrid](https://sarunw.com/posts/swiftui-lazyvgrid-lazyhgrid/)
- [A SwiftUI implementation of UICollectionView & UITableView](https://github.com/apptekstudios/ASCollectionView)
### Automatic Reference Counting (ARC)
- Interview question: explain memory management in Swift (or something along these lines)
- ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated.
- [Allocates and Deallocates references from memory](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html)
- 'weak' will create a weak reference (instead of a [strong reference](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html#ID51) which may lead to a memory leak).
- A weak reference will cause that the reference count won't increase! [Ref](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html#ID52)
- Anytime we make something weak, it is going to be optional (can be nil)
- 'unowned' is like weak but instead force unwraps the optional
- [When to use weak self and why](https://www.donnywals.com/when-to-use-weak-self-and-why/)
### [AsyncImage](https://developer.apple.com/documentation/SwiftUI/AsyncImage)
- [AsyncImage. Loading images in SwiftUI](https://www.artemnovichkov.com/blog/async-image)
- AsyncImage uses URLCache underneath
- [Downloading and Caching images in SwiftUI](https://www.avanderlee.com/swiftui/downloading-caching-images/)
### GitHub
- [GitHub Flavoured Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/about-writing-and-formatting-on-github)
### Design
- [Modality](https://developer.apple.com/design/human-interface-guidelines/patterns/modality/)
### WebView (WebKit)
- There is still (in 2022) no native way in SwiftUI to show a WebView, so we have to build it ourselves with the help of UIKit:
- [SwiftUI: How to Display Web Page Using WKWebView](https://www.appcoda.com/swiftui-wkwebview/)
- [Building a WebView for iOS and macOS in SwiftUI](https://danielsaidi.com/blog/2022/04/24/building-a-webview-for-swiftui)
- [How To Present WebView In SwiftUI?](https://ishtiz.com/swiftui/how-to-present-webview-in-swiftui)
- [Create a web browser with WebKit and SwiftUI](https://benoitpasquier.com/create-webview-in-swiftui/)
- [How to monitor WKWebView page load progress](https://www.hackingwithswift.com/example-code/wkwebview/how-to-monitor-wkwebview-page-load-progress-using-key-value-observing))
### Design
- [Device Mockups for Sketch, Figma and XD](https://angle.sh/)
- [icons and illustrations](https://shape.so/)
### NetworkManager
- [A Swift Network Manager](https://paulpeelen.com/SwiftNetworkManager)
### SwiftUI vs UIKit
- [Thoughts on SwiftUI vs UIKit](https://swiftrocks.com/my-experience-with-swiftui)
### Localize your SwiftUI App
- Extract LocalizedStringKeys: is a special Swift type that will lookup localized Strings in your bundle. Use them in your custom SwiftUI view to make them ready for localization.
- Go to Project -> Build Settings -> and enable "Use Compiler to Extract Swift Strings" to extract localized String keys from code when exporting from Xcode.
- Internationalize your code with formatting
- Style your localized stings with Markdown
- Use Text() to add comments for translation context## Testing π§ͺ
### Unit-Tests
- [Unit testing: the pragmatic guide on where to start](https://hybridcattt.com/blog/start-testing-pragmatic-guide/)### UI-Tests
- User interface tests access your app using iOSβs accessibility system.
- UI-Tests are much more fragile than unit tests because small changes can cause tests to fail, but on the other hand do provide excellent proof that your app workflows function as intended.
- The accessibilityIdentifier(_ identifier:) is designed for internal use only, unlike the other two accessibility text fields (accessibilityValue and accessibilityLabel) that are read to the user when Voiceover is activated.
- [XCUITest Cheat Sheet](https://www.hackingwithswift.com/articles/148/xcode-ui-testing-cheat-sheet)
- [BDD for XCUITest](https://testautomationu.applitools.com/introduction-to-ios-test-automation-with-xcuitest/chapter4.html)
- [xcpretty: Flexible and fast xcodebuild formatter](https://github.com/xcpretty/xcpretty)
- [XCUITest on the CI](https://testautomationu.applitools.com/introduction-to-ios-test-automation-with-xcuitest/chapter8.html)
#### Screen Enum Pattern
- As I was refactoring the Screen (Page) Objects into Screen Enums, I discovered the Screen Enum Pattern!
- The Screen Enum pattern is a design pattern commonly used in test automation to represent the different screens or pages of an application as an enumerated type.
- This pattern involves creating an enum class that defines all the screens of the application as constant values. Each constant represents a screen or page of the application, and has a name and an associated locator that uniquely identifies the screen element on the page.
- Using the Screen Enum pattern can help make test code more maintainable and readable by providing a centralized location for all the screens in the application. It can also simplify test code by eliminating the need to hardcode locators for each screen or page.## GitHub API ππΈ
- [List followers of a user](https://docs.github.com/en/rest/users/followers#list-followers-of-a-user)## Worklog π
This worklog describes in chronological order, what I have been working on:
### Get things working
- Create screens and views
- Add the view model (MVVM)
- Validate username input by adding a regex
- Add the Model (MVVM)
- Setup the NetworkManager (Singleton Pattern)
- Implement the LazyVGrid
- Add AsyncImage for avatar loading (not sure what URLCache actually caches? The URL or the image itself?)
- Pagination in the viewModel and infinite Scrolling in the View
- Fix NavigationView Title with Search and username
- Attach the viewModel as @EnvironmentObject instead of injecting it (and then wrap it @ObservedObject)
- Empty State (when someone has no followers)
- Search Bar: make the FollowerView [searchable](https://medium.com/geekculture/swiftui-tutorial-searchable-d71b42ab0e2f)
- Favorites: create the favorites view
### Reflect, Rethink, Refactor
- [Fix bugs](https://github.com/simonberner/githubfollowme/issues?q=is%3Aissue+is%3Aclosed+label%3Abug)
- Add more tests while fixing a bug related to username input regex
- Change architecture from MVVM to MV State Pattern (which I already used right from the beginning)
- Documentation (README, code comments)## Improvements and Ideas π‘
For a list of all the features, improvements, fixes, enhancements I currently have in mind, have a look at the open [issues](https://github.com/simonberner/githubfollowme/issues).## Junior, Mid, Senior, Lead, Principal, Architect? π€
In our industry, we very often categorise/put ourself and others in experience levels. Sometimes this can be good as reference
for employment but it can also be misleading. Because there might be situations where you are e.g. Lead in one area and want to
move on into another area (same industry) where you haven't years of working experience - are you then a Junior all over again?
It's hard to answer this question straight away because it depends, right?
The post [Junior, Middle, Senior, Lead - what's the difference?](https://dataart.com.ar/news/junior-middle-senior-lead-what-s-the-difference/)
brings a little bit light into the above and reflects on the different experience levels.### Definitions
In general I like these descriptions of [programmers definitions](https://github.com/basecamp/handbook/blob/master/titles-for-programmers.md) from a company called [basecamp](https://basecamp.com/).## Blogs βπ½
During development of this App, I have found a handful of new blogs from people I didn't know before:
- [Benoit Pasquier](https://benoitpasquier.com/)
- [Donny Wals](https://www.donnywals.com/)
- [Matteo Manferdini](https://matteomanferdini.com/)
- [Azam Sharp](https://azamsharp.com/)## Credits ππ½
GitHubFollowMe is inspired by the course 'iOS Dev Job Interview Practice - Take Home Project' by [Sean Allen](https://twitter.com/seanallen_dev).
I ported the original UIKit implementation to SwiftUI.
Made with a π Simon Berner