DEV Community

Discussion on: Please explain why I need software architecture

Collapse
 
slavius profile image
Slavius • Edited

MVC, MVVM, MVP are just a very small part of software architecture that applies to web applications with integrated backend/frontend, where Controller is the isolated backend task (like GetAllCustomers), Model is representation of data (coming probably from some sort of database) and View is the presentation layer.

In general software architecture is trying to make the code logically structured, isolated, easy to extend and maintain.
This results in code that does not repeat (you don't have to write and maintain the same logic in multiple places, where forgetting to update function that does something important in all places all over the project results in inconsistent or erratic behavior of the application).
It also tries to isolate and structure your code into domains where e.g. class CustomerRepository in a file CustomerRepository.java does only Customer related tasks so it is easy to identify within your project what goes where and where to search for it. This becomes more important once you start using Inversion of Control of some sort, like Dependency Injection where the dependencies are loose (they might be figured out at runtime not at compile time).
It also tries to form some sort of abstractions (for the same reasons mentioned above, where your isolated domain responsible pieces of code does not need to hardly depend on specific implementations). This becomes very useful during testing or running different environments (test, staging, production). You probably don't want your developers to upload files to your production storage from their development machines every time they run the code the same way you don't want to test some features together, like calling an API that deletes data from the database. For this reasons you'll impement Interfaces that just define how your object should look like and behave but you develop multiple implementations - one for production that does what it should in production, one for unit tests that deletes data from local SQLite database and returns the success result or just mock/fake that just returns true because your test is focused on running the API call, validate credentials, authorization, input parameters and produce valid response, but not focused on whether you can delete data from a database which you'd need to prepopulate before each test as response from the database trying to delete data from empty table would mess your test results.
Another goal is to make code extensible. Here again Interfaces really help as you can define an interface called IVehicle that implements typical vehicle features (length, weight, person capacity, etc.) and has typical properties. This can be used in places where you don't care what vehicle it is, like implementing a Highway class where any vehicle can ride on it. Then you can extend the IVehicle with IPersonalVehicle, IBus, ILorry which are based on IVehicle but extend it with different properties and functions (e.g. bool isLongVehicle, uint TrailerCount etc.) which you can use while implementing e.g. a highway toll gate where you have specific gates for specific vehicles and you cannot pass ILorry object type into PersonalVehicleTollGate() function because the parameter type does not match but still you did not have to implement basic functions of the ILorry object implementation over again because they are inherited from generic IVehicle interface. As you now have an PersonalVehicleTollGate() function and LorryTollGate() you don't have to write a big switch case or if (vehicle.type == Lorry) within your function. It also helps your unit tests to not depend on specific implementations but rather generic ones or to provide fakes/mocks as mentioned before.
Interfaces also allow you to swap implementations, e.g. you develop an app that stores files in Google Drive by implementing Google's REST API calls in appropriate places in your application. However you soon realize that there is a limitation of some sort and you need to swap for S3 storage. Ideally you'd implement an IRemoteStorage interface at the beginning with methods like Save(), Read(), Delete(), Search() etc. and implement class GoogleDriveStorage extends IRemoteStorage that abstracts the implementation. Then when you need to change from Google to S3 provider you need to develop another implementation based on the interface and just swap them in the application initialization where you register your new AmazonS3Storage as an implementation of IRemoteStorage interface in Dependency Injection container instead of GoogleDriveStorage.
The rest makes sure the application can be easily developed and maintained by multiple people at the same time.