Pragmatic Programmer Slide

Pragmatic Programmer


What is difference between "programming" vs "Software Engineering"?
assets/Pasted image 20230131224607.png


Problem Solving

assets/Pasted image 20230131220834.png


"Fix" error, not "turn off" error notification

assets/Pasted image 20230131221557.png

Dive deep, analysis the problem
Pragmatic Programmer/start-with-why.png


Pragmatic Programmer/CN1BapPUYAEJPaL.png


Nature of Software Engineering

Create "value"

Challenge

always changes

requirements, technologies, knowledges, emotions :)

Consequences

"Cost" increased
resource cost, human cost


Target

Create "value" with minimal "cost"

Solution

Reduce the changing cost by making system

Easier to Change


How?

Best practices, coding principles, pattern design, testing, etc


Don't Repeat Yourself (DRY)

avoid

duplicated a piece of knowledge

and

duplicated code duplicated knowledge

def validate_age(value): 
	validate_type(value, :integer) 
	validate_min_integer(value, 0) 
def validate_quantity(value): 
	validate_type(value, :integer) 
	validate_min_integer(value, 0)

DRY

duplicated between document and code

# Calculate the fees for this account. 
# * Each returned check costs $20 
# * If the account is in overdraft for more than 3 days, 
# charge $10 for each day 
# * If the average account balance is greater that $2,000 
# reduce the fees by 50% 
def fees(a) 
	f = 0 
	if a.returned_check_count > 0 
		f += 20 * a.returned_check_count 
	end 
	if a.overdraft_days > 3 
		f += 10*a.overdraft_days 
	end 
	if a.average_balance > 2_000 
		f /= 2 
	end 
	f 
end

solution

change layout, better naming

def calculate_account_fees(account) 
	fees = 20 * account.returned_check_count 
	fees += 10 * account.overdraft_days if account.overdraft_days > 3 
	fees /= 2 if account.average_balance > 2_000 
	fees 
end

DRY Violation in Data

class Line 
{ 
	Point start; 
	Point end; 
	double length; 
};

assumpt: $length = start - end$

length information has two sources

sooner or later those source will be conflicted


Solution

using setter, getter

def getLength()
{
	return abs(start - end)
}
### another option ###
def calculateLength()
{
	length = abs( start - end)
}

def setStart(Point newStart)
{
	start = newStart
	calculateLength()
}

Use "value" to guide the choice of solution


Knowledges Synchronization

avoid

repeat work

Make it Easy to Reuse


Orthogonality

a single, well-defined responsibility

Benefit

change in one does not affect the others


How to implement?

modular, component-based, layers-based

well-defined responsibility

eliminate the redundant, small, easy to track

avoid

coupling

coupling is the degree of interdependence between modules (class, function, data, etc)


How to avoid coupling?

Testing

Testing is not about finding bugs

The first User of your code

It gives feedback about your implementation design

Test Early, Test Often, Test Automatically


Testing

class Database:
    def __init__(self):
        self.data = []

    def add_data(self, item):
        self.data.append(item)

    def get_data(self):
        return self.data

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def save(self):
        database = Database()
        database.add_data({"name": self.name, "age": self.age})

class TestUser(unittest.TestCase):
    def test_save(self):
        user = User("John", 30)
        user.save()

        database = Database()
        data = database.get_data()

        self.assertEqual(len(data), 1)
        self.assertEqual(data[0]["name"], "John")
        self.assertEqual(data[0]["age"], 30)


Not know where to start

Tracer Bullets
Pragmatic Programmer/tracer_bullets.png
Get feedback as soon as possible


Coding

Impossible Assumption

  • A month with fewer than 28 days
  • Error code from a system call: can’t access the current directory
  • In C++: a = 2; b = 3; but (a + b) does not equal 5
  • A triangle with an interior angle sum ≠ 180°
  • A minute that doesn’t have 60 seconds
  • (a + 1) <= a

Coding

Assertive Programming

put assert statement to check "impossible" state


Coding

Decoupling

Type of couplings:

  • Train wrecks
  • Globalization

Decoupling: Train wrecks

public void applyDiscount(customer, order_id, discount) 
{ 
	totals = customer.orders.find(order_id).getTotals(); 
	totals.grandTotal = totals.grandTotal - discount; 
	totals.discount = discount; 
}

5 abtraction levels: implicit knowledge

Client request: no order has discount more than 40%

where to change?


Decoupling: Train wrecks

Tell, Don’t Ask

should not make decisions based on the internal state of an object and then update that object

class Total
{
	public void applyDiscount(discount)
	{
		this.discount = discount;
		grandTotal -= this.discount;
	}
}

public void applyDiscount(customer, order_id, discount) 
{ 
	customer.orders.find(order_id).getTotals()
	.applyDiscount(discount);
}

Decoupling: Train wrecks

Tell, Don’t Ask

should not make decisions based on the internal state of an object and then update that object

class Total
{
	public void applyDiscount(discount)
	{
		this.discount = discount;
		grandTotal -= this.discount;
	}
}
class Order
{
	public void applyDiscount(discount)
	{
		getTotals().applyDiscount(discount);
	}
}

public void applyDiscount(customer, order_id, discount) 
{ 
	customer.orders.find(order_id).applyDiscount(discount);
}

Decoupling: Globalization

global data is available inside every method