Software development principles and practices for solid Software Engineers

Although today’s way of software development is rapidly changing, having a good understanding of these principles and good practices may only help you become better in software development.

Personally, I would recommend to every solid Software Engineer to get familiar with these practices if not already.

Coding practices

Photo by RDNE Stock project on Pexels.com

YAGNI

This principle came from Extreme Programming and states very simple things: Don’t overthink the problem solution in the execution stage.

Just write enough code to make things work!

DRY

This principle follows and states for: “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.”

Basically, don’t replicate functionality in the system, and make your code reusable.

SOLID

This principle has its own space in OOP. The SOLID mnemonic acronym represents these five design principles:

  1. Single-responsibility
    Design your classes in structural business entity/domain hierarchy, so that only one class encapsulates only logic related to it.
  2. Open-closed
    Entities should be open for extension but closed for modification.
    In the development world, any class/API with publicly exposed methods or properties should not be modified in their current state but extended by other features as needed.
  3. Liskov substitution
    This principle defines the way how to design classes when it comes to inheritance in OOP.
    The simplified base definition says that if class B is a subtype of class (super) A, then objects of A may be replaced with objects of type B without altering any of the desirable properties of the program.
    In other words, if you have a (super) class of type Vehicle and subclass of type Car, you should be able to replace any objects of Vehicle with the objects Car in your application, without breaking application behavior or its runtime.
  4. Interface segregation
    In OOP is recommended to use Interfaces as an abstracted segregation level between the producer/consumer modules. This creates an ideal barrier preventing coupling dependencies and exposing just enough functionality to the consumer as needed.
  5. Dependency inversion
    The principle describes a need for abstract layer incorporation between the modules from top to bottom hierarchy. In brief, a high module should depend on an abstract layer (interface), and a lower module with dependency on the abstract layer should inherit/implement it.

KISS

Acronym for Keep it simple, stupid – and my favorite over the last years!

The principle has a very long history but has been forgotten by many Devs many times from my professional experience.

Avoiding unnecessary complexity should be in every solid Software Engineer’s DNA.

This keeps the additional development cost down for further software maintenance, new human resources onboarding, and the application/system’s additional organic growth.

BDD

Behavior-driven development is becoming a more and more desirable practice to follow in Agile-oriented business environments.

The core of these principles is coming from FDD. The BDD applies a similar process at the level of features (usually a set of features). One’s tests build the application/system is getting a return on investment in the form of automated QA testing for its lifetime. And therefore this way of working is very economically efficient in my opinion.

The fundamental idea of this is to engage QAs (BAs) in the development process right from the beginning.

This is a great presentation of the principle from the beginning to the end of the release lifecycle: Youtube

TDD

The software development process gained its popularity over time in test automatization. Basics come from the concept of starting the test first and following with the code until the test runs successfully.

Leveraging Unit test frameworks for this such as xUnit, NUnit (or similar), if you are a .NET developer, helps to build a code coverage report very easily in MS Visual Studio (Enterprise edition) for example, which helps to build QA confidence over the code which last long time over the code releases.

FDD

Well, know approach how to deliver the small blocks (features) in an Agile running environment.

In other words, if you have a load of work to deliver is better to slice it down to individual blocks (features) that can be developed, tested, and delivered independently.

The whole FDD methodology has 5 stages:

  1. Develop a model of what is needed to build
  2. Slice this model into small, testable blocks (features)
  3. Plan by feature (development plan – who is going to take that ownership)
  4. Design by feature (selects the set of features the team can deliver within the given time frame)
  5. Build by feature (build, test, commit to the main branch, deploy)

The beauty of this development methodology approach is that deployment features such as Feature toggling can be integrated with relatively minimal complexity overhead. With this integration in place, the production team can move forward only on one main branch, an unfinished feature development state regardless. An enterprise-level production team will appreciate this advantage, no doubt about it.

Summary

By following these principles and practices production team will produce maintainable code, with high test coverage and human resources high utilization over the SDLC (ROI).

Thanks for staying, subscribe to my blog and leave me a comment below.

cheers\

TLS handshake between Client and Server explained

Not every developer these days has a clear picture of how the Client/Server HTTPS/TSL encryption works. To be fair I have to sometimes look at my notes to recall this process as it’s confusing and easy to forget.

Especially for these Devs working on the front end and using publicly available 3rd parties middleware, ready to be used for your solution – so, why bother?

But anyway … this is a good piece of information to keep in the mind and if you forget, this handy post can remind you how the entire process workflow works again.

TLS handshake (negotiation) process flow

Example algorithm used now on: ECDH/RSA

  1. Client – [Sends](Hello: These are my supported cipher suites) -> Server
  2. [Server chooses the cipher from the supplied cipher suites]
  3. Server – [Sends](Hello: This is my certificate with Public key) -> Client
  4. [Client validates the Certificate]
  5. Server – [Sends](Hello done) -> Client
  6. [Client generates Pre-Master secret and encrypts it by Server Public key]
  7. [Client generates (calculate) Symmetric key (Master secret) based on Pre-Master secret and random numbers
  8. Client – [Sends: Pre-Master Secret exchange](Change Cipher: Pre-Master secret) -> Server
  9. [Server receives and decrypts Pre-Master secret]
  10. [Server generates (calculate) Symmetric key (Master secret) based on received Pre-Master secret and random numbers]
  11. Client – [Sends](Change Cipher Spec) -> Server, which means that from now on, any other message from the Client will be encrypted by the Master secret
  12. Client – [Sends: Encrypted] -> Server and the Server tries to decrypt the finished message
  13. Server – [Sends](Change Cipher Spec) -> Client, which means that from now on, any other message from the server will be encrypted by the Master secret
  14. Server – [Sends: Encrypted] -> Client, Client tries to decrypt the message

-- handshake is completed --
— the communication encryption is changing from asymmetric to symmetric —

Example algorithm used now on: AES

15. Symmetric bulk encryption switched, Client and Server established TLS communication

// Agenda

   [] -> action
   () -> message

Some other facts to be aware of

  • Anything encrypted by the public key can be decrypted by the private key only
  • More details about TSL
  • What are ECDH, RSA, and AES
  • What are asymmetric and symmetric cryptography

Thanks for staying, subscribe to my blog, and leave me a comment below.

cheers\