Splitting up Swift types.

Tram Ho

  • A different application with different features and systems should be clearly separated in terms of their function and scope of influence, which is of great interest in software development. So there are many structures and techniques + principles that have been introduced over the years that make it easier to code in Swift and many other languages.
  • For whatever type of structure we choose to apply in a specific project, we need to ensure that each type has a clear and unique set of responsibilities. This becomes especially difficult as the project continues to be developed and adds many new features.
  • Let’s take a look at a few techniques that can help us do that by separating types once their responsibilities are beyond the allowed limits.

1 / States and scopes:

  • A source code becomes complex when a single type to handle has multiple scope effects as well as various state state . For example, we work on the networking layer of the application and we have implemented the entire class in a single class called NetworkController :

  • Although implementing an entire feature or system in a class is not a bad thing, in this case we have a confusing source code . Because we use the same API to request both a public endpoint and an endpoint , as well as when authentication is required.
  • It would be easier if we could use the Swift type system to prevent all endpoint requiring authentication to be called without a valid access token. That way, we will be able to validate our network code much more closely into complie time .
  • To do that, move all the authentication related codes and access tokens from NetworkContoder and into a new instance of that class , we named AuthenticatedNetworkContoder . The controller allows us to make network call based on endpoint :

  • We also provide network controller type of end point dedicated its own AuthenticatedEndpoint . That also clearly identifies our endpoint definitions, so an authentication request endpoint was accidentally passed to our previous NetworkContoder .
  • Because that type no longer has to handle any authentication requests, we can greatly simplify and rename it (and its end point type) better describe its new role in the network layer of we :

  • We can begin to transfer the deployed network base off the controller and into the type smaller, more specialized. For example, we can create a separate NetworkRequestPerformer that both of our controller can use to execute controller requests while keeping the top-level API completely separate and type safe:

-Now we can allow both of our network controller to focus solely on providing type-safe API to fulfill requests while their basic implementations are being kept in sync through the utility type:

2 / Loading versus managing objects:

  • Next, consider another type of situation that can make certain parts of the source code more complex than necessary, when the same type is responsible for both loading and managing a certain object . A very common example is when everything related to a user’s session has been implemented in a single type – such as UserManager .
  • For example, here such a type is responsible for both the user logging into and exiting the application, keeping the currently logged-in User in sync with our server:

  • The first thing we will do is extract all the code associated with downloading the USer versions from UserManager and into a separate new type . We will call it UserLoader and use our AuthenticatedNetworkControll beforehand to request the user ‘s endpoint :

  • By splitting our UserManager into smaller blocks we can allow many of our functions to be implemented as non- state structures because those type will simply perform tasks instead of arguments. another object (like our previous NetworkRequestPerformer ).

  • The advantage of the above code is that we can now use one of our two new type whenever we need to perform specific tasks of that type instead of always having to use the same UserManager regardless We log in, log out or simply update the current User .

  • The refactoring tool above not only allows us to remove an unnecessary option, but also allows us to remove a lot of ambiguous statements if and protects from any code that depends on the User Logging provides us with a greater degree of flexibility because we can now choose the level of abstraction related to the User we want to work with in each new feature we will build.
Share the news now

Source : Viblo