82
Nicolas Perriault 30 Symfony Best Practices 30 Symfony Best Practices SymfonyDay ’09, Cologne, Germany September 4th, 2009

30 Symfony Best Practices

Embed Size (px)

DESCRIPTION

These are the slides of the talk I gave at Symfonyday Cologne '09 (http://www.symfonyday.com/)

Citation preview

Page 1: 30 Symfony Best Practices

Nicolas Perriault

30 Symfony Best Practices

30 Symfony Best Practices

SymfonyDay ’09, Cologne, GermanySeptember 4th, 2009

Page 2: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

Best Practices?A Best practice is a technique, method, process, activity, incentive or

reward that is believed to be more effective at delivering a particular outcome than any other technique, method, process, etc. The idea is that with proper processes, checks, and testing, a desired outcome

can be delivered with fewer problems and unforeseen complications. Best practices can also be defined as the most

efficient (least amount of effort) and effective (best results) way of accomplishing a task, based on repeatable procedures that have

proven themselves over time for large numbers of people.

-- Wikipedia, august 2009

2

Page 3: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

Best Practices?

Making. Stuff. Efficient.

3

Page 4: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

Best Practices?

• Moreover, best practices in software development and symfony are all about:

• improving communication between developers through standardization

• enhancing security, maintainability, portability and interoperability by increasing code quality

4

Page 5: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

Disclaimer• These best practices are not sorted by

importance, nor criticality

• All best practices listed here are debatable, at least because they’re based on my own experience

• There are always exceptions

• Some best practices are not symfony-specific ; “Zake Igniter” developers, you can take some notes too.

5

Page 6: 30 Symfony Best Practices

Nicolas Perriault

30 Symfony Best Practices

Let’s begin...

Page 7: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#0

• Always write “symfony” starting with a small cap.

7

Page 8: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#0

• Always write “symfony” starting with a small cap.

• Or maybe not (mostly depends on the result of rand(0, 1))

7

Page 9: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#1• Manage the View within the View

• View is intended to be handled in templates

• Try to avoid the use of the view.yml file

• Try to avoid handling the view from the controller (eeeek) or the model (you’re fired)

• Slots can help (a lot)

8

Page 10: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#1For example, handling <title> tag and assets:

Note: here the value of $defaultTitle could (should) be handled in an app.yml configuration file

9

Page 11: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#1

• Remember this: if you’re a graphic designer/integrator, you don’t want to deal with YAML or complex PHP code to manage the presentation

10

Page 12: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#2

• Always enable output escaping and CSRF protection

• starting with symfony 1.3, they’re enabled by default

11

Page 13: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

12

Page 14: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#3• Always call a redirect after posting data

• for security purpose

• for ergonomy

• to avoid duplicates in database

• don’t forget to add a flash message to the end user after every transaction made

13

Page 15: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

14

Page 16: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

15

Page 17: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#4• No Propel Criteria or Doctrine_Query

instances, SQL queries and any ORM/RDBMS specific calls should ever be found neither in the templates nor in the actions.

• The more you couple your model to your controllers and views, the more it’ll be hard to change your persistence backend or strategy.

16

Page 18: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

Doctrine_Collection

17

Page 19: 30 Symfony Best Practices

Nicolas Perriault

BETTER30 Symfony Best Practices

Array

18

Page 20: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

Array (ideally)

19

Page 21: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#5• Symfony core files should never be

modified to add or change the features they provide, but replaced through the autoloading mechanism, or way better: extended.

• Tweaking the factories.yml file and catching native symfony events can help a lot achieving this goal.

20

Page 22: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

Unused

21

Page 23: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

22

Page 24: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#6

• The templates must contain PHP alternative templating syntax, for readability and ease of use.

23

Page 25: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

24

Page 26: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

25

Page 27: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#7• Verify cache settings, especially that the

cache is actually enabled in prod environment. Don’t laugh, it happened quite a lot.

• If you use cache, create a staging environment to test the caching strategy if it doesn't exist.

• Better: avoid using cache. No kidding.

26

Page 28: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

27

Page 29: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#8

• Use routes instead of raw module/action couple in url_for(), link_to() and redirect() calls.

• Also, default routes should be deactivated by default (at least in apps which don’t run admin-generator 1.0 modules)

28

Page 30: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#9

• All code comments, phpdoc, INSTALL, CHANGELOG and README files, variables, functions, classes and methods names and more generally the developer documentation, should be written in English.

29

Page 31: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

30

Page 32: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

31

Page 33: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#10

• Catch and log exception messages, display human readable error messages to the end user

32

Page 34: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

33

Page 35: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

34

Page 36: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#11

• Only deploy production front controllers in production

35

Page 37: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

36

Page 38: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

37

Page 39: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#12

• Ideally:

• A typical controller method should never exceed ~30 lines.

• A typical controller class should never have more than ~15 action methods.

38

Page 40: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

x~2000 lines on this actions class (the slidescreen size was to short to list them all). Unmaintenable. 39

Page 41: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#13

• Always apply consistent coding standards.

• Always apply Symfony’s coding standards.http://trac.symfony-project.org/wiki/HowToContributeToSymfony#CodingStandards

40

Page 42: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

41

Page 43: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

42

Page 44: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#14

• Session persistence logic should reside in sfUser derived class methods, and only them.

43

Page 45: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

44

Page 46: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

45

Page 47: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#15

• Never serialize objects in the session

46

Page 48: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

47

Page 49: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

Note: of course, a setRecentlySeenProducts() method could have been implemented in the myUser class.

48

Page 50: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#16

• Always create customized 404 error and 500 error pages

49

Page 51: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

50

Page 52: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

51

Page 53: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#17• There should never be any direct use of

sfContext inside the Model layer (eg. sfContext::getInstance())

• Because the sfContext instance you get can differ a lot regarding the used env (cli, test, dev, prod...)

• It would make your code quite untestable

• Yes, it’s hard.

52

Page 54: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

53

Page 55: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

54

Page 56: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

55

Page 57: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

56

Page 58: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#18

• Avoid creating a big generic utility class with many static methods

• It's like reinventing procedural programming or using functions

• Write specialized classes

57

Page 59: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#19

• Use sfLogger for debugging instead of echoing variable or debug messages

• FirePHP(1) or FireSymfony(2) custom loggers can be more than helpful to debug your app (webservices for example)

(1) http://firephp.org/(2) http://firesymfony.org/

58

Page 60: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

The FireSymfony Firebug extension for Firefox in action

factories.yml

59

Page 61: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#20• If source code is managed through a SCM

tool, versioned files should NEVER contain passwords, local paths, etc.

• Files containing them should be added to the ignore directive

• Typical example: the databases.yml file

• Distribute platform-dependent configuration files

60

Page 62: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

61

Page 63: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

62

Page 64: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#21• Write unit and functional tests:

• Unit test your business logic (please don’t test symfony or Doctrine again, it’s already done)

• Functionally test the user interface when it’s important (eg. 404/403/401 HTTP codes, security and user authentication, transactions and forms, etc.)

63

Page 65: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#21Hint: you can write your own functional browser/

tester to avoid duplicate test code

64

Page 66: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#22

• Never use absolute paths in code, or at least put them in YAML configuration files.

• Make your symfony project portable: use dirname(__FILE__) to point at the symfony libs in the project configuration class.

• You can put symfony lib in a lib/vendor dir.

65

Page 67: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

66

Page 68: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

67

Page 69: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#23• Data objects should always be represented

by a slug in urls, not a primary key

• For security: numeric PKs are easily guessable, whereas slugs are not

• For URL usability and SEO: /article/symfony-rulez.html is sexier than /article/123.html

68

Page 70: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#24• Every application or project specific

configuration variable should be stored in its app.yml file

• You can share project-wide (cross-applications) settings by putting an app.yml file within the root config/ folder of the project

69

Page 71: 30 Symfony Best Practices

Nicolas Perriault

BAD30 Symfony Best Practices

70

Page 72: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

Default value

71

Page 73: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#25

• Avoid versioning any generated Base* class file, especially if you want to write reusable plugins or redistribute your work.

• Maybe people will want to extend or add behaviors to your model classes.

72

Page 74: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#26• Use symfony tasks system for CLI batch

scripts

• Tasks have access to all the symfony facilities

• Tasks are designed for the CLI

• Text output

• Pretty printing

73

Page 75: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#26

74

Page 76: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#27• Alter request and response

programmatically by using filters.

• You can use the request.filter_parameters and response.filter_content events too.

• Filters are easy to setup and to debug, whereas events are more clean and powerful. Matter of taste.

75

Page 77: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

76

Page 78: 30 Symfony Best Practices

Nicolas Perriault

GOOD30 Symfony Best Practices

77

Page 79: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#28

• Always write a README, an INSTALL and a CHANGELOG file at the root of the project (or the plugin). If open sourced, a LICENSE file is appreciated too.

• And please don’t release plugins under the terms of the GPL license. Symfony Plugin != Operating System

78

Page 80: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#29

• Share features and modules across applications by writing plugins

• If it’s really cool, release it publicly

79

Page 81: 30 Symfony Best Practices

30 Symfony Best Practices

Nicolas Perriault

#30

• Study other frameworks code!

• They might have good, even better ideas to solve the problem you have

• Even frameworks written in other languages than PHP (Django, Rails, Spring...)

80

Page 82: 30 Symfony Best Practices

Nicolas Perriault

30 Symfony Best Practices

Questions?

Nicolas [email protected]+33 660 920 867

prendreuncafe.com | symfonians.net | symfony-project.org