Showing posts with label Software. Show all posts
Showing posts with label Software. Show all posts

Sunday, January 23, 2022

An advisory CTO: does it help to hire one?

As a consulting CTO/Engineering head for small-sized and medium-sized software product firms for about one and half a decade, often times I am asked this question by the main stakeholders of current and potential clients: why do I need your service? What can you do, that can benefit us?

It is an obvious question to ask. It is a fair question too. Over years, I have tried to answer this question to the best of my ability and intent. It will be a lie if I say that every time, my explanations drove home the point, as concisely as one expected. However, a theme underpinned my answers, every time. This write-up is an elaboration of that theme.

It helps to have someone as a sounding board for all things technical, behind your product

As your idea is taking shape or your offering is getting newer features (thereby bringing in new customers, you don’t want to lose the momentum. Catering to customers’ demands, adding features to the product, positioning it for newer market segments: all these are important for you and your Product Management team. However, the software stack that is going to lie underneath all these, has to support the offering, all along. Some level of plumbing is necessary now and cheap; the rest should be built as the direction of the product becomes clearer with the journey. A CTO can hear your plans, co-visualize the product alongside you, align your vision with trends of technology and outline for you technical underpinning that must evolve, you will have a much better view of cost of building what you want to build, the time it is going to take and the risks and benefits that alternatives offer.

Your Product Management team must be heard well and told clearly

Your Product Managers have ideas. They are quite enthusiastic about those. They would want these ideas to be implemented/realized as early as possible. However, they look for assurances from the engineering/technical team about the feasibility. The engineering team has to know really, really well what needs to be built, in order for those ideas to be materialized. An experienced CTO/Engineering Head can bridge this gap effectively and quickly. One cannot emphasize the importance of this act of elaboration: the correctness and completeness of the next several milestones of the product depend overwhelmingly on how well the boundaries are drawn and innards are sketched. Some times, the CTO may insist on restricting some feature temporarily so that subsequent features can be rolled out much faster. Some other times, the Engineering head may advise to fold two seemingly unconnected features together because of very beneficial reuse of components. A CTO can be the perfect interlocutor and devil’s advocate who talks straight, all for your benefit.

The future versions of the software requires deep and wide considerations

First version of the product came into being primarily because the first customers had to be acquired. Because of value your product continued to put forward, next few customers came in too. Now, the expectations of these customers — and of many potential future customers — are weighing heavily in your plans and in your software. The second version has to be built right, because the next phase is not only of growth but also of retention. The technical choices and decisions that your engineering team faces, turns quite challenging as the product begins to cater to variety of customers. The overall architecture may need a revisit. The non-functional requirements may crystallize and pose questions about the current technical structure. Perhaps, several proof-of-concept exercises become necessary. Your engineering team finds themselves in a flux. The steady and reassuring presence of a CTO can be immense help in situations like this.

Accidental complexities of software have to be dealt with

The primary features of the product you build, don’t necessarily depend on the complexity that the software begets or is infused with. You may begin with a browser-based UI but soon decide to move to native mobile apps. The code-bases increase. The areas of expertise required, increase. In effect, the whole of the development pipeline is affected, one way or the other. Business may demand a move to a cloud provider. The operational aspects spring up. The laws of the land may demand special actions to ensure privacy of your customers. All these cost money, time and effort. You will need someone to think and plan through these not-so-straightforward aspects. Someone must understand what the engineering team is facing and help align their preparatory or mitigative steps that gain confidence the Product Management team. As the accidental complexity grows, so do the need of specialized expertise in your engineering team. Your CTO will ensure that right teams are given the right tasks and establish appropriate engineering best practices. By avoiding mistakes she has learnt through her experiences, she can prevent cost of release and rework (this can be a substantial cost).

Your engineering team is your asset too; nurture the members and environment

Collectively, your engineering team carries a picture of the product: the various inputs and outputs, their formats, the points of integration with other 3rd party software, schema of the data storage, boundaries of primary business functions and their representation in executable form etc. They want the software they have built, to be used extensively by the intended users, both internal and external. That is the source of their **self-actualization**. An enthusiastic and expert team can, not only bring to fruition newer features smoothly, but also attract equally enthusiastic and expert staff from outside. Put differently, in order for the product to grow and meet expectations — speedily and timely — your engineering team has to be at its best. And, which challenges do they solve and how, go a long way to induce other great software technologists from outside to your organisation. A CTO can bring about the passion and commitment to your engineering team and help build a culture that stands your organisation in good stead. In a larger sense, such a team is one of the main ingredients of the world-class product that you build.

By hiring a CTO/Engineering Head — even in advisory or consulting positions — you and your stakeholders can be highly benefited. By having a clear understanding of the business and its future as well as a fantastic grasp of technology trends, with hands-on knowledge as necessary, a CTO can anticipate directions that your business is going to take, take preparatory measures on behalf of your technology team and help your business stay ahead of the curve, as it were. In the process, she also prevent not-so-obvious mistakes your engineers are likely to make and save you from unnecessary costs.

Wednesday, November 16, 2016

Finite State Machine using Akka (2): modeling multiple elevators in a hotel

This is second part of the series that I am writing on this topic. The first part is here.

In this post, I will elaborate the code structure a bit. This may help in getting hold of the design I have chosen.

To help us get the context, here’s a summary of the Use-Case we are targeting:
A hotel employs a number of lifts/elevators. A Controller coordinates their movement. A lift’s carriage gets its inputs (press on a button) either from a passenger waiting at floor’s lobby or from a passenger inside it, who chooses the floor she wants to go to, using the panel mounted inside.

Here’s is a block diagram showing for components that our model is using.

Implementation

We will form the right solution for the Use-Case (outlined at the beginning), step-by-step.

A carriage is represented as an Actor:
class LiftCarriageWithMovingState (val movementHWIndicator: ActorRef) extends Actor
 with LoggingFSM[LiftState,LiftData]
 with ActorLogging
{ // …
}

The construction parameter movementHWIndicator is the actor which represents the hardware circuit associated the carriage which indicates end of movement (i.e., arrival at a floor). We are representing that as a trait:
trait MovingStateSimulator extends Actor with ActorLogging {
// ..
}

So, at the time of construction, LiftCarriageWithMovingState receives an ActorRef which refers to an instance of MovingStateSimulator.

The states that the carriage can be in, are enumerated as follows:
sealed trait LiftState
object PoweredOff extends LiftState
object PoweredOn  extends LiftState
object Ready      extends LiftState
object Waiting    extends LiftState
object Moving     extends LiftState
object Stopped    extends LiftState

A vector named pendingPassengerRequests holds the request for movement that have reached the carriage so far. The head of pendingPassengerRequests    always represents the next floor to stop.
private var pendingPassengerRequests: Vector[NextStop] = Vector.empty

Every stop is represented as a tuple of floor’s number and the reason why it is moving to it:
case class NextStop(floorID: Int, purposeOfMovement: PurposeOfMovement)

object PurposeOfMovement extends Enumeration {
 type PurposeOfMovement = Value
 val ToWelcomeInAnWaitingPassenger, ToAllowATransportedPassengerAlight = Value
}

After it is switched on, every carriage is at the ground floor and is in Ready state.

While in the Moving state, the carriage responds to three events:
when (Moving)              {
   case Event(ReachedFloor(currentStop),_) =>
     currentFloorID = pendingPassengerRequests.head.floorID
     pendingPassengerRequests = pendingPassengerRequests.tail
     goto (Stopped)

   case Event(PassengerIsWaitingAt(floorID),_)      =>
        this.pendingPassengerRequests = accumulateWaitingRequest(floorID)
        stay

   case Event(PassengerRequestsATransportTo(floorIDs),_)                =>
     this.pendingPassengerRequests = accumulateTransportRequest(floorIDs)
     stay
 }

While in the Stopped state, the carriage waits for some time for the door to open, to let the passengers come in or go out, and then for it to close. If there is no pending requests, it goes back to Ready state:
private val actWhenStoppedForLongEnough: StateFunction = {
   case Event(StateTimeout, _)   =>
     if (this.pendingPassengerRequests isEmpty) {
       log.debug("Stopped.timeout, No pending passenger requests")
       goto (Ready)
     }
     else {
       log.debug( s"Stopped.timeout, moving to floor:( ${this.pendingPassengerRequests.head} )")
       movementHWIndicator ! InformMeOnReaching(
                                 this.currentFloorID,
                                 this.pendingPassengerRequests.head)
       goto(Moving)
     }
 }

Whenever pendingPassengerRequests is empty, the carriage is in the Stopped or Ready state and is stationary at the last floor it has reached.  

Simulation of consumption of time while Moving

When the carriage is moving, it must expend time doing that. Moreover, while it is expending time, asynchronous events are possible to arrive (from the Controller or the Button Panel: both actors in their own rights). Because movementHWIndicator is an Actor, it is easy to model the asynchronicity by generating its signal using a Scheduler, after a delay.
Because the Scheduler runs on ActorSystem’s scheduler thread, it becomes messy when we want to test behaviour of LiftCarriageWithMovingState together with a MovingStateSimulator. I had to mock the behaviour of MovingStateSimulator. However, Instead of mocking it using a framework, I have decided to use a do-nothing Actor to construct a LiftCarriageWithMovingState. Its behaviour is much like that of an echo Actor:

trait MovingStateSimulator extends Actor with ActorLogging {

 case class SpentTimeToReach(nextStop: NextStop, carriageToBeInformed: ActorRef)

 val timeToReachNextFloor: FiniteDuration = 1000 millis  // up  or down, same time taken
 def simulateMovementTo(
      fromFloorID: Int,
      nextStop: NextStop): Unit

 override def receive: Receive = {
   case InformMeOnReaching(fromFloorID,nextStop) =>
     if (fromFloorID == nextStop.floorID) // Just a regular edge-case check
       sender ! ReachedFloor(nextStop)
     else
       simulateMovementTo(fromFloorID,nextStop)

   case SpentTimeToReach(nextStop,carriageToBeInformed)   =>
     log.debug(s"Informing ${carriageToBeInformed} after reaching the floor.")
     carriageToBeInformed ! ReachedFloor(nextStop)
 }
}

object DefaultMovingStateSimulatorActor extends MovingStateSimulator
 with ActorLogging {
 override def simulateMovementTo(
                fromFloorID: Int,
                toNextStop: NextStop) = {
   // Immediate response, no time consumption in moving
   sender ! ReachedFloor(toNextStop)
 }
}

Finally, we have a  Controller and a InlaidButtonPanel to complete the story:
class InlaidButtonPanel (
        panelID: Int, attachedToCarriage: ActorRef, val noOfFloors: Int = 10)   
extends Actor
with ActorLogging{ // ..
}

class LiftController (carriages: Vector[ActorRef]) extends Actor
 with LoggingFSM[LiftState,LiftData]
 with ActorLogging { // ..
}

Remember that a Carriage receives the instruction to pick a passenger from the Controller and to drop a passenger, from the button panel.

The following is a sample output log of a hotel having two lifts (enumerated 0 and 1) available. The Driver code emulates a instruction sequence of
A passenger presses a button at the lobby of floor 2
A passenger presses a button at the lobby of floor 4
Controller checks with Carriage(1), at which floor it is now
// Carriages reach floor 2 and 4 after some time...
Passenger inside Carriage[0]wants to go to floor 5, presses button
2 Passengers inside Carriage[1]; one wants to go to 6 and the other, to 2; press buttons
Controller checks with Carriage(0), at which floor it is now
Controller checks with Carriage(1), at which floor it is now
Controller checks with Carriage(0), at which floor it is now
Controller checks with Carriage(1), at which floor it is now

The output (pruned for space and readability):
Selection_195.png
The latest code is here.

While writing this blog, I have read a number of blogs on the same / similar topic. Some of them which I enjoyed reading were: