Skip to content

simonberner/githubfollowme

Repository files navigation

GitHub Follow Me

Twitter: @simonbernerdev Gitmoji

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 makes you an ace. 😁


Contents


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

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 of a candidate, the scope can be cut down or enlarged accordingly.

Tech Stack πŸ“‘

Architecture πŸ›

This App is build with the MV State Pattern (State Pattern/Model View pattern) 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.\

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!
  • 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 πŸ“š

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

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)
  • 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 taken into account for instances of classes? (Structs an enums are value types!)
  • Is premature optimization 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
  • 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 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

Swift

SwiftUI

Regular Expressions

NSPredicate

SwiftLint

Architecture

What?

Patterns

MVVM architecture

UIKit vs SwiftUI

  • What is called view in SwiftUI, are called ViewControllers in UIKit

Codable

Guard

Commenting code

Concurrency

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
  • 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

@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
  • Before Async await: @escaping closures outlive the life of a func (because they have to wait for certain async code)

UIKit - UICollectionViewDiffableDataSource (iOS13+)

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
  • 'weak' will create a weak reference (instead of a strong reference which may lead to a memory leak).
  • A weak reference will cause that the reference count won't increase! Ref
  • 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

GitHub

Design

WebView (WebKit)

Design

NetworkManager

SwiftUI vs UIKit

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

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
  • BDD for XCUITest
  • xcpretty: Flexible and fast xcodebuild formatter
  • XCUITest on the CI

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 πŸ™πŸ˜Έ

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
  • Favorites: create the favorites view

Reflect, Rethink, Refactor

  • Fix bugs
  • 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.

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? 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 from a company called basecamp.

Blogs ✍🏽

During development of this App, I have found a handful of new blogs from people I didn't know before:

Credits πŸ™πŸ½

GitHubFollowMe is inspired by the course 'iOS Dev Job Interview Practice - Take Home Project' by Sean Allen. I ported the original UIKit implementation to SwiftUI.


Made with a πŸ™‚ Simon Berner

Buy Me A Coffee