• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 3/6/20

Bring it all together!

Log in or subscribe for free to enjoy all this course has to offer!

We are almost at the finish line with our current example. 🏃‍♀️ There are just a few more things to sort out, so let’s connect the remaining dots and perform some improvements!

Now is the time to reflect back on our intentions: writing quality code. Here we are going to review the SOLID principles and assess the quality of our code.

Let's go! 😁

SOLID. check

Single responsibility principle

Reminder: A code entity should have single responsibility.

Let's use our data model as an example. We could create a monster like this:

class MediaMonster {
var id: Int
var title: String
var artistName: String
var artworkUrl: String
var collection: String?
var sourceUrl: String
var artworkData: Data?
var swagId: Int
var swagTitle: String
var swagArtworkUrl: String
var swagSourceUrl: String
var swagArtworkData: Data?
init(/* all the necessary variations */) {
// ...
}
func loadMediaArtwork() {
// ...
}
func loadSwagArtwork() {
// ...
}
}

On top of that, we could use the prefix  media  for all the media-related properties. 😱

Does this look overwhelming?

Instead, we have three clean classes to hold data and let the service entity handle the image loading:

class MediaBrief {
var id: Int
var title: String
var artistName: String
var artworkUrl: String
var artworkData: Data?
init(...) {
// ...
}
}
class Media: MediaBrief {
var collection: String?
var sourceUrl: String
init(...) {
// ...
}
}
class Swag {
var id: Int
var title: String
var artworkUrl: String
var sourceUrl: String
var artworkData: Data?
init(...) {
// ...
}
}
class MediaService {
// ...
static func getImage(...) {
// ...
}
// ...
}

It's ok to create slightly imperfect entities. However, always make time for refactoring and aim for the best you can do at the time!

Open/closed principle

Reminder: Code entities should be open for extension and closed for modification.

Any violations of this kind in our code?

Ok, I'll give you a hint...

We are all good here!

Instead, go ahead and identify some good examples where this principle is being followed!

Your turn! This time you are on a hunt for goodies!

Any findings?!
What did you find?

Let me know what you found!

Extensions maybe?

Liskov substitution principle

Reminder: A subclass should be usable in the context of its superclass.

This one is interesting!

Try to identify the code in our project that violates this principle!

Found anything?!
Find anything?

OK...

Time to share your findings!

(I haven't found any!)

Interface segregation principle

Reminder: The interface should implement only necessary capabilities for the context.

Thankfully, overall we don't have such faults in our code. A monster example we've come up with in the beginning of this chapter could serve as a good example. We would be passing around the entire object with all of the properties that wouldn't be needed at times. We wouldn't need extra media data for the list view or any of the swag functionality at all!

Good thing we don't have that problem! 😁

Dependency inversion principle

Reminder: A code entity should depend on the least number of other entities.

A good example to analyze this principle is the MediaService class. Our small project is used as a model to explore essential networking capabilities. However, along the way we've built a number of traps for ourselves. The same class is responsible for:

  • Dealing with the particulars of media object

  • Performing networking

  • Parsing all the data

  • Fetching images

In larger projects, typical configuration would have separate classes that are responsible for:

  • Networking - only sending and receiving data.

  • Creating requests based on abstract parameters.

  • Object-specific communication (we've started here and incorporated the rest).

    • Fetching media and images, for example, would be at the same level - nothing as a subitem of another. 

  • Parsing data - object specific.

Think about how it can be improved - it's all in your capable hands! 😁

The coding attitude

Imagine your code will live forever, or at least a century from now. 😉 It’s not out of the question considering some code written in old programming languages is still functioning and even serves as a basis for new software. And, Swift is a very new language that quickly gained in popularity which is a good sign it’s not going anywhere in the near future. It’s also a sign that it will keep changing and evolving, which gives us a reason to write good code that will allow for quick adjustments and easy migrations to newer versions.

Aim to deliver the best you can for the moment! 💪

Let's recap!

  • [S] - Keep your code elements at minimal and straight-to-the-point functionality - ideally, single responsibility.

  • [O] - Keep parts of code entities closed for modification and open for extension.

  • [L] - Ensure subclasses keep the superclass functionality intact.

  • [I]  - Provide only useful interface in the context of a particular application.

  • [D]  - Make your code entities the least dependent possible on other entities.

  • Always perform the SOLID check!

Moving forward

Congratulations on fantastic progress! In this course, we’ve worked with new aspects of an application - learned to work with collection views and practiced networking! You also now know how to handle app requirements that may come in different forms and shapes. Those will definitely become valuable additions to your development equipment.

Knowing the basics is a necessary starting point to continue exploring those concepts and elements in depth, as well as expand your knowledge!

Keep learning! 🤩

Example of certificate of achievement
Example of certificate of achievement