# Software Production

Software Engineering is an overlap of computer science, management science, and engineering principles for the development of software applications systematically. Software Engineering can also be considered as a branch of Systems Engineering. The earliest origin of the term “software engineering” was by Margaret Hamilton in the early 1960s while she was working on Apollo space mission. The official reference of the word was in a [Software Engineering Conference](http://homepages.cs.ncl.ac.uk/brian.randell/NATO/index.html) hosted by the NATO science community held at Garmish, Germany in 1968 by Anthony Oettinger and, Brian Randell and Peter Naur point out in their introduction proceedings. The need for software engineering has come due to the increasing complexity of programs, many people being involved in the development of applications, changing technology landscape, pressure on cost and quality management, and increased applicability across industries.

### Software Development Life Cycle (SDLC) <a href="#software-development-life-cycle-sdlc" id="software-development-life-cycle-sdlc"></a>

SDLC stands for Software Development Life Cycle. It is a workflow process that defines the core stages and activities of development cycles or A framework that describes the operations performed at each phase of a software development project. Some of the life cycle models are -

* **Waterfall Model** - It follows a sequential step-by-step process from requirements analysis to maintenance and it is one of the oldest models. Systems that have well-defined and understood requirements are a good fit for the Waterfall Model.
* **Iterative Model** - The Iterative SDLC model does not need the full list of requirements before the project starts. The development process may start with the requirements of the functional part, which can be expanded later. The process is repetitive, allowing us to make new versions of the product for every cycle. Every iteration (which lasts from two to six weeks) includes the development of a separate component of the system, and after that, this component is added to the functional developed earlier. Speaking with math terminology, the iterative model is a realization of the sequential approximation method; that means a gradual closeness to the planned final product shape.
* **Spiral Model** - It combines architecture and prototyping by stages. It is a combination of the Iterative and Waterfall SDLC models with a significant accent on the risk analysis. The main issue of the spiral model is defining the right moment to take a step into the next stage. The preliminary set time frames are recommended as the solution to this issue. The shift to the next stage is done according to the plan, even if the work on the previous stage isn’t done yet. The plan is introduced basing on the statistical data, received during the previous projects even from the personal developer’s experience.
* **V-shaped SDLC model** - It is an expansion of classic waterfall model and it’s based on associated test stage for every development stage. This is a very strict model and the next stage is started only after the previous phase. This is also called the *“Validation and verification”* model. Every stage has the current process control, to make sure that the conversion to the next stage is possible.
* **Agile Model** - In the agile methodology after every development iteration, the customer is able to see the result and understand if he is satisfied with it or he is not. This is one of the advantages of the agile software development life cycle model. One of its disadvantages is that with the absence of defined requirements it is difficult to estimate the resources and development cost. Extreme programming is one of the practical uses of the agile model. The basis of such a model consists of short weekly meetings.

### Software Architecture <a href="#software-architecture" id="software-architecture"></a>

Software Architectural pattern is a general, reusable solution to a commonly occurring problem in software architecture within a given context. Architectural patterns are like software design patterns but have a broader scope. Some of them are as follows

* **Layered Pattern** - This pattern can be used to structure programs that can be decomposed into groups of sub-tasks, each of which is at a particular level of abstraction. Each layer provides services to the next higher layer. Usage includes General desktop applications and E-commerce web applications. The most commonly found 4 layers of a general information system are as follows-
  * *Presentation layer (also known as UI layer)*
  * *Application layer (also known as service layer)*
  * *Business logic layer (also known as domain layer)*
  * *Data access layer (also known as persistence layer)*
* **Client-Server Pattern** - This pattern consists of two parties; a server and multiple clients. The server component will provide services to multiple client components. Clients request services from the server and the server provides relevant services to those clients. Furthermore, the server continues to listen to client requests. Usage includes online applications such as email, document sharing, and banking.
* **MVC Pattern** - This pattern, also known as MVC pattern, divides an interactive application into 3 parts as follows -
  * **model** — contains the core functionality and data
  * **view** — displays the information to the user (more than one view may be defined)
  * **controller** — handles the input from the user
* This is done to separate internal representations of information from the way information is presented to, and accepted from, the user. It decouples components and allows efficient code reuse. Usage includes an architecture for World Wide Web applications in major programming languages. Also used in Django, Flask, Rails.
* **Master-slave pattern** - This pattern consists of two parties; master and slaves. The master component distributes the work among identical slave components and computes a final result from the results which the slaves return. Usage includes database replication, the master database is regarded as the authoritative source, and the slave databases are synchronized to it.
* **Pipe-filter pattern** - This pattern can be used to structure systems that produce and process a stream of data. Each processing step is enclosed within a filter component. Data to be processed is passed through pipes. These pipes can be used for buffering or for synchronization purposes. Usage includes Compilers. The consecutive filters perform lexical analysis, parsing, semantic analysis, and code generation.
* **Peer-to-peer pattern** - In this pattern, individual components are known as peers. Peers may function both as a client, requesting services from other peers, and as a server, providing services to other peers. A peer may act as a client or as a server or as both, and it can change its role dynamically with time. Usage includes file-sharing networks.
* **Broker pattern** - This pattern is used to structure distributed systems with decoupled components. These components can interact with each other by remote service invocations. A broker component is responsible for the coordination of communication among components. Servers publish their capabilities (services and characteristics) to a broker. Clients request a service from the broker, and the broker then redirects the client to a suitable service from its registry. Usage includes message broker software such as Apache ActiveMQ, Apache Kafka, RabbitMQ.
* **Event-bus pattern** - This pattern primarily deals with events and has 4 major components; event source, event listener, channel, and event bus. Sources publish messages to particular channels on an event bus. Listeners subscribe to particular channels. Listeners are notified of messages that are published to a channel to which they have subscribed before. usage includes notification services.

### Software Testing <a href="#software-testing" id="software-testing"></a>

Testing is an important part of software development, security, and scalability. Some of them are given below:

* **Unit testing** - Fast, low-level tests with small footprint written by developers to test the stability of isolated units of code. For example, given an argument function should return the expected result. The goal is to test a unit of code (component, module, function) in isolation and in a meaningful way.
* **Integration testing** - Verifying if and how two or more components or modules integrate (talk to each other). Usually, this kind of testing can be done by QA tester if it’s a black box testing or a developer if it involves more complex and technical integration like a database.
* **System testing (or end-to-end testing)** - Is a complete system testing. When unit tests and integration tests are testing parts of the system, this one is targeting the system as a whole. This testing is performed by QA testers. For example, testing an entire application from login to checkout and making sure emails are delivered. This is done from the user perspective, and shouldn’t be automated with data mocks or fake requests. This type of testing is the most involved and time-consuming. If a bug was discovered during E2E testing, that means something was missing in the unit or integration testing.
* **Acceptance Testing** - It is a level of software testing where a system is tested for acceptability. The purpose of this test is to evaluate the system’s compliance with the business requirements and assess whether it is acceptable for delivery.
* **Functional testing** is using software to check if its behavior matches the expectations. Expectations should be documented in the form of a technical spec that can be written in the form of documentation or a user story. Functional testing applies to all levels of tests from unit to end-to-end. If it answers the “what” question, it checks if a function returned the expected value.
* **Non-functional testing** focuses on usability, reliability, maintainability, and other attributes. It answers the “how” question, for example, function’s performance when it returns a specific value.
* **Performance testing** is self-explanatory. It checks how fast the application loads, how responsive it is, and its reliability under high load. This kind of test is necessary to make sure the system can scale under high traffic. Stress testing and spike testing are different types of performance testing to check if the system can withstand higher than the expected load.
* **Security testing** should be done by security specialists. It can also be performed as an audit. It’s highly likely for e-commerce websites to undergo security testing on a regular basis and have random audits. Usually, security testing is focused on data integrity, confidentiality, and availability. E-commerce companies can also be checked for PCI compliance.
* **Regression testing** checks if new changes to the system have not broken existing functionality or caused old bugs to reappear. It’s done by re-running all tests on the system.
* **Smoke testing** focuses only on the most important functions of work. This testing is performed to make sure the system is stable enough for users to do basic actions (like the search for hotels or log in with email/password). It’s usually done right after production deploy to check if the server is running and everything looks okay. Smoke testing can be part of a continuous deploy cycle.
* **Static analysis** is a type of testing where code is analyzed for any errors without running or executing the code. The most common form of static analysis are linters.

### Version Control <a href="#version-control" id="version-control"></a>

Version control systems are a category of software tools that help a software team manage changes to source code over time. Version control software keeps track of every modification to the code in a special kind of database. If a mistake is made, developers can turn back the clock and compare earlier versions of the code to help fix the mistake while minimizing disruption to all team members. Developing software without using version control is risky, like not having backups. Version control can also enable developers to move faster and it allows software teams to preserve efficiency and agility as the team scales to include more developers. While it is possible to develop software without using any version control, doing so subjects the project to a huge risk that no professional team would be advised to accept. So the question is not whether to use version control but which version control system to use.

**Git** - Git is a mature, actively maintained open source project originally developed in 2005 by Linus Torvalds, the famous creator of the Linux operating system kernel. A staggering number of software projects rely on Git for version control, including commercial projects as well as open source. Developers who have worked with Git are well represented in the pool of available software development talent and it works well on a wide range of operating systems. Installation Instructions for Git can be found [here](https://www.atlassian.com/git/tutorials/install-git).

### Programming Paradigm <a href="#programming-paradigm" id="programming-paradigm"></a>

A programming paradigm is a style or a way of programming. Paradigms are not meant to be mutually exclusive; a single program can feature multiple paradigms. Very few languages implement a paradigm of 100%. When they do, they are pure. It is incredibly rated to have a *pure OOP language* or a *pure functional* language. A lot of languages have a few escapes.

A lot of languages will facilitate programming in one or more paradigms. In Scala, you can do imperative, object-oriented, and functional programming quite easily. If a language is purposely designed to allow programming in many paradigms is called a multi-paradigm language. If a language only accidentally supports multiple paradigms, we don’t have a special word for that. Below are a few common programming paradigms practiced by software developers while developing software systems using a variety of programming languages.

* **Imperative**: Programming with an explicit sequence of commands that update state. Fortran and Algol are few examples.
* **Declarative**: Programming by specifying the result you want, not how to get it. HTML, XML, CSS, SQL, Prolog, Haskell, F# hold these properties.
* **Structured**: Programming with clean, goto-free, nested control structures. C, Perl, ALGOL are few examples.
* **Procedural**: Imperative programming with procedure calls. BASIC, C, FORTRAN, Java, and Pascal holds these properties.
* **Functional (Applicative)**: Programming with function calls that avoid any global state.
* **Function-Level (Combinator)**: Programming with no variables at all.
* **Object-Oriented**: Programming by defining objects that send messages to each other. Python, Ruby, Scala, Smalltalk are few of them. Objects have their own internal (encapsulated) state and public interfaces. Object orientation can be:
  * **Class-based:** Objects get state and behavior based on membership in a class.
  * **Prototype-based:** Objects get behavior from a prototype object.
* **Event-Driven**: Programming with emitters and listeners of asynchronous actions. Visual Basic, Visual C++, and Java are some of the languages which can be implemented as event-driven.
* **Flow-Driven**: Programming processes communicating with each other over predefined channels.
* **Logic (Rule-based)**: Programming by specifying a set of facts and rules. An engine infers the answers to questions. Prolog is a good example of logic based languages.
* **Aspect-Oriented**: Programming cross-cutting concerns applied transparently.

### Software Licensing <a href="#software-licensing" id="software-licensing"></a>

A software license is an agreement between you and the owner of a software program that allows you to do certain things that would otherwise be an infringement of copyright law. The software license usually answers questions such as :

* Where and how and how often can you install the program?
* Can you copy, modify, or redistribute it?
* Can you look at the underlying source code?

The price of the software and the licensing fees, if any, are sometimes discussed in the license agreement, but usually, it's described elsewhere. There are around five types of common software license models. They are

* **Public domain** - This is the most permissive type of software license. It means that anyone can modify and use the software without any restrictions. But you should always make sure it’s secure before adding it to your own codebase. Note that code that doesn’t have a license is NOT automatically in the public domain.
* **Permissive** - Permissive licenses are also known as “Apache-style” or “BSD style.” They contain minimal requirements about how the software can be modified or redistributed. This type of software license is perhaps the most common and popular with free and open source software. Aside from Apache and BSD, another common variant is the MIT License.
* **LGPL** - The GNU Lesser General Public License allows you to link to open source libraries in your software. If you simply compile or link an LGPL-licensed library with your own code, you can release your application under any license you want, even a proprietary license. But if you modify the library or copy parts of it into your code, you’ll have to release your application under similar terms as the LGPL.
* **Copyleft** - Copyleft licenses are also known as reciprocal licenses or restrictive licenses. These licenses allow you to modify the licensed code and distribute new works based on it, as long as you distribute any new works or adaptations under the same software license. For example, a component’s license might say the work is free to use and distribute for personal use only. Any derivative you create would also be limited to personal use only. “*Derivatives*” includes any new software you develop that contains the component. The catch here is that any end user of your software also has the right to modify the code. Therefore, you must make your own source code available. Exposing your source code may not be in your best interests. The most common example of a copyleft or reciprocal license is the GPL.
* **Proprietary** - Of all types of software licenses, this is the most restrictive. The idea behind it is that all rights are reserved. It’s generally used for proprietary software where the work may not be modified or redistributed.

### Software Offering <a href="#software-offering" id="software-offering"></a>

The manufactured software is widely offered in the below formats:

* **SaaS defined (Software as Service)**: a solution hosted and maintained by a third-party.
* **On-Premise defined:** a solution hosted in-house and usually supported by a third-party.
* **Off-Premise defined:** a solution hosted by a third-party and usually supported by a different third-party.

For a small business with minimal existing infrastructure and if we want something immediate and agile, hosted / SAAS solutions are the best option for software deployment. For a medium sized business with an existing investment in IT Infrastructure and systems then we can probably take a more measured approach and choose either hosted or on-premise solutions depending on what suits your scenario best.

In the case of large corporate, chances are there are many factors involved in the decision-making process of any solution. The likelihood is that every option will go through rigorous scrutiny before being deployed so in this environment no offering will be quick and immediate. Historically in this space, systems have tended to be on-premise but some software can only be offered as hosted solutions which eventually become more mature.
