Security management

În lumea de azi cînd toate sunt conectate cu toate, Security trebuie să fie un rol important. De la autentificare și autorizare, pînă la asigurarea integrității datelor (a se citi coruperea intenționată a datelor) și accesibilitate. Dacă AAA (autentificare, autorizare, audit) sunt imediat recognoscibile ca Security Management, integritatea datelor nu este de obicei luată în calcul (decît pe sisteme dedicate). De obicei un sistem se asigură că datele nu sunt corupte fizic pe suportul de stocare, în timpul scrierii sau citirii, cît și de-a lungul existenței lor pe storage (eg. la un reboot forțat). În context de securitate, Integritatea Datelor identifică autorul datelor și pe cel ce le modifică. Mai mult, ne asigură că datele nu au fost modificate cu rea intenție.

O altă componentă importantă a Security este Accesibilitatea Datelor. Dacă datele sunt greu accesibile atunci ele nu vor fi folosite și business-ul își pierde interesul pentru sistem (business-ul sunt cei care plătesc și care hotărăsc folosirea unui sistem sau altul). Da, anumite date au statut special și ele vor fi accesibile conform unui sistem de securiate strict, dar de aici pînă a încurca userul în day-to-day activity pentru că esti paranoic nu e un sistem bun. Un sistem flexibil, dar fără compromisuri, este marea încercare a unui OS modern.

Audit

Auditul activității în sistem este un rol necesar pentru a determina și preveni activități nedorite în sistem. Userii normali ai unui sistem vor parcurge pașii de acțiune în ordinea lor firească, dar un răuvoitor va încerca diferite scheme de ocolire a procedurii de securitate și numai prin auditul activităților din sistem (reușite și nereușite) se va putea determina o alarmă de securiate. Aici iar dăm în capcana accesibilitații – dacă sistemul va produce o tonă de evenimente și se va isteriza pentru orice bîzîit el va fi neutilizabil și va fi folosibil doar pentru a reconstitui niște pași pe baza unor log-uri (proces necesar în cazul unor evenimente nedorite deja întîmplate, dar cum prevenția costă de zece ori mai puțin decît corecția atunci ne vom concentra mai ales pe rolul de prevenție).

Sistemul va pune la dispoziția dezvoltatorilor servicii de log și audit pentru înregistrarea evenimentelor în sistem un model unitar care să poată fi interpretat ușor. Ba mai mult, se va căuta un model integrat (sau integrabil) cu alte sisteme eterogene pentru a putea fi interpretate la nivel enterprise.

În zilele noastre cînd serviciile în cloud au luat locul aplicațiilor locale, anumiți operatori vor cere și servicii de Accounting în cadrul rolul de Audit (eg. cît timp s-a folosit un anumit serviciu, ce resurse a folosit etc.). Deși la prima vedere pare că este o parte a rolul de Audit, acesta trebuie gîndit ca un rol separat și trebuie consumat direct de aplicații și servicii. Asta pentru că exstă foarte multe scenarii pentru a gîndi servicii, de le combina resurse în pachete și de a le factura (eg. lunar la pachet sau per GB folosit sau per acces-numărdevizite etc) care depășesc definiția de Master Copntroller a unui OS.

User Interaction management

Acest rol este vital pentru dezvoltarea și longevitatea unui OS. Dacă utilizatorii nu pot intracționa eficient cu sistemul atunci ei nu vor mai intracționa deloc. Gadget-urile smart și-au luat avînt DOAR DUPĂ ce a apărut o interfață prietenoasă. Unii afirmă că acel scroll gesture a simplificat suficient lucrurile pentru user. Nu e adevărat, dar gestures au o greutate mare în adoptarea smart-X-urilor.

Deși toată lumea a fost de acord, încă de la inventarea fotografiei, că o imagine face cît o mie de cuvinte, interfața grafică de interacțiune cu un computer s-a născut destul de greu. Chiar dacă hardware-ul a permis-o relativ repede (de la începutul anilor 1970), doar pe la jumătatea deceniului opt (după lupte seculare în ani-tehnologici) interfața grafică a devenit suportată pe sisteme. Motivul invocat va fi fost costul, dar eu cred că e ceva mai adînc, psihanalizabil, legat de castă – it-iștii cu hieroglifele lor urmau avocații cu avocățeasca lor sau contabilii cu contabiliceasca lor. Greșeală fatală, azi miliardele se fac din accesibilitatea publicului larg la tehnologie.

Cerințele moderne ale UI sunt legate de user experience, multi user și remote acces. Remote acces este mai mult legată de Communication Management, dar atîrnă greu în balanță modul cum interacționezi remote cu un sistem.

Communication management

La începuturile erei noastre computerul era suficient sie însuși. Dacă mai avea și o imprimantă legată la un port intern era o unealtă și mai folositoare. Odată cu creșterea cantității de date (în lume datele se dubleză la fiecare doi ani) a existat nevoia comunicării între computere. Bumul tehnologic de astăzi se datorează proiectării inițiale corecte a acestui rol. Au creat protocoale de comunicație atît de bune încît tehnologii care nu existau în momentul proiectării au fost integrate foarte ușor, natural, în sistem. Cel mai bun exemplu sunt tehnologiile wireless care nu existau în anii 1970 cind au creat protocolul TCP/IP și care apoi au folosite împreună natural, fără eforturi de integrare.

Succesul acestui model s-a bazat pe abstractizarea diferitelor funcții necesare într-o comunicare, de la transport – mediu de comunicare, protocol, pînă la limbaj și application specific. Modelul teoretic (diferit de practica curentă) este numit Open Systems Interconection (aka OSI model). El identifică șapte nivele/layere: physical, data link, network, transport, session, presentation și application. În practică au mai apărut diverse nevoi pe care modelul standard nu le-a prevăzut, ca VLANuri, VPNuri sau transport criptat (altceva decît datele criptate), dar cum în IT practica primează acestea au fost înghesuite în OSI (cu bătăi de cap doar pentru teoreticieni).

Comunicarea între sisteme diferă esențial de comunicarea între obiecte descrisă în capitolul Object Management prin natura tipului de comunicare. În primul caz sistemele sunt procupate de legătură și transport, pentru ele datele transportate fiind necunoscute, iar în al doilea tip de interacțiune – aplicațiile cunosc serviciile pe care le consumă, dar nu le pasă cum ajung la ele. În mod ideal cele două nu se intersectează, dar în practică acestea se suprapun în nenumărarte sisteme. Cel mai bun exempl este storage-ul. Inițial, era treaba unei aplicații (de tip serviciu, dar de nivel superior) să dea acces la storage (printr-un protocol special de acces, SMB, NFS, FTP) unui sistem remote, azi storage-ul poate fi virtualizat printr-un seviciu de nivel inferior al sistemului, așa încît datele să stea în toată lumea și aplicațiile care-l folosesc să naibă habar pe unde sunt dale lor

Definiție: Sistemul de operare este o aplicație software care joacă rolul de “Master Control Program” și care face legătura între hardware și celelalte aplicații software.

Principalele atribuțiuni ale unui OS sunt:

  • hardware management – gestionarea diferitelor device-uri hardware;
  • process management – executarea diferitelor aplicații software;
  • object management – gestionarea diferitelor obiecte software (fișiere, aplicații, mașini virtuale, hardware virtualizat etc);
  • user interaction management;
  • security management;
  • communication  management;
  • instrumentation and orchestration;
  • application development;
  • audit.

Hardware management

Acesta este rolul primordial al unui OS. Chiar prin definiție rolul său este să facă legătura între hardware și celelalte aplicații software.

Deși putem imagina multe device-uri hardware pe care ar trebui să le cunoască un OS, în fapt, de-a lungul timpului obiectele hardware s-au separat în cîteva categorii bine definite, 10-12 toate. Vom găsi, în ordinea importanței hardware: procesoare, motherboards, RAMi, video, storage, networking, HIDs (human interface devices), audio. Celelalte cad în categorii foarte specializate, rămînînd pentru OS doar sarcina găsirii unor mijloace (aka porturi) de conectare la aplicații. Și porturile hardware au avut aceași evoluție și s-au standardizat, cele mai folosite azi sunt porturile seriale și porturile USB (deși USB este un port hardware și are caracter serial, nu este un port serial, fiind folosit doar pentru transport).

Cel mai mare succes în managementul hardware-ului l-a avut Windows-ul pentru că a introdus un layer de abstractizare (HAL), ceea ce a permis dezvoltarea unitară a drivere-lor hardware. (definiție: driver-ul este o aplicație software specifică unui hardware ce permite sistemului de operare accesul la funcțiile device-ului.) Astfel, aplicațiile au avut o interfață unitară pentru accesul la o întreagă clasă de device-uri fără a-i păsa ce producător a construit-o. Și invers, producătorii de hardware au avut un framework unitar pentru a-și dezvolta driverele, fapt ce i-a ajutat să creeze niște aplicații robuste (fără bug-uri).

Process management

Tot definiția ne îndrumă cătrea al doilea mare rol al unui OS. În process management sistemul încarcă în memorie o aplicație software și execută instrucțiunile sale în limbaj mașină (aka cod mașină). Procesele trebuie să fie izolate, cu acces direct doar la spațiul de memorie alocat. Accesul la resurse nu se face direct, ci prin intermediul serviciilor de sistem (sau funcțiilor de sistem, dar un serviciu, spre deosebire de o funcție, are posibilități de autentificare, de prioritizare și alte atribute moderne). Cea mai mare provocare a acestui proces este de a pune la dispoziția aplicațiilor mecanisme să-și păstreze ACIDitatea (atomice, consistente, izolate și durabile).

Caraterul ACID este dat de:

  • Atomicitate – orice operațiune fie se termină cu succes, fie se termină cu eroare nelăsînd părți modificate;
  • Consitență – orice operațiune trebuie să fie validă, ducînd aplicația dintr-o stare validă într-o altă stare validă (validă din punct de vedere al OS și nu al aplicației pentru că OSul nu poate ști ce e aia stare validă pentru ea);
  • Izolare – OSul trebuie să asigure spațiu de memorie izolat fiecărei aplicații, nepermițînd unui alt software să modifice direct în spațiul dedicat;
  • Durabilitate – odată ce o operație s-a terminat toate efectele sale rămîn, orice altă operațiune ulterioară nemaiavînd acces la datele inițiale.

Object management

Dacă primele două roluri au fost evidente și cam toate sistemele de pînă acum s-au achitat onorabil în implementarea corectă a lor, partea de Object Management a fost PROST gîndită în toate OSurile cunoscute. Daca în vremurile cu hardware scump se putea trece cu vederea lipsa de viziune asupra acestui rol primordial al OSului, azi trebuie să-l avem în centrul atenției pentru că obiectele care există și interacționează într-un OS sunt suficient de complexe și diferite așa încît comunicarea dintre ele să nea de peste cap (să introducă o complexitate nejustificată) multe aplicații propuse.

Abordarea inițială a fost everything is a file și a funcționat o vreme. Prin simplitatea ei a permis orientarea țintelor optimizării software către primele două roluri, ceea ce e de înțeles pentru că hardware-ul era scump și nu așa de rapid. UNIXul a rulat inițial pe hardware de sub 1MHz !!?! Critica principala a acestui model o aduc virușii. Nediferențierea între o aplicație și un fișier de date a făcut posibil ca aplicații malițioase să se camufleze sub formă de date (documente, poze, etc). De asemenea, dacă într-un sistem modern un obiect poate fi izolat doar la acțiuni specifice, în vechime everything is file a permis accesul tuturor aplicațiilor la tot sistemul de fișiere (fie ele de bună credință sau malware). Chiar dacă teoretic sub drepturi de acces, o simplă operațiune ce pretindea drepturi full-admin putea duce la infectarea sau accesul la date confidențiale a unei aplicații răuvoitoare latentă în sistem.

Sistemele moderne trebuie să cunoască natura obiectelor (aplicații, date chioare, hardware virtualizat, video, formulare), să le identifice, să le izoleze și să le permită doar acțiuni specifice. În ziua de azi autentificarea se face ușor prin certificate SSL, prin același mecanism de identificare existent și testat pe internet. Se practică și identificarea sursei de instalare, Apple App Store, Windows Store, GPlay obligînd dezvoltatorii să-și publice aplicațiile în cadrul unor servicii publice unice. Mecanism prin care marii producători pretind că verifică aplicațiile, fapt imposibil dat fiind numărul mare de programe și producători, dar care nu face decît să le dea un control foarte mare asupra distribuției (care azi înseamnă publicitate pe bani mulți).

Tot aici se va asigura comunicarea (standardizarea comunicării) între obiecte. S-au dezvoltat două mari protocoale DCOM și CORBA (după două mari categorii de OSuri, Win și *NIX). Practic un obiect își înregistrează serviciile publice într-un registru gestionat de sistem de unde clienții află de ele și încearcă să le consume. Celebrul Copy/Paste, indispensabil azi, este cel mai bun exemplu de comunicare asigurat de rolul Object Management și care nu era posibil în era EisF.

It’s fine to provide guidance for beginners, but education isn’t a substitute for great app design. First and foremost, make your app intuitive. If too much guidance is needed, revisit the design of your app.

See Design Patterns, part one; Introduction to get the definitions and the laws of design patterns.

Structural Patterns define the way objects are connected with other objects so changes in the system do not affect these connections. Again, the low coupling law is the base for the app designs.

There are eight patterns:

  • Adapter – converts the interface of a class into another interface clients expect;
  • Bridge – separates an object’s interface from its implementation;
  • Façade – provides a more comfortable way to deal with a library or bundle of resources;
  • Decorator – adds objects responsibilities dynamically;
  • Flyweight – reducing the number of objects;
  • Proxy – an object representing other object;
  • Composite – to compose objects into tree structures to represent part-whole hierarchies;
  • Private Class Data – restricts accessor/ mutator access.

 

Adapter

Adapter converts the interface of a class into another interface clients expect, as any cable adapter you may encountered. Usually you want to reuse an old component that offers compelling functionality, but its “view of the world” is not compatible with the architecture of the system currently being developed.

Reuse has always been painful and elusive, against everything that theorists said – OOP is about reuse, reuse and reuse. There is always something not quite right between the old and the new. It may be physical dimensions or misalignment. It may be timing or synchronization. It may be unfortunate assumptions or competing standards.

Adapter functions as a wrapper or modifier of an existing class. It provides a different or translated view of that class. Adapter provides a different interface to its subject, Proxy provides the same interface. Adapter makes things work after they’re designed, Bridge makes them work before they are.

Proxy

Proxy speaks for other object. It is used to support distributed, controlled or intelligent access.

You can think about Proxy when

  • you need to delay the creation of a costly object until it is needed;
  • you have to control communication with remote objects;
  • you want to control access to objects;
  • you may want smart reference to an object – caching, locking etc.

Façade

Façade wraps a complicated subsystem with a simpler interface. An Operating System is a Façade for hardware. An eCommerce site is a Façade for ordering, billing and shipping the goods.

The Façade design captures the complexity and collaborations of the component and delegates to the appropriate methods. The client uses (is coupled to) Façade only.

Adapter and Façade are both wrappers. Façade defines a new interface, whereas Adapter uses an old interface. Adapter wraps a single object, while Façade routinely wraps multiple objects. Façade could front-end a single complex object and Adapter could wrap several legacy objects.

Bridge

The goal of Bridge is to allow you to structure your code so that you can easily add new kinds of front-end objects which are implemented with functionality in new kinds of back-end objects. Therefore, both handle and body can vary independently of each other.

Bridge is really a code-organization tool that allows you to add in any number of new front-end services that implement their operations by delegating to any number of back-end options. Using Bridge, you can accomplish this without the normal combinatorial explosion of possibilities that would otherwise occur.

Flyweight

Some programs require a huge number of objects that have some shared state among them. Each flyweight object can be divided into two pieces: the state-dependent (extrinsic) part and the state-independent (intrinsic) part. Then put them to share that intrinsic part to save memory. The key here is the HUGE number of objects. The simplicity law ask us to get it only if the memory is a pain.

Decorator

Too many classes! Decorators provide a flexible alternative to subclassing for extending functionality. Instead to create all combination at design time, you will add dynamically behavior or state to individual objects at run-time.

Note that this pattern allows responsibilities to be added to an object, not methods to an object’s interface. The interface presented to the client must remain constant as functionalities are specified.

There are some tradeoffs: coding is more complicated when using Decorators. So, try compromise – there will always be certain combinations that you will describe regularly, which would often work exactly as they are, but if you wanted to decorate them then you would use decorators to make the modifications. This will keep your code readable and maintainable.

Private Class Data

  • Encapsulate class data initialization!
  • Control write access to class attributes!
  • Separate data from methods that use it!

Yes, these are the first lessons in coding. And yes, it is about a design pattern, if you check the definition of Design Patterns.

Composite

The common objects relationship in computing – Containers that contain Containees, each of which could be a Container.

Divide your domain concepts into container classes and containee classes. Create a lowest common denominator interface that makes your containers and containees interchangeable. It should specify the behavior that needs to be exercised uniformly across all containee and container objects.

In a larger Composite problems could arise as recursion is always expensive.

G.

 

See Design Patterns, part one; Introduction to get the definitions and the laws of design patterns.

Creational Patterns are used to isolate the details of object creation. They will help us stay under the law of low coupling. App controllers will be decoupled of object types and they will not change as new types arrived. Creational Patterns are about how an object can be created.

There are identified six patterns (more or less an exact number, they have not yet standardized the patterns):

  • Singleton – only one instance can exist;
  • Factory Method – creates an instance of several derived classes;
  • Abstract Factory – creates an instance of several families of classes;
  • Builder – to separate the construction from the representation to allow multiple different representations;
  • Object Prototyping – creates objects based on a fully initialized instance (copy or clone);
  • Object Pool – avoid expensive acquisition and recycle.

 

Singleton

You may use Singletons when your application needs one, and only one, instance of an object. The first intent is to prevent the client programmer from having any way to create an object except the ways you provide.

There are many examples of Singleton usage:

  • any Factories as they are a global need;
  • logging points;
  • configuration classes;
  • lookup service;
  • accessing resources in shared mode.

There are several implementations of this pattern, but all make all constructors private and create at least one constructor to prevent the compiler from synthesizing a default constructor. Some of the theorists ask for lazy initialization, but I do not consider it a must. The Singleton design pattern is one of the most inappropriately used patterns. Singletons are intended to be used when a class must have exactly one instance, no more, no less. Programmers frequently use Singletons in a misguided attempt to replace global variables, why the hell are you using global data?

Object Pool

Sometimes objects are expensive (eg. db connections) and you can think about recycling them. This is a technique to create a limited pool of objects.

As a Factory Design it is a Singleton. Factories create the objects and then forget about them, but The Pool manages objects lifetime and keeps track of them.

Factory Method

The new operator is considered harmful and this pattern makes the difference between requesting an object and creating one. The new operator always creates an object and fails to encapsulate object creation. Factory Method enforces that encapsulation and allows an object to be requested without inextricable coupling to the act of creation.

When you need to add new types to the system the first idea is to use polymorphism as new types may be added without disturbing existing code. If the code that creates objects is distributed throughout your application, you must chase down all the points of your code where type matters and you will broke the night compilation. The solution is to force the creation in one place through a common Factory. As you get experience I suspect that Factories will be the most universally useful kinds of design patterns.

Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward more abstract as the designer needs more flexibility.

As OOD has two fundamental ways to relate classes – inheritance and composition here you may also think as two ways to create objects – Factory Method use creation through inheritance and Prototyping creation through delegation. Prototype doesn’t require subclassing, but it does require an Initialize operation. Factory Method requires subclassing, but doesn’t require Initialize.

The most used example is the injection mold press. Manufacturers of plastic toys process plastic molding powder and inject the plastic into molds of the desired shapes. The class of toy (car, action figure etc.) is determined by the mold.

Abstract Factory

Provide an interface for creating families of related or dependent objects without specifying their concrete classes. It is a natural evolution of Factories as modern applications can run on different platforms. If an application is to be portable, it needs to encapsulate platform dependencies (including UI, OS, DBs etc). The application must replace the entire family of products simply by instantiating a different concrete instance of the abstract factory. In other words, The Abstract Factory is a super-factory which creates other factories (Factory of factories).

Follow the law of simplicity and do not consider platform independency if not needed. To get one more abstraction layer just because you do not choose what DB to build on it is a very bad design. First to do is a Pro-Cons matrix of “platforms” versus “products”, sometimes it is easier and cheaper to build products on platforms.

Builder

The goal of Builder is to separate the construction from the representation to allow multiple different representations. The construction process stays the same, but the resulting object has different possible representations. The differentia of Builder in Factories is that it has multiple steps in creating an object and those steps are accessed externally to the Builder object.

An old lady thought me that McDonalds is using a builder process. Whether a customer orders a hamburger, cheeseburger or chicken the process is the same. The employee at the counter directs the crew to assemble a main item, side item and toy. These items and the drink are then placed in a bag.

Prototyping

The mitotic division of a cell – resulting in two identical cells – is an example of a prototype. The new operator is considered harmful and then we can consider build our own Factory that cache prototypical objects for use as breeders of all future instances. javascript is the common object-oriented language that relays on Prototyping.

A problem with the other Factory designs above is that they require a central location where all the types of the objects must be known: inside the factory( ) method. If new types are regularly being added to the system, the factory( ) method must be changed for each new type. When you discover something like this, it is useful to try to go one step further and move all of the information about the type, including its creation, into the class representing that type. This way, the only thing you need to do to add a new type to the system is to inherit a single class.

 

At the end I must emphasize that sometimes Creational Patterns are competitors: there are cases when either Prototype or Abstract Factory could be used properly. At other times they are complementary: Abstract Factory might store a set of Prototypes from which to clone and return product objects.

G.

 

These days I’ve been asked to teach these junior software developers several advanced features of Object Oriented Programming and I’ve started this class of Design Patterns. This is a drought, a skeleton, to develop the course.

What are Design Patterns? I don’t know, ;). Can be thought as grounded best practices to solve a class of problems, to have the most general and flexible solution for them. To define what patterns are we have to think about advanced application design. The advanced practice in software developing is to separate the thinks that change from the ones that stay the same. We introduce this abstraction layer into our applications to isolate changes and keep them to propagate other changes throughout the code (of course, the difficult part is to identify what change). Once you have isolated the changes in your code you have some kind of a pattern. Is it a Design Pattern? Nope, you will achieve it when you go with the most general solution.

Four problem solving techniques:

  • language specific – when use language features to get the problem solved;
  • specific design – when use the described technique to solve specific problem;
  • standard design – to solve some kind of problems (repetitive reusable pieces of codes);
  • design patterns – the most general and flexible solution for a class of problems.

Do not let them fool you with words – generalizing is not a goal, is a means. Do not waste your time looking for patterns, start thinking about your problem and in time they will be revealed.

Classifying patterns:

  • Creational – how objects are created; used to isolate the details of object creation;
  • Structural – the way objects are connected with other objects so changes in the system do not affect these connections;
  • Behavioral – objects that handle particular actions.

The laws of application design:

  • the simplest solution is the best; of course you have to consider full application life-cycle, but simplicity is the base;
  • avoid duplication;
  • isomorphism – one abstraction per class, one class per abstraction;
  • consistency – keep your ideas in place;
  • low coupling, high cohesion – coupling refers to the degree to which the objects depend on each other, cohesion refers to the degree to which the objects belong together;
  • keep your code readable (my first choice);
  • keep surprises out;
  • make common things easy and rare things possible;
  • use YAGNI – the design is finished when anything cannot be removed;
  • keep your unit testing updated.

G