DEV Community

loading...
Cover image for The untold truth I learned about frameworks

The untold truth I learned about frameworks

ov1n profile image ov1n ・9 min read

tl;dr : No mater how much beautiful,sophisticated web systems you could make by using frameworks, try doing everything by yourself manually once and you'll gain a huge insight as a developer. We learnt this throughout our group project and this is how.

The Setting:

So exactly almost a year ago for our 2nd year curriculum , me and 3 others were allocated to a group (almost randomly 😙) and our module content was to create a web application for a real-world client. Sounds simple right? Well, the catch was,

  1. Since we did not go for a mobile app (which had to be done using native Android) Along with HTML and vanilla CSS we had to use either PHP or Java as the backend.

  2. We weren't allowed to use ANY FRAMEWORKS .not even Bootstrap .

Alt Text

In a modern society where even a 12-year-old simply uses npx create-react-app my-app to kick-start things, me and my teammates were baffled by why our lecturers wanted us to basically "reinvent the wheel" with technology that is almost obsolete now.

But being almost new to a project of this scale, we soon learned otherwise, and to this date consider this as the best learning experience we had as beginner developers.

Our project:

Repository link:
https://github.com/ov1n/Cleancar

The business idea was simple, A system for a car service station with 2 components where,

User Role Functionalities
Customer Place a reservation from a real-time time table
Employee Apply for Lieu , and see statistics
Receptionist Place emergency reservation , add employee etc.
Manager Could confirm/reject them and see statistics.

Other Functionalities:

Contributors:

what could go wrong

The architecture at-a-glance:

Since our rubric contained that marks will be awarded for the architectural pattern of the project, we chose MVC (at first over a Discord call within 5 minutes because it sounded awesome and we've heard of it in many Indian coding tutorials, but later had to know because of the questions we got in the interim presentation)

Project was done using a modified MVC archtecture

Well, we planned it out this way for the UI flows, there were a difference or two at the end
UI flow

Where the disaster started (or fun began):

CSS 😌

A main reason most of us use bootstrap or tailwind for a site is because they have responsive components. ever wondered how you hard-code responsiveness in CSS? It looks like this:

@media screen and (max-width: 900px){
  .card{
    margin-left: 10%;
    width:80%;
  }
}

@media screen and (max-width: 800px){
  input[type=text], input[type=password], input[type=email], input[type=date],input[type=tel] ,input[type=time],select{
    margin-left: 2%;
  }
}

@media screen and (max-width: 750px){
  input[type=text], input[type=password], input[type=email], input[type=date],input[type=tel] ,input[type=time],select{
    width: 200px;

  }
}
Enter fullscreen mode Exit fullscreen mode

Now think this being repeated and customized either by percentage or by pixel for seperate relevant classes in the website 😵

With tons of modified classes and without preprocessors we managed to get by a responsive layout. The credit should go to flexbox.

ahh.. responsive :3

And who said good data visualization can't be done without librarires 😆
leave report

Lessons learnt and experience gained:

  • Making pages responsive with Vanilla CSS and flexbox
  • Data Visualization without libraries

MVC?? 🤖

During our interim presentation when the panel asked us "Why do you use MVC?" and asked us to view the content of the default controller and model we did not know the answers and afterwards we soon realized it has something to do with how the framework had been set-up in environments such as CodeIgniter and Laravel

The solution 😴 :

Our Framework

So our framework basically has,

  1. An autoloader for classes
  2. A view loader in the default controller
  3. A query builder for SQL functions
  4. A router (to disable URL SQL injections)

The autoloader was made in the root folder included into the index.php to load the Classes by name.

<?php
require_once './lib/routes.php';    //load routes

//to autoload classes,models and controllers
function __autoload($class_name){
    if(file_exists('./lib/classes/'.$class_name.'.php')){
        require_once './lib/classes/'.$class_name.'.php';
    }else if(file_exists('./Controllers/'.$class_name.'.php')){
        require_once './Controllers/'.$class_name.'.php';
    }
}
?>
Enter fullscreen mode Exit fullscreen mode

The default controller was there to load the view and if there were additional parameters (passing of back-end, session variables etc.) it was overloaded in that respective controller. Since there are 4 user roles in the system and some had elevated privileges, with the help of session variables only the privileged role was allowed access to that page and otherwise redirected to a 403-Forbidden page.
The create_view function in the default controller:

public static function create_view($view_name,$role){

            if($role==""){
                //no permission needed
                require_once("./views/$view_name.php");
            }
            else if($role=="loggedin"){

                if(Session::get("role")){
                    require_once("./views/$view_name.php");
                }

            }else if(Session::get("role")==$role){
                require_once("./views/$view_name.php");
            }

            else{
                require_once("./views/error_403.php");
            }
        }
Enter fullscreen mode Exit fullscreen mode

The function was called in the routes.php file as,

        Session::init();
        //logout if time is exceeded in session
        Login::timeout(Session::get("curr_time"));
        Manager::create_view('manager_home','manager');
Enter fullscreen mode Exit fullscreen mode

For the default model after including the database connection and methods for object instantiation (A constructor which calls the class in app/lib/Database.php to establish the connection), we implemented separate functions for each query type based on parameters provided.
Yes it's a simple string builder but it did the job for all Model functions 😁
Following is the SELECT function and we considered the rest of queries too in the app/models/Model.php to call the functions.

function select($arr,$tableName,$condition){
            //$condition= "WHERE custid=.......INNER JOIN...."

             //if arr is * select all from the table
             if($arr=="*"){
                $sql = "SELECT* FROM ".$tableName." ".$condition;

            //otherwise string concat the fields to select
            }else{

                $sql = "SELECT";
                //WHERE e='p' group by ................
                //if an array is the input get the fields
                if(gettype($arr)=='array'){

                    foreach ($arr as $elem) {

                        //if it's the last field comma is omitted
                        //SQL HAS ERROR IF LAST ELEMENT IS RECURRING BEFORE ITLL BE TAKEN AS FINAL ELEMENT
                        if($elem==$arr[count($arr)-1]){
                            $sql.=" ".$elem;

                        //if not get all fields necessary for select
                        }else{

                        $sql.=" ".$elem.",";
                        }

                    }

                //otherwise if its a string just append it without a loop
                }else if(gettype($arr)=='string'){

                    $sql.=" ".$arr;
                }


                $sql.=" FROM ".$tableName." ".$condition;
            }

            //echo($sql."\n");
            $result= mysqli_query($this->conn,$sql);

            //debugging
            if (!$result) {
                printf("Error: %s\n", mysqli_error($this->conn));
                exit();
            }

            return $result;

        }
Enter fullscreen mode Exit fullscreen mode

The routing was done by the paths given in the routes.php file which are a compilation of calls to the functions in the Route.php.
The .htaccess file was rigged with regex to prevent SQL injections so a separate path was allocated for each page that was loaded.
This was a pivotal point as I was able to get a great understanding on general Regex programming.

Lesson learnt and experience gained:

  • Handling of PHP variables and associative arrays (eg: date=>time=> time_slots)
  • Folder structuring of files folder structure

Real-time scheduling time-table (The Cherry on top) 🍰 or my masterpiece 😏

As told earlier all of us had only moderate-to-beginner experience in coding for big projects. JavaScript was also the same 😒. So as we superfluously included in our SRS that we will be having a component similar to the seat-booking system in Scope Cinemas (Guys, please brainstorm and only include what you CAN ACTUALLY DO in your projects.) as the time drew closer to the final demonstration shi* just got real 😵 .
Personally for me connecting PHP and JavaScript was like eating Butter Cake with Parippu.

But after almost 3 weeks of learning on-the-fly table creation, passing back-end PHP variables to JS variables, animation customization and event listeners the end product was like this:

The customer reservation system

For vanilla CSS it's fancy right? Well, this is the just the back-end controller (without the rest of JS and model functions) of the calendar

static function get_time_slots(){

            $timeslot=new Time_slot();
            $service_type=new Service_type();

            $min=$timeslot->get_min();
            $max=$timeslot->get_max();

            //get seperate timeslots for 3 slots 
            $full_service_slots=$normal_service_slots=$body_wash_slots=array();

            //get durations for service types
            $full_service_duration=$service_type->get_duration_from_name('Full Service');
            $normal_service_duration=$service_type->get_duration_from_name('Normal Service');
            $body_wash_duration=$service_type->get_duration_from_name('Body Wash');

            //full service
            $curr=$min;
            while(strtotime($curr)<strtotime($max)){
                array_push($full_service_slots,$curr);
                $curr=$timeslot->add_slots($curr,$full_service_duration);
            }

            //normal service
            $curr=$min;
            while(strtotime($curr)<strtotime($max)){
                array_push($normal_service_slots,$curr);
                $curr=$timeslot->add_slots($curr,$normal_service_duration);
            }

            $curr=$min;
            while(strtotime($curr)<strtotime($max)){
                array_push($body_wash_slots,$curr);
                $curr=$timeslot->add_slots($curr,$body_wash_duration);
            }
            //echo($normal_service_duration);
            //array_push($a,"blue","yellow");
            //set variables
            Session::set('full_service_slots',$full_service_slots);
            Session::set('normal_service_slots',$normal_service_slots);
            Session::set('body_wash_slots',$body_wash_slots);

            //get dates for the coming week
            $tomorrow = date("Y-m-d", strtotime('tomorrow'));
            Session::set('coming_week',Time_func::week_generate($tomorrow));
        }
Enter fullscreen mode Exit fullscreen mode

Our project was on a car-service station which had platforms with different functionalities for different vehicles, so some had the ability to do Full-Service some didn't 😕 . Also these service types had different durations. Yes, practically an NP scheduler problem.

Now, After hours of scratching heads and slamming keyboards handling these on SQL got us queries like this:

SELECT timeslot_no
                    FROM time_slot
                    WHERE timeslot_no NOT IN (SELECT DISTINCT time_slot.timeslot_no
                    FROM time_slot,reservation_time_slot
                    WHERE time_slot.start_time>='$start_time' AND
                    time_slot.end_time<='$end_time' AND
                    time_slot.timeslot_no=reservation_time_slot.timeslot_no AND 
                    reservation_time_slot.date='$res_date') AND 
                    time_slot.start_time>='$start_time' AND
                    time_slot.end_time<='$end_time'
                    GROUP BY start_time;";
Enter fullscreen mode Exit fullscreen mode

Other stuff we managed to did:

Halfway through we realized that this is more of a learning project . So why not try to do everything on our own to see how they work out?

  • Hashing Algorithm? We have our own one 😏 (Credits to Minuri.) which randomizes byte by byte with an arbitrary number of cycles stored in a salt.
  • Did you know even though PHP and MYSQL are used in almost all legacy stacks for development, they don't share a mutual data type for time 😵, Remedy? Hundreds of lines of code on these :
function convert_to_12hour(time) {
  ...............
}

function date_validate(){
  ...............
}

//function to display date in needed format
function date_display(){
  .............
}

function addDays(date, days) {
  .........
}

//function to generate numerical values for upcoming week
function generate_week(days=7){
  ........

  return days;

}
Enter fullscreen mode Exit fullscreen mode
  • The only 2 libraries we used were the e-mail,SMS notifier and PDF generator. On a span of almost 5 working months with lectures alongside the 4 of us managed to hardcode every other aspect of it.

  • Other separate classes we implemented with modularity include:

Conclusion:

Is building a project of this scale a pain? Yes!
Is building a project without frameworks in this time a pain? ... Really Yes

But was all of this worth it? For me as a beginner developer YES ALL THE WAY!
Because :

iron man

Again a huge thanks to our lecturers, our supervisor and co-supervisor who guided us through and every one who helped! Please feel free to point out any issues in the repo and feedback.

The overall best experience gained: Working together as a team in the middle of a pandemic, in front of a computer screen 💻 going through an SDLC for the first time

And if you are an undergrad who is boarding the same boat and feeling miserable if you are limited by the technologies provided in the rubric well, you could build almost ANYTHING! and..
if you CAN build anything, you shouldn't worry about anything right? 😏
dream team

Discussion (4)

pic
Editor guide
Collapse
lakmal profile image
Dimuthu Lakmal

The project was a terror with fun. 🙂
Thanks for remind it once again.👻

Collapse
ov1n profile image
ov1n Author

true though, but "When only the going gets tough, the tough get going ":)

Collapse
udithaishan profile image
Uditha Ishan

Behind the scenes 🔥

Collapse
ov1n profile image