Friday, 30 October 2020

OOP Object interfaces and decomposing the blob class

Introduction

The interface of the object should provide meaningful services to clients. A problem arises when too many jobs are assigned to one class of object for example a client object:

class Client {

public:

    void Authenticate();

    void SendMessageToChat();

    void JoinChatRoom();

    void LeaveChatRoom();

    void JoinGroup();

    // etc

}

Looks fine and useful but why does the client contain the information to manage groups and chat rooms?

Interface beauty and implementation blob

This object looks fine from the interface point of view and incredibly useful in that all the functions you need are in one place. But, it suggests a problem with the implementation behind the interface. The problem doesn't seem to be the interface semantically/syntactically but a problem in terms of information.

Since the Client's interface is the set of operations on the Client object, why does the client object contain the information to manage chat rooms, groups and all the other objects? The Client object holds way too much information about the rest of the system. This is known as a "God class" or "Blob".

Decomposing the blob

A solution for this would be to seperate the client object into further important concepts:

class Server;
class User;

class Client {

public:

    void Authenticate(Server& server);

}

class ChatRoom {

public:

    void Join(User& user);

    void Leave(User& user);

    void Post(User& user, string message);

}

class Group {

public:

    void Join(User& user);

    void Leave(User& user);

}

Here the information is spread across meaningful objects in the system which is more desireable since now each object can be thought of and maintained individually (for example assigning multiple people on each object instead of all on the client object).

Paraphrasing the collaboration, Subject not object

Additionally there error made in the design in the original client class is that the client object is not viewed as the subject of the methods calls. For example; the object method SendMessageToChat() could be paraphrased as "tell the client to send a message to the chat" or "the client can send a message to the chat" but in these phrases the subject is Chat not Client. This is a confusing notion however its simplifed if you remember that an object is the subject of its methods and wording the class collaboration appropriatly. The original client seems to be a functional decomposition instead of a data abstraction view.

Conclusion

When creating objects, always remember that the object is the subject and to carefully paraphrase the collaborations.

Tuesday, 20 October 2020

Commands, queries and side-effects (object interface design)

Commands and queries

"A machine has 2 types of buttons, command and query buttons. When a command button is pressed, the machine performs work and its state is modified. When a query button is pressed, the machine returns some information about it." - Bertrand Meyer

Command corresponds to procedures, they do not return any results. For example:

class MyMachine {

public:

    void SetName(const char * name); // is a command/procedu

}

Query corresponds to functions or attributes, for example:

class MyMachine {

public:

    void SetName(const char * name);     // command/procedure

    const char * GetName() const;        // query/function        

    bool ProcessingReady() const;        // query/attribute

private:

    const char * name;

}


Side effects

 "A side effect on an object is an operation that may change at least one attribute of the object."

The above command and query view is important with relation to side effects since  according to Bertrand Meyer in his book XXX (Chapter 7.7.2 "Commands and queries", Page 134)...

"The clean seperation between procedures and functions averts many of the pitfalls of traditional programming. Side-effect-producing functions, which have been elevated by some langauges (C seems to be the most extreme example) to the status of an institution, conflict with the classical notion of function in mathematics. A mathematical function will always give the same result when applied to the same argument."

Conclusion

From this information, we can create better class interfaces and keep them "more true" to the mathmatical foundation of abstract data type theory. This means that our code is closer to "formal verification" than guesswork.



Wednesday, 7 October 2020

ADT, type theory and set theory.

Intro

Mathematical models underpin most (arguably all) software, to create models we need to understand the bits that make them. Sets, types, algebraic structures.

Type and set theory provide the formal definitions for programming today. I believe that understanding how these pieces fit together we can create "better" software; more readable, easier to debug.

There is a saying that "the ideal solution for a professor to a problem was to introduce 10 classes instead of creating 1 function" and i think that this blog post might shed light on it. By distinguishing Types from Sets from Algebraic Structures and ADTs.

Sets and types

Sets and types are similar concepts and can both be thought about at a high level.

  1. They are used in logic.
  2. They are used to create models.

Since programming is about representing concepts and creating models, sets and types are important.

An example of a type is PERSON, and using programming we can represent this type in many ways, the most common is by using classes. Therefore we can create a class called PERSON which represents the type PERSON. Also, we can view the PERSON type as a set, it is identical to the type view.

class PERSON {
public:
 void Op();
private:
 bool HasName();
private:
 int data;
};

Algebraic structure as ADT as set/type

An algebraic structure is defined as a carrier set, operations, axioms and distinguished members. The above classes are expressed as an Abstract Data Type. Where PERSON is the carrier set (or type), operations are Op(), and an example of an explicit axiom is HasName().

Since we can represent algebraic structures with an ADT. And algebraic structures can represent types/sets, therefore, we can represent types/sets with an ADT. This is recursive definition where we can represent a set of a set using two ADTs.

Conclusion

By using classes we have bound the operations to the type/set explicitally, this means we can more easily represent individual types than individual sets. However, the unification of the two means that while programming, "names run out" and we often find ourselves creating strange types to manage types. However, if we seperate the carrier set and the operations that perform on it, we can create more sensible programs. To summarise; by using classes to create individual types and favouring modules over types to perform functions. We might end up with better sematic and formalized programs.

Seperating OOP objects and modules using this as our reasoning gives us a huge amount of flexibility with how we structure our programs. On the one hand we can create descriptive real-life heirarchies by following the type view, where PERSON is-a HUMAN and using polymorphism for dynamic dispatch. On the other hand we can functionally decompose the programs system into modules which more directly represent what the software is doing.

I believe that a common error with modern OOP (where real life concept=object) is that everything is strictly a type, and never viewed as a algebraic structure. Functions are bound to the objects as types and then more types are created to hold functions that manage other types. Now this view may seem ideal, and represent real life perfectly where say; a chest holds and number of items, however as we can see above, type theory is not the only way to create programs. This is reflected with Java, with a heavy use of type theory the application can be overly verbose and make abstractions that are wasteful and make no sense.

References

  1. https://en.wikipedia.org/wiki/Abstract_data_type
  2. https://en.wikipedia.org/wiki/Algebraic_structure
  3. Discrete Mathematics in Computer Science - STANAT, DONALD F - 1977 - ISBM 0-13-2160528 - Chapter 7 Algebras, 7.1 Structure of algebras

OOP - Recovering lost class types

 Normally casting is used to convert classes to other classes, however this operation can break the type system. For example, a "List&q...