Set Up Your Home Defense Gun: Rifle, Shotgun & Pistol [GUIDE]

https://www.pewpewtactical.com/wp-content/uploads/2021/03/4.-Home-Defense-Glock-G19-Light-1024×744.jpg

Home defense is a hot topic in the firearms community, with newbies and seasoned pros debating the merits of different platforms.

But what should you consider when setting up a home defense or bedside gun?

Home Defense Glock G19 Light
What happens when things go bump in the night?

Well, I’m here to help. I’m going to try and dial in on some suggestions of things I would consider essential in home defense, as well as looking at the stats behind home invasions.

I will preface this by saying that everything contained in this article is meant as a general picture and in no way should be construed as an all-inclusive, gospel, or a cookie-cutter response to fit every person or scenario.

Vaultek MXi, Fully Loaded
Vaultek MXi

There are simply too many variables to account for in one article in dealing with a home defense scenario and what the correct tool for the job is.

But I’ve done my best to offer a broad perspective that should at least get you started. So keep reading to learn more!

Table of Contents

Loading…

Science of Home Defense

One of the common misconceptions in the firearms community is that we must prepare to fight off waves of invaders in a home defense situation.

Could that happen? Sure. Is it likely? Reading through recent home invasion stories reported to the police, no.

Probably not going to be fighting these off. (Photo: Rogue Pictures)

Local statistics in Las Vegas are that the likelihood is one or two (average was 1.5) persons will attempt to gain entry, though more are possibly outside in supporting roles.

This can vary from area to area, but lower-income locations typically see more burglaries and attempts.

Per the FBI’s Criminal Justice Information Services Division, a break-in occurs once every 26 seconds in the United States.

Home Defense Ominous Shadow
Ominous Shadow

Of those break-ins, 61% of offenders were unarmed at the time of the offense, and only 12% of all violent break-ins involved the offender having a firearm. Often, the offenders were known to the victims, and an assault occurred in only 5% of the break-ins reported.

So, what does all that have to do with setting up your home defense? First and foremost, the best deterrent you can have to prevent a home invasion is a security system — 83% of would-be burglars check for some sort of security system before breaking in.

Ring Security System
Ring Security System

If you choose to defend yourself, your home, and your family with a firearm, you need to understand that you may know the person attempting to break in, they may or may not be armed, and that the likelihood is that they want to get in and get out with cash or goods, not hurt you.

In short, make sure you understand your local laws VERY well.

What’s the Best Home Defense Tool?

This is a very complicated answer, and there isn’t a blanket “this works best for everyone” response.

Instead of going into a nuanced answer, I’m going to attempt to give some information that will highlight the strengths and weaknesses of different firearms for home defense.

Ultimately you will have to decide what will work best based on your level of familiarity and comfort with a particular platform, the layout of your house, availability of defensive ammo, and many other variables.

Why does the layout of your house matter? Defending a one-bedroom apartment will be a vastly different scenario than trying to defend a 10,000-square-foot ranch house on 27 acres of land.

The key here is realizing that you are legally responsible for everything a bullet does once it exits the muzzle of your firearm after being discharged.

Low Round Count Drill
You are responsible for every one of these that leaves the barrel…

Sending a round through a wall into your neighboring townhouse means you are responsible for any damages or injuries it causes. Different tools will excel in different environments, so figure out what will do the best for you.

Investing in some deterrents can often prevent the need to use force.

We already saw that potential burglars check for a security system, so that is the first thing you should be investing in. (Or take a look at our article on the Best Ways to Secure Your Home for more tips!)

Beyond that, what’s the next step to deterring a burglary without escalating to force? A good-quality handheld flashlight and properly using it.

Sean's EDC streamlight

Let’s face facts; if something goes bump in the night, most of the time, there isn’t a need to point a gun at it.

The use of a flashlight to investigate what is skulking around your property allows you to make an informed decision on whether the use of force is necessary or if you simply caught your teenage kid sneaking back into the house.

A little light goes a long way.

If you spot a would-be burglar, the threat of being caught and detained statistically shows they are less likely to stay.

In that 5% of break-ins that turn into an assault, however, use of force may be needed, and that is where other tools are more suitable for the job.

Hands & Home Defense

I’m not getting into a debate over semi-automatic vs. revolver or a debate on which caliber is the best.

The correct answer is finding a gun that you will train to become more proficient with, that can add the features you work best with, and ensure you are confident in its use.

If you can wield a revolver well, then rock on, my friends.

I will not recommend a .22 LR as a defensive handgun, but if that is all you have, you better make it work for you.

Generally, any caliber from .380 and up that offers hollow-point rounds can be suitable for a defensive gun. Each caliber will have some advantages and disadvantages.

Popular Pistol Calibers
Popular Pistol Calibers

Quality matters for defensive guns. Right now, finding quality guns can be both difficult and expensive, but you have to ask yourself what your life is worth.

Stick to brands with proven track records of success and quality like Glock, CZ, H&K, Smith & Wesson, Sig Sauer, FN, etc.

FN 509

Set your gun up for dominance and success.

Let’s face it, in the middle of the night; you should have the advantage in your home over a stranger. You know the layout better, you know where obstacles typically are, and you are just generally more familiar. Why not press that advantage with your firearm?

Floor Plan
You know the layout better than they do.

If you find yourself in a dark house trying to defend yourself, getting positive target identification and getting sights on target are the two things with which you need to be concerned — speaking in terms of operating the gun itself, not considering things like finding and using cover, etc.

To this end, I do recommend a weapon-mounted light of good quality — Streamlight, Surefire, Modlite, etc.

1911s with Lights & Lasers
1911s with Lights & Lasers

Additionally, I am a huge advocate for adding an optic to your pistol. Optics allow you to be threat-focused, rather than requiring you to switch to sight focus beyond a certain distance.

Best Pistol Red Dot
469

at Brownells

Prices accurate at time of writing

Prices accurate at time of writing

Available Coupons
  • 25% off all OAKLEY productsOAKLEY25

Optics allow you to acquire your aiming device regardless of lighting conditions and permit faster follow-up shots with more consistency, regardless of shooting experience.

Bunch of Micro Guns and Red Dots
Bunch of Micro Guns and Red Dots

Can’t night sights/fiber optic sights do the same thing? Yes and no. They will allow you to find your sights faster, but you are still limited by lighting conditions to get sights on target, and iron sights still require sight focus vs. being target focused.

The last component is ammo. Find good quality, consistent hollow points that will get the job done.

Popular 9mm Ammo
Popular 9mm Ammo

Examples of this would include but are not limited to Speer Gold Dot, Hornady Critical Duty, or Federal HST for larger handguns like the Glock G17 and G19.

For shorter barreled guns like Glock G43x, S&W Shield, or Sig P365, Hornady Critical Defense or Federal Punch are better options.

22

at Brownells

Prices accurate at time of writing

Prices accurate at time of writing

Available Coupons
  • 25% off all OAKLEY productsOAKLEY25

Speaking with Chuck Haggard of Agile/Training & Consulting, he mentioned that shorter barreled handguns lead to the round not fully expanding on some of the duty grade hollow points.

His testing and experience showed that Critical Defense was a much better choice in that scenario.

Glock G43X
Glock G43X

Make sure your gun is rated for any +P or +P+ ammo you intend to shoot, and then shoot a magazine worth through your gun to make sure it cycles without any issue.

Pistols do have their limits, and you need to know them.

Depending on the handgun you’ve selected, you will have between six and 17 rounds to use for your defense without reloading.

Shield vs Stock Glock 43x Mag
Shield vs Stock Glock 43x Mag

Looking back at the average number of attackers, that is between three and eight shots at each adversary.

Add in adrenaline and the high stress of the situation, and you now have a scenario where you are likely reverting to your lowest proficiency and training to put hits on target.

Rifles for Home Defense

Many, myself included, choose to use a rifle or pistol version of a rifle for home defense.

Rifles offer a more stable, more forgiving firing platform than handguns due to the increased points of body contact with the gun.

Ruger PCC shooting standing

Additionally, they typically offer more ammunition to feed and, in most cases, provide increased velocity over handguns.

So, when will a rifle be an advantage over a handgun? If your house is laid out in such a manner that you can create distance, a rifle is going to generally be better than a handgun.

I want to clarify this in that shot placement matters; either way, people can generally fire a rifle better than a handgun at low skill levels. At 15 to 20 yards, both can be effective; it will come down to training and comfort.

Aero AR-15 10.5" Pistol
Aero AR-15 10.5″ Pistol

In my case, my entire family is housed on the second floor of our home. I can then use a rifle to defend against people coming upstairs and know that it will be effective.

Much like handguns, some definite upgrades are recommended.

Just like with handguns, a rifle will benefit from a weapon-mounted light. Target identification is still a priority, even more so at greater distances.

Cloud Defensive OWL, light on
Cloud Defensive OWL

Some form of quality optic is needed as well. I prefer red dots that I can leave on like an Aimpoint CompM5 or T2 so that my gun is ready when I pick it up. I know others that run low-power variable scopes and are very effective.

789

at Brownells

Prices accurate at time of writing

Prices accurate at time of writing

Available Coupons
  • 25% off all OAKLEY productsOAKLEY25

I would avoid using just iron sights, as you still suffer the same limitations as handgun sights. Invest in a quality optic, stay away from knocks-offs and low-quality products, and prosper.

Faxon Firearms Ascent AR Pistol
Faxon Firearms Ascent

Lastly, a sling is a must-have for a defensive rifle. This allows the user to retain possession of the weapon if hand to hand occurs and allows for retention of the rifle if you need your hands free to pick something or someone up to help.

55

at Shall Not Comply

Prices accurate at time of writing

Prices accurate at time of writing

Available Coupons
  • 25% off all OAKLEY productsOAKLEY25

Rifles are not without their drawbacks, though. That sling that I just mentioned means that the gun is attached to you to some extent. A knowledgeable attacker can use that as leverage against you to control your body and/or throw you.

Pew Pew Tactical Sling Padding
Pew Pew Tactical Sling

In closer quarters or houses with lots of turns, a longer barrel can be a hindrance in terms of maneuverability.

Ammo selection, along with good shot placement, also plays a huge role in the effectiveness of a rifle. Once again, something like Speer Gold Dot, Federal LE Tactical, or Hornady TAP FDP that are made to have a hollow or soft point allow for better defensive use than a full metal jacket round.  

TAP and other fragmenting rounds are especially worth considering if over-penetration is a concern in smaller living spaces. Please understand that fragmenting rounds are different than frangible rounds, and under no circumstances are frangible rounds a go-to for personal protection.

Going back to our average number of people in the break-in, rifles offer more rounds to put on target.

An AR-15 magazine comes in 10-round, 20-round, and 30-round magazines as the most common options. You can get larger capacity drum magazines, but many tend to be lower quality, finicky, and not reliable to consider for a self-defense scenario.

Aero Precision Thunder Ranch TR15 AR Mags
All the mags

As I mentioned above, it may take more than one round to stop someone from attacking you, so having more ammunition to expend in that pursuit is a good thing.

Shotgun Setups for Home Defense

Shotguns for home defense use have become a more heated topic in the last few years.

Search any gun forum or message board, and you’ll encounter people saying…shotguns are the best defensive gun ever, you just need to rack the action to scare away every bad guy in a 3-mile radius, you don’t have to aim, etc.

Streamlight Universal Shotgun Light Cordage Pump Action

The truth is that shotguns have their place in home defense, but like anything else, they aren’t a blanket answer to a problem. Sometimes shotguns will be the optimal choice and other times they won’t.

The first thing to consider is the gun itself…

Remington 870 with Streamlight
Remington 870 with Streamlight

Remington 870s or Mossberg 590s are the go-to pump-action shotguns.

If semi-automatic shotguns are more your thing, the Beretta 1301, Benelli M2 or M4, and the Mossberg 940 will do.

Best High-End Semi-Auto
1799

at Palmetto State Armory

Prices accurate at time of writing

Prices accurate at time of writing

Available Coupons
  • 25% off all OAKLEY productsOAKLEY25

Once you have a good-quality, reliable shotgun, the next step is patterning your ammo.

This involves getting the ammo you intend to use and shooting it at various distances to see how the pellets spread and pattern on a target. 

Shotgun Battle Belt 2
Practicing at the range with your ammo will give you a good idea of how it flies

This is important, as using different types of buckshot with different guns will get you different results. As you are responsible for everything your ammo does after it is fired, you need to know exactly where these pellets will fly, where they end up, and if you will face any unintended damage.

There are two viable shotgun rounds for defense, buckshot, and slugs. Birdshot and snakeshot are not suitable for self-defense, and their use could leave you facing an angry opponent that is still able to function.

12ga Birdshot, Opened
12ga Birdshot, Opened

Buckshot utilizes larger pellets that are ideally suited for home defense, but not all of them pattern the same. Depending on your barrel and if you are running a choke or not, Federal Flight Control may be an option, and generally, 8-pellet buckshot is going to be superior to 9-pellet.

Federal FliteControl shell, dissected 2
Federal FliteControl shell, dissected 2

Slugs are your other option for self-defense. Slugs utilize a solid projectile instead of pellets and were originally designed for use on larger game.

Think of firing a softball instead of marbles. Slugs will be a better choice for defensive rounds at longer distances, as buckshot patterns will spread out more there. Inside of 10 yards, though, buckshot will be better.

12ga Slug, Opened
12ga Slug, Opened

Distance is generally going to be the enemy of a shotgun beyond 30 yards or so. Inside of that range, a shotgun is a devastating tool that will very quickly end engagements.

Contrary to popular myth, you still have to aim a shotgun for it to be effective. To that end, a good quality light for target identification is worth considering. As with other platforms, mounting an optic is not a bad idea.

Blue Force Gear Vickers Sling
Blue Force Gear Vickers Sling

Additionally, a sling is a great idea for the same reason discussed earlier. Also, keep in mind that a shotgun will generally be longer and often heavier than an AR-15 or AK-47.

Shotguns do have their drawbacks, though. Like rifles, movement and mobility can be hindered by the size of the gun.

Additionally, recoil mitigation for follow-up shots is something that must be trained, as some people will find the gun awkward and uncomfortable without adjustments made.

Mossberg Retrograde 590A1 Shooting Front
Mossberg Retrograde 590A1

Reloading a shotgun is also a bit more involved than slapping a fresh magazine in, so it is a skill that must be trained to be fast and proficient at it.

Applying shotguns to our two-attacker scenario, this is where things are very different.

Depending on which shotgun model you have, the tube may hold between six and eight rounds without extended tubes.

shotgun speed reload keanu

While this leaves only three or four rounds per assailant within a shotgun’s effective range, one round delivered to an attacker is devastating. The shot must still hit, but if it does, there is a very high probability that the fight is now over and your opponent’s behavior has changed.

Final Thoughts

No two scenarios are the same, and thus no answer will fit universally. Find the self-defense setup that makes sense for you, train with the tools and understand the tactics needed to win the fight.

Home Defense Glock G19 at Door

Also, source out quality information, and do not be afraid to challenge the misconceptions you might have or might have heard.

In the end, defending yourself and those you care about is the only thing that matters, so give yourself as much advantage as possible.

The post Set Up Your Home Defense Gun: Rifle, Shotgun & Pistol [GUIDE] appeared first on Pew Pew Tactical.

Pew Pew Tactical

Percona Platform First Steps

https://www.percona.com/blog/wp-content/uploads/2022/05/Percona-Platform.pngPercona Platform

I am a big fan of Percona Monitoring and Management (PMM) and am happy to report that setting up Percona Platform is as easy to set up and offers a lot of value. Percona Platform reached GA status recently and I think you will find it a handy addition to your infrastructure.

What is Percona Platform?

Percona Platform brings together enterprise-level distributions of MySQL, PostgreSQL, and MongoDB plus it includes a range of open source tools for data backup, availability, and management. The core is PMM which provides database management, monitoring, and automated insights, making it easier to manage database deployments. The number of sites with more than 100 separate databases has grown rapidly in the past few years.  Being able to have command and control of that many instances from a CLI has become impossible. Businesses need to move faster in increasingly complex environments which puts ever-increasing pressure on database administrators, developers, and everyone involved in database operations. The spiraling levels of demand make it harder to support, manage, and correct issues in database environments.

What Percona Platform provides is a unified view of the health of your entire database environment to quickly visually identify and remediate issues.  Developers can now self-service many of their database demands quickly and efficiently so they can easily provision and manage databases on a self-service basis across test and production instances. So you spend fewer resources and time on the management of database complexity.

The two keys to Percona Platform are Query Analytics (QAN), which provides granular insights into database behavior and helps uncover new database performance patterns for in-depth troubleshooting and performance optimization, and Percona Advisors, which are automated insights, created by Percona Experts to identify important issues for remediation such as security vulnerabilities, misconfigurations, performance problems, policy compliance, and database design issues. Automated insights within Percona Monitoring and Management ensure your database performs at its best. The Advisors check for replication inconsistencies, durability issues, password-less users, insecure connections, unstable OS configuration, and search for available performance improvements among other functions. 

Percona Platform is a point of control for your database infrastructure and augments PMM to be even more intelligent when connected to the Percona Platform. By connecting PMM with the Percona Platform, you get more advanced Advisors, centralized user account management, access to support tickets, private Database as a Service, Percona Expertise with the fastest SLAs, and more.

Percona Platform architecture

So How Do I Install Percona Platform?

The first step is to install PMM by following the Quick Start Guide. You need version 2.2.7 or later.

Second, You will need a Percona Account.

Third, you will need to connect that account to PMM.

I will assume that you will already have PMM installed.  Did I mention that PMM is free, open source software?

Percona Platform account signup

The signup form allows you to create a new account or use an existing account.

Now you can create a name for your organization.

Form for creating your organization and connecting PMM

After creating your username and password, create your organization

Now login to your PMM dashboard and select the Settings / Percona Platform.  You will need to get your ‘Public Address’ which the browser can populate the value for you if need be.

The PMM Server ID is automatically generated by PMM.  You will need to provide a name for your server, and you will need a second browser window to login into Percona Platform to get the Percona Platform Access Token (this token has a thirty-minute lifetime, so be quick or regenerate another token).

Go back into PMM, paste the Access Token into the Percona Platform Access Token field, and click Connect.

On the Percona Platform page, you will see your PMM instances. Congratulations, you are using Percona Platform!

Advisor Checks

All checks are hosted on Percona Platform. PMM Server automatically downloads them from here when the Advisors and Telemetry options are enabled in PMM under Configuration > Settings > Advanced Settings. Both options are enabled by default.

Depending on the entitlements available for your Percona Account, the set of advisor checks that PMM can download from Percona Platform differ in terms of complexity and functionality.

If your PMM instance is not connected to Percona Platform, PMM can only download the basic set of Anonymous advisor checks. As soon as you connect your PMM instance to Percona Platform, has access to additional checks, available only for Registered PMM instances.

If you are a Percona customer with a Percona Customer Portal account, you also get access to Paid checks, which offer more advanced database health information. A list is provided below.

Check Name Description Tier
MongoDB Active vs Available Connections Checks the ratio between Active and Available connections. Registered, Paid
MongoDB Authentication Warns if MongoDB authentication is disabled. Anonymous, Registered, Paid
MongoDB Security AuthMech Warns if MongoDB is not using the default SHA-256 hashing as SCRAM authentication method. Paid
MongoDB IP Bindings Warns if MongoDB network binding is not set as recommended. Anonymous, Registered, Paid
MongoDB CVE Version Shows an error if MongoDB or Percona Server for MongoDB version is not the latest one with CVE fixes. Anonymous, Registered, Paid
MongoDB Journal Check Warns if journal is disabled. Registered, Paid
MongoDB Localhost Authentication Bypass is Enabled Warns if MongoDB localhost bypass is enabled. Anonymous, Registered, Paid
MongoDB Non-Default Log Level Warns if MongoDB is not using the default log level. Paid
MongoDB Profiling Level Warns when the MongoDB profile level is set to collect data for all operations. Registered, Paid
MongoDB Read Tickets Warns if MongoDB is using more than 128 read tickets. Paid
MongoDB Replica Set Topology Warns if the Replica Set cluster has less than three members. Registered, Paid
MongoDB Version Warns if MongoDB or Percona Server for MongoDB version is not the latest one. Anonymous, Registered, Paid
MongoDB Write Tickets Warns if MongoDB network is using more than 128 write tickets. Paid
Check if Binaries are 32-bits Notifies if version_compatible_machine equals i686. Anonymous, Registered, Paid
MySQL Automatic User Expired Password Notifies if version_compatible_machine equals i686. Registered, Paid
MySQL InnoDB flush method and File Format check Checks the following settings: innodb_file_formatinnodb_file_format_maxinnodb_flush_method and innodb_data_file_path Registered, Paid
MySQL Checks based on values of MySQL configuration variables Checks the following settings: innodb_file_format,innodb_file_format_max,innodb_flush_method and innodb_data_file_path. Paid
MySQL Binary Logs checks, Local infile and SQL Mode checks Warns about non-optimal settings for Binary Log, Local Infile and SQL mode. Registered, Paid
MySQL Configuration Check Warns if parameters are not following Percona best practices, for infile, replication threads, and replica checksum. Paid
MySQL Users With Granted Public Networks Access Notifies about MySQL accounts allowed to be connected from public networks. Registered, Paid
MySQL User Check Runs a high-level check on user setup Registered, Paid
MySQL Advanced User Check Runs a detailed check on user setup Paid
MySQL Security Check Runs a detailed check on user setup Paid
MySQL Test Database This check returns a notice if there is a database with name ‘test’ or ‘test_%’. Registered, Paid
MySQL Version Warns if MySQL, Percona Server for MySQL, or MariaDB version is not the latest one. Anonymous, Registered, Paid
PostgreSQL Archiver is Failing Verifies if the archiver has failed. Paid
PostgreSQL Cache Hit Ratio Checks database hit ratio and complains when this is too low. Paid
PostgreSQL Configuration Change Requires Restart/Reload Warns when a configuration was changed and requires a server restart/reload Registered, Paid
PostgreSQL fsync is Disabled Shows an error if the fsync configuration is disabled, as this can result in unrecoverable data corruption. Anonymous, Registered, Paid
PostgreSQL Autovacuum Logging Is Disabled Shows an error if the fsync configuration is disabled, as this can result in unrecoverable data corruption. Paid
PostgreSQL Checkpoints Logging Is Disabled Notifies if the log_checkpoints configuration option is not enabled. Paid
PostgreSQL Max_connections is too high Notifies if the max_connections setting is set above 300. Anonymous, Registered, Paid
PostgreSQL Stale Replication Slot Warns for stale replication slots since these can lead to WAL file accumulation and DB server outage. Paid
PostgreSQL Super Role Notifies if there are users with superuser privileges. Anonymous, Registered, Paid
PostgreSQL Version Check Warns if the PostgreSQL minor or major versions are not the latest, and shows an error if the major version is 9.4 or older. Anonymous, Registered, Paid

More Advisors will be added and Perona always welcomes contributions. Check out Percona Platform today!

 

Percona Database Performance Blog

MySQL Partitioned Tables

MySQL Partitioned Tables

Learning Outcomes

  • Learn about List Partitioning.
  • Learn about Range Partitioning.
  • Learn about Columns Partitioning.
  • Learn about Hash Partitioning.
  • Learn about Key Partitioning.
  • Learn about Subpartitioning.

Lesson Material

MySQL supports partitioning of tables. It supports range, list, hash, and key partitioning. Range partitioning lets you partition based on column values that fall within given ranges. List partitioning lets you partition based on columns matching one of a set of discrete values. Hash partitioning lets you partition based on the return value from a user-defined expression (the result from a stored SQL/PSM function). Key partitioning performs like hash partitioning, but it lets a user select one or more columns from the set of columns in a table; a hash manages the selection process for you. A hash is a method of organizing keys to types of data, and hashes speed access to read and change data in tables.

Each of the following subsections discusses one of the supported forms of partitioning in MySQL. Naturally, there are differences between other databases and MySQL’s implementation.

List Partitioning

A MySQL list partition works by identifying a column that contains an integer value, the franchise_number in the following example. Partitioning clauses follow the list of columns and constraints and require a partitioning key to be in the primary key or indexed.

The following list partition works with literal numeric values. MySQL uses the IN keyword for list partitions. Note that there’s no primary key designated and an index is on the auto-incrementing surrogate key column. A complete example is provided to avoid confusion on how to index the partitioning key:

CREATE TABLE franchise
( franchise_id     INT UNSIGNED AUTO_INCREMENT
, franchise_number INT UNSIGNED
, franchise_name   VARCHAR(20)
, city             VARCHAR(20)
, state            VARCHAR(20)
, index idx (franchise_id))
PARTITION BY LIST(franchise_number)
( PARTITION offshore VALUES IN (49,50)
, PARTITION west VALUES IN (34,45,48)
, PARTITION desert VALUES IN (46,47)
, PARTITION rockies VALUES IN (38,41,42,44));

The inclusion of a PRIMARY KEY constraint on the franchise_id column would trigger an ERROR 1503 when the partitioning key isn’t the primary key. The reason for the error message is that a primary key implicitly creates a unique index, and that index would conflict with the partitioning by list instruction. The use of a non-unique idx index on the franchise_id column is required when you want to partition on a non-primary key column.

Range Partitioning

Range partitioning works only with an integer value or an expression that resolves to an integer against the primary key column. The limitation of the integer drives the necessity of choosing an integer column for range partitioning. You can’t define a range-partitioned table with a PRIMARY KEY constraint unless the primary key becomes your partitioning key, like
the one below.

CREATE TABLE ordering
( ordering_id     INT UNSIGNED AUTO_INCREMENT
, item_id         INT UNSIGNED
, rental_amount   DECIMAL(15,2)
, rental_date     DATE
, index idx (ordering_id))
PARTITION BY RANGE(item_id)
( PARTITION jan2011 VALUES LESS THAN (10000) , PARTITION feb2011 VALUES LESS THAN (20000) , PARTITION mar2011 VALUES LESS THAN (30000));

Range partitioning is best suited to large tables that you want to break into smaller pieces based on the integer column. You can also use stored functions that return integers as the partitioning key instead of the numeric literals shown. Few other options are available in MySQL.

Columns Partitioning

Columns partitioning is a new variant of range and list partitioning. It is included in MySQL 5.5 and forward. Both range and list partitioning work on an integer-based column (using TINYINT, SMALLINT, MEDIUMINT, INT [alias INTEGER], and BIGINT). Columns partitioning extends those models by expanding the possible data types for the partitioning column to include CHAR, VARCHAR, BINARY, and VARBINARY string data types, and DATE, DATETIME, or TIMESTAMP data types. You still can’t use other number data types such as DECIMAL and FLOAT. The TIMESTAMP data type is also available only in range partitions with the caveat that you use a UNIX_TIMESTAMP function, according to MySQL Bug 42849.

Hash Partitioning

Hash partitions ensure an even distribution of rows across a predetermined number of partitions. It is probably the easiest way to partition a table quickly to test the result of partitioning on a large table. You should base hash partitions on a surrogate or natural primary key.

The following provides a modified example of the ordering table:

CREATE TABLE ordering
( ordering_id       INT UNSIGNED PRIMARY KEY AUTO_INCREMENT
, item_id           INT UNSIGNED
, rental_amount     DECIMAL(15,2)
, rental_date       DATE)
PARTITION BY HASH(ordering_id) PARTITIONS 8;

This is the partitioning type that benefits from a PRIMARY KEY constraint because it automatically creates a unique index that can be used by the hash. A non-unique index such as the list partitioning example doesn’t work for a hash partition.

Key Partitioning

Key partitioning is valuable because you can partition on columns that aren’t integers. It performs along the line of hash partitioning, except the MySQL Server uses its own hashing expression.

CREATE TABLE orders_list
( order_list_id     INT UNSIGNED AUTO_INCREMENT
, customer_surname  VARCHAR(30)
, store_id          INT UNSIGNED
, salesperson_id    INT UNSIGNED
, order_date        DATE
, index idx (order_list_id))
PARTITION BY KEY (order_date) PARTITIONS 8;

This is the only alternative when you want to partition by date ranges. Like the hash partition, it’s easy to deploy. The only consideration is the number of slices that you want to make of the data in the table.

Subpartitioning

The concept of subpartitioning is also known as composite partitioning. You can subpartition range or list partitions with a hash, linear hash, or linear key.

A slight change to the previously created ordering table is required to demonstrate composite partitioning: we’ll add a store_id column to the table definition. The following is an example of a range partition subpartitioned by a hash:

CREATE TABLE ordering
INT UNSIGNED
INT UNSIGNED
DATE
 ( ordering_id     INT UNSIGNED AUTO_INCREMENT
, item_id          INT UNSIGNED
, store_id         INT UNSIGNED
, rental_amount    DECIMAL(15,2)
, rental_date      DATE
, index idx (ordering_id))
PARTITION BY RANGE(item_id)
  SUBPARTITION BY HASH(store_id) SUBPARTITIONS 4
( PARTITION jan2011 VALUES LESS THAN (10000)
, PARTITION feb2011 VALUES LESS THAN (20000)
, PARTITION mar2011 VALUES LESS THAN (30000));

Composite partitioning is non-trivial and might require some experimentation to achieve optimal results. Plan on making a few tests of different scenarios before you deploy a solution.

Planet MySQL

Matthew Wright: An introduction to accessing financial data in EDGAR, using Python

Some sources of financial data can be expensive or difficult to find. For example, some is only available from exchanges or vendors who charge a hefty fee for access. However, the financial industry is also heavily regulated, and one of its main regulators provides free access to its data. The (U.S. Securities and Exchange Commission)[https://www.sec.gov] … Continue reading An introduction to accessing financial data in EDGAR, using Python

The post An introduction to accessing financial data in EDGAR, using Python appeared first on wrighters.io.

Planet Python

Accurate Stormtroopers

https://theawesomer.com/photos/2022/05/accurate_stormtroopers_t.jpg

Accurate Stormtroopers

Link

(PG-13: Gore) As Star Wars fans know, stormtroopers have a long history of missing their targets. Corridor imagines how differently things might have turned out if the Empire’s plastic-armored troops just a bit more practice. Bonus VFX points for Han Solo’s mustache.

The Awesomer

Archaeologists Have Just Discovered CONCLUSIVE PROOF Of The Bible: A Rock In The Red Sea That Says ‘Moses Wuz Here’

https://media.babylonbee.com/articles/article-11387-1.jpg

CAIRO—Nautical archaeologists have at last discovered the exact location of where the Israelites crossed the Red Sea, having found a rock reading “Moses Wuz Here”.

“It seems a bit juvenile, but the evidence is unmistakable,” said archaeologist Benjamin Ioset. “We found it right next to several Egyptian chariots, along with another rock that said ‘Here The Lord Pwned Pharoah’.”

The revelation has lead to a cascade of breakthroughs in tracing the exodus route of ancient Israel. “With this rock in our possession, experts can now match the handwriting to other markers in the desert and we can follow the steps of Moses,” said Mr. Ioset. “For example, we have already discovered a match at the site of Israel’s battle with the Amalekites, where Moses had to keep his staff raised above his head for several hours. There is a small inscription which simply reads ‘Arm Day FTW!’. We also have found in Ancient Midian, where Moses met his wife, an inscription in a cave reading ‘Moses+Zipporah 4Eva’. We really hit the jackpot here!”

Scholars had hoped that this would lead to finally discovering the famed Ark Of The Covenant. Sources say that an archaeology team reportedly found what they believed may be the Ark, but they accidentally touched it and no one’s heard from them since.

At publishing time, experts discovered Moses’ handwriting also displayed a startling similarity to the writing of Mr. Charlton Heston.

Checkmate, atheists!


In the social justice system, words are considered violence. In New York City, the dedicated detectives who investigate these vicious attacks are members of an elite squad known as the Microaggression Victims Unit. These are their stories.

Subscribe to The Babylon Bee on YouTube

The Babylon Bee

Restructuring a Laravel Controller using Services, Events, Jobs, Actions, and more

https://laravelnews.imgix.net/images/controller-refactor.jpg?ixlib=php-3.3.1

One of the top Laravel questions I hear is “How to structure the project”. If we narrow it down, the largest part of it sounds like “If the logic shouldn’t be in Controllers, then where should we put it?”

The problem is there is no single correct answer to such questions. Laravel gives you the flexibility to choose the structure yourself, which is both a blessing and a curse. You won’t find any recommendations in the official Laravel docs, so let’s try to discuss various options, based on one specific example.

Notice: as there’s no one way to structure the project, this article will be full of side-notes, “what if” and similar paragraphs. I advise you don’t skip them, and read the article in full, to be aware of all the exceptions to the best practices.

Imagine you have a Controller method for registering users that does a lot of things:

1public function store(Request $request)

2{

3 // 1. Validation

4 $request->validate([

5 'name' => ['required', 'string', 'max:255'],

6 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],

7 'password' => ['required', 'confirmed', Rules\Password::defaults()],

8 ]);

9 

10 // 2. Create user

11 $user = User::create([

12 'name' => $request->name,

13 'email' => $request->email,

14 'password' => Hash::make($request->password),

15 ]);

16 

17 // 3. Upload the avatar file and update the user

18 if ($request->hasFile('avatar')) {

19 $avatar = $request->file('avatar')->store('avatars');

20 $user->update(['avatar' => $avatar]);

21 }

22 

23 // 4. Login

24 Auth::login($user);

25 

26 // 5. Generate a personal voucher

27 $voucher = Voucher::create([

28 'code' => Str::random(8),

29 'discount_percent' => 10,

30 'user_id' => $user->id

31 ]);

32 

33 // 6. Send that voucher with a welcome email

34 $user->notify(new NewUserWelcomeNotification($voucher->code));

35 

36 // 7. Notify administrators about the new user

37 foreach (config('app.admin_emails') as $adminEmail) {

38 Notification::route('mail', $adminEmail)

39 ->notify(new NewUserAdminNotification($user));

40 }

41 

42 return redirect()->route('dashboard');

43}

Seven things, to be precise. You will all probably agree that it’s too much for one controller method, we need to separate the logic and move the parts somewhere. But where exactly?

  • Services?
  • Jobs?
  • Events/listeners?
  • Action classes?
  • Something else?

The trickiest part is that all of the above would be the correct answers. That’s probably the main message you should take home from this article. I will emphasize it for you, in bold and caps.

YOU ARE FREE TO STRUCTURE YOUR PROJECT HOWEVER YOU WANT.

There, I said it. In other words, if you see some structure recommended somewhere, it doesn’t mean that you have to jump and apply it everywhere. The choice is always yours. You need to choose the structure that would be comfortable for yourself and your future team to maintain the code later.

With that, I probably could even end the article right now. But you probably want some “meat”, right? Ok, fine, let’s play around with the code above.


General Refactoring Strategy

First, a “disclaimer”, so it would be clear what we’re doing here, and why. Our general goal is to make the Controller method shorter, so it wouldn’t contain any logic.

Controller methods need to do three things:

  • Accept the parameters from routes or other inputs
  • Call some logic classes/methods, passing those parameters
  • Return the result: view, redirect, JSON return, etc.

So, controllers are calling the methods, not implementing the logic inside the controller itself.

Also, keep in mind, that my suggested changes are only ONE way of doing it, there are dozens of other ways which would also work. I will just provide you with my suggestions, from personal experience.


1. Validation: Form Request classes

It’s a personal preference, but I like to keep the validation rules separately, and Laravel has a great solution for it: Form Requests

So, we generate:

1php artisan make:request StoreUserRequest

We move our validation rules from the controller to that class. Also, we need to add the Password class on top and change the authorize() method to return true:

1use Illuminate\Validation\Rules\Password;

2 

3class StoreUserRequest extends FormRequest

4{

5 public function authorize()

6 {

7 return true;

8 }

9 

10 public function rules()

11 {

12 return [

13 'name' => ['required', 'string', 'max:255'],

14 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],

15 'password' => ['required', 'confirmed', Password::defaults()],

16 ];

17 }

18}

Finally, in our Controller method, we replace Request $request with StoreUserRequest $request and remove the validation logic from the Controller:

1use App\Http\Requests\StoreUserRequest;

2 

3class RegisteredUserController extends Controller

4{

5 public function store(StoreUserRequest $request)

6 {

7 // No $request->validate needed here

8 

9 // Create user

10 $user = User::create([...]) // ...

11 }

12}

Ok, the first shortening of the controller is done. Let’s move on.


2. Create User: Service Class

Next, we need to create a user and upload the avatar for them:

1// Create user

2$user = User::create([

3 'name' => $request->name,

4 'email' => $request->email,

5 'password' => Hash::make($request->password),

6]);

7 

8// Avatar upload and update user

9if ($request->hasFile('avatar')) {

10 $avatar = $request->file('avatar')->store('avatars');

11 $user->update(['avatar' => $avatar]);

12}

If we follow the recommendations, that logic should not be in a Controller. Controllers shouldn’t know anything about the DB structure of the user, or where to store the avatars. It just needs to call some class method that would take care of everything.

A pretty common place to put such logic is to create a separate PHP Class around one Model’s operations. It is called a Service class, but that’s just a “fancy” official name for a PHP class that “provides a service” for the Controller.

That’s why there’s no command like php artisan make:service because it’s just a PHP class, with whatever structure you want, so you can create it manually within your IDE, in whatever folder you want.

Typically, Services are created when there are more than one method around the same entity or model. So, by creating a UserService here, we assume there will be more methods here in the future, not just to create the user.

Also, Services typically have methods that return something (so, “provides the service”). In comparison, Actions or Jobs are called typically without expecting anything back.

In my case, I will create the app/Services/UserService.php class, with one method, for now.

1namespace App\Services;

2 

3use App\Models\User;

4use Illuminate\Http\Request;

5use Illuminate\Support\Facades\Hash;

6 

7class UserService

8{

9 public function createUser(Request $request): User

10 {

11 // Create user

12 $user = User::create([

13 'name' => $request->name,

14 'email' => $request->email,

15 'password' => Hash::make($request->password),

16 ]);

17 

18 // Avatar upload and update user

19 if ($request->hasFile('avatar')) {

20 $avatar = $request->file('avatar')->store('avatars');

21 $user->update(['avatar' => $avatar]);

22 }

23 

24 return $user;

25 }

26}

Then, in the Controller, we can just type-hint this Service class as a parameter of the method, and call the method inside.

1use App\Services\UserService;

2 

3class RegisteredUserController extends Controller

4{

5 public function store(StoreUserRequest $request, UserService $userService)

6 {

7 $user = $userService->createUser($request);

8 

9 // Login and other operations...

Yes, we don’t need to call new UserService() anywhere. Laravel allows you to type-hint any class like this in the Controllers, you can read more about Method Injection here in the docs.

2.1. Service Class with Single Responsibility Principle

Now, the Controller is much shorter, but this simple copy-paste separation of code is a bit problematic.

The first problem is that the Service method should act like a “black box” that just accepts the parameters and doesn’t know where those come from. So this method would be possible to be called from a Controller, from Artisan command, or a Job, in the future.

Another problem is that the Service method violates the Single Responsibility principle: it creates the user and uploads the file.

So, we need two more “layers”: one for file upload, and one for the transformation from the $request to the parameters for the function. And, as always, there are various ways to implement it.

In my case, I will create a second service method that will upload the file.

app/Services/UserService.php:

1class UserService

2{

3 public function uploadAvatar(Request $request): ?string

4 {

5 return ($request->hasFile('avatar'))

6 ? $request->file('avatar')->store('avatars')

7 : NULL;

8 }

9 

10 public function createUser(array $userData): User

11 {

12 return User::create([

13 'name' => $userData['name'],

14 'email' => $userData['email'],

15 'password' => Hash::make($userData['password']),

16 'avatar' => $userData['avatar']

17 ]);

18 }

19}

RegisteredUserController.php:

1public function store(StoreUserRequest $request, UserService $userService)

2{

3 $avatar = $userService->uploadAvatar($request);

4 $user = $userService->createUser($request->validated() + ['avatar' => $avatar]);

5 

6 // ...

Again, I will repeat: it’s only one way of separating the things, you may do it differently.

But my logic is this:

  1. The method createUser() now doesn’t know anything about the Request, and we may call it from any Artisan command or elsewhere
  2. The avatar upload is separated from the user creation operation

You may think that the Service methods are too small to separate them, but this is a very simplified example: in real-life projects, the file upload method may be much more complex, as well as the User creation logic.

In this case, we moved away a bit from the sacred rule “make a controller shorter” and added the second line of code, but for the right reasons, in my opinion.


3. Maybe Action Instead of Service?

In recent years, the concept of Action classes got popular in the Laravel community. The logic is this: you have a separate class for just ONE action only. In our case, the action classes may be:

  • CreateNewUser
  • UpdateUserPassword
  • UpdateUserProfile
  • etc.

So, as you can see, the same multiple operations around users, just not in one UserService class, but rather divided into Action classes. It may make sense, looking from the Single Responsibility Principle point of view, but I do like to group methods into classes, instead of having a lot of separate classes. Again, that’s a personal preference.

Now, let’s take a look at how our code would look in the case of the Action class.

Again, there’s no php artisan make:action, you just create a PHP class. For example, I will create app/Actions/CreateNewUser.php:

1namespace App\Actions;

2 

3use App\Models\User;

4use Illuminate\Http\Request;

5use Illuminate\Support\Facades\Hash;

6 

7class CreateNewUser

8{

9 public function handle(Request $request)

10 {

11 $avatar = ($request->hasFile('avatar'))

12 ? $request->file('avatar')->store('avatars')

13 : NULL;

14 

15 return User::create([

16 'name' => $request->name,

17 'email' => $request->email,

18 'password' => Hash::make($request->password),

19 'avatar' => $avatar

20 ]);

21 }

22}

You are free to choose the method name for the Action class, I like handle().

RegisteredUserController:

1public function store(StoreUserRequest $request, CreateNewUser $createNewUser)

2{

3 $user = $createNewUser->handle($request);

4 

5 // ...

In other words, we offload ALL the logic to the action class that then takes care of everything around both file upload and user creation. To be honest, I’m not even sure if it’s the best example to illustrate the Action classes, as I’m personally not a big fan of them and haven’t used them much. As another source of examples, you may take a look at the code of Laravel Fortify.


4. Voucher Creation: Same or Different Service?

Next, in the Controller method, we find three operations:

1Auth::login($user);

2 

3$voucher = Voucher::create([

4 'code' => Str::random(8),

5 'discount_percent' => 10,

6 'user_id' => $user->id

7]);

8 

9$user->notify(new NewUserWelcomeNotification($voucher->code));

The login operation will remain unchanged here in the controller, because it is already calling an external class Auth, similar to a Service, and we don’t need to know what is happening under the hood there.

But with Voucher, in this case, the Controller contains the logic of how the voucher should be created and sent to the user with the welcome email.

First, we need to move the voucher creation to a separate class: I’m hesitating between creating a VoucherService and putting it as a method within the same UserService. That’s almost a philosophical debate: what this method is related to the vouchers system, the users’ system, or both?

Since one of the features of Services is to contain multiple methods, I decided to not create a “lonely” VoucherService with one method. We’ll do it in the UserService:

1use App\Models\Voucher;

2use Illuminate\Support\Str;

3 

4class UserService

5{

6 // public function uploadAvatar() ...

7 // public function createUser() ...

8 

9 public function createVoucherForUser(int $userId): string

10 {

11 $voucher = Voucher::create([

12 'code' => Str::random(8),

13 'discount_percent' => 10,

14 'user_id' => $userId

15 ]);

16 

17 return $voucher->code;

18 }

19}

Then, in the Controller, we call it like this:

1public function store(StoreUserRequest $request, UserService $userService)

2{

3 // ...

4 

5 Auth::login($user);

6 

7 $voucherCode = $userService->createVoucherForUser($user->id);

8 $user->notify(new NewUserWelcomeNotification($voucherCode));

Something else to consider here: maybe we should move both of those lines into a separate method of UserService that would be responsible for the welcome email, which would in turn call the voucher method?

Something like this:

1class UserService

2{

3 public function sendWelcomeEmail(User $user)

4 {

5 $voucherCode = $this->createVoucherForUser($user->id);

6 $user->notify(new NewUserWelcomeNotification($voucherCode));

7 }

Then, Controller will have only one line of code for this:

1$userService->sendWelcomeEmail($user);


5. Notifying Admins: Queueable Jobs

Finally, we see this piece of code in the Controller:

1foreach (config('app.admin_emails') as $adminEmail) {

2 Notification::route('mail', $adminEmail)

3 ->notify(new NewUserAdminNotification($user));

4}

It is sending potentially multiple emails, which may take time, so we need to put it into the queue, to run in the background. That’s where we need Jobs.

Laravel Notification classes may be queueable, but for this example, let’s imagine there may be something more complex than just sending a notification email. So let’s create a Job for it.

In this case, Laravel provides the Artisan command for us:

1php artisan make:job NewUserNotifyAdminsJob

app/Jobs/NewUserNotifyAdminsJob.php:

1class NewUserNotifyAdminsJob implements ShouldQueue

2{

3 use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

4 

5 private User $user;

6 

7 public function __construct(User $user)

8 {

9 $this->user = $user;

10 }

11 

12 public function handle()

13 {

14 foreach (config('app.admin_emails') as $adminEmail) {

15 Notification::route('mail', $adminEmail)

16 ->notify(new NewUserAdminNotification($this->user));

17 }

18 }

19}

Then, in the Controller, we need to call that Job with the parameter:

1use App\Jobs\NewUserNotifyAdminsJob;

2 

3class RegisteredUserController extends Controller

4{

5 public function store(StoreUserRequest $request, UserService $userService)

6 {

7 // ...

8 

9 NewUserNotifyAdminsJob::dispatch($user);

So, now, we’ve moved all the logic from the Controller to elsewhere, and let’s recap what we have:

1public function store(StoreUserRequest $request, UserService $userService)

2{

3 $avatar = $userService->uploadAvatar($request);

4 $user = $userService->createUser($request->validated() + ['avatar' => $avatar]);

5 Auth::login($user);

6 $userService->sendWelcomeEmail($user);

7 NewUserNotifyAdminsJob::dispatch($user);

8 

9 return redirect(RouteServiceProvider::HOME);

10}

Shorter, separated into various files, and still readable, right? Again, will repeat once more, that it’s only one way to accomplish this mission, you can decide to structure it in another way.

But that’s not all. Let’s also discuss the “passive” way.


6. Events/Listeners

Philosophically speaking, we can divide all the operations in this Controller method, into two types: active and passive.

  1. We’re actively creating the user and logging them in
  2. And then something with that user may (or may not) happen in the background. So we’re passively waiting for those other operations: sending a welcome email and notifying the admins.

So, as one way of separating the code, it should not be called in the Controller at all, but be fired automatically when some event happens.

You can use a combination of Events and Listeners for it:

1php artisan make:event NewUserRegistered

2php artisan make:listener NewUserWelcomeEmailListener --event=NewUserRegistered

3php artisan make:listener NewUserNotifyAdminsListener --event=NewUserRegistered

The event class should accept the User model, which is then passed to ANY listener of that event.

app/Events/NewUserRegistered.php

1use App\Models\User;

2 

3class NewUserRegistered

4{

5 use Dispatchable, InteractsWithSockets, SerializesModels;

6 

7 public User $user;

8 

9 public function __construct(User $user)

10 {

11 $this->user = $user;

12 }

13}

Then, the Event is dispatched from the Controller, like this:

1public function store(StoreUserRequest $request, UserService $userService)

2{

3 $avatar = $userService->uploadAvatar($request);

4 $user = $userService->createUser($request->validated() + ['avatar' => $avatar]);

5 Auth::login($user);

6 

7 NewUserRegistered::dispatch($user);

8 

9 return redirect(RouteServiceProvider::HOME);

10}

And, in the Listener classes, we repeat the same logic:

1use App\Events\NewUserRegistered;

2use App\Services\UserService;

3 

4class NewUserWelcomeEmailListener

5{

6 public function handle(NewUserRegistered $event, UserService $userService)

7 {

8 $userService->sendWelcomeEmail($event->user);

9 }

10}

And, another one:

1use App\Events\NewUserRegistered;

2use App\Notifications\NewUserAdminNotification;

3use Illuminate\Support\Facades\Notification;

4 

5class NewUserNotifyAdminsListener

6{

7 public function handle(NewUserRegistered $event)

8 {

9 foreach (config('app.admin_emails') as $adminEmail) {

10 Notification::route('mail', $adminEmail)

11 ->notify(new NewUserAdminNotification($event->user));

12 }

13 }

14}

What is the advantage of this approach, with events and listeners? They are used like “hooks” in the code, and anyone else in the future would be able to use that hook. In other words, you’re saying to the future developers: “Hey, the user is registered, the event happened, and now if you want to add some other operation happening here, just create your listener for it”.


7. Observers: “Silent” Events/Listeners

A very similar “passive” approach could be also implemented with a Model Observer, in this case.

1php artisan make:observer UserObserver --model=User

app/Observers/UserObserver.php:

1use App\Models\User;

2use App\Notifications\NewUserAdminNotification;

3use App\Services\UserService;

4use Illuminate\Support\Facades\Notification;

5 

6class UserObserver

7{

8 public function created(User $user, UserService $userService)

9 {

10 $userService->sendWelcomeEmail($event->user);

11 

12 foreach (config('app.admin_emails') as $adminEmail) {

13 Notification::route('mail', $adminEmail)

14 ->notify(new NewUserAdminNotification($event->user));

15 }

16 }

17}

In that case, you don’t need to dispatch any events in the Controller, the Observer would be fired immediately after the Eloquent model is created.

Convenient, right?

But, in my personal opinion, this is a bit dangerous pattern. Not only the implementation logic is hidden from the Controller, but the mere existence of those operations is not clear. Imagine a new developer joining the team in a year, would they check all the possible observer methods when maintaining the User registration?

Of course, it’s possible to figure it out, but still, it’s not obvious. And our goal is to make the code more maintainable, so the fewer “surprises”, the better. So, I’m not a big fan of Observers.


Conclusion

Looking at this article now, I realize I’ve only scratched the surface of possible separations of the code, on a very simple example.

In fact, in this simple example, it may seem that we made the application more complex, creating many more PHP classes instead of just one.

But, in this example, those separate code parts are short. In real life, they may be much more complex, and by separating them, we made them more manageable, so every part may be handled by a separate developer, for example.

In general, I will repeat for the last time: you are in charge of your application, and only you decide where you place the code. The goal is so that you or your teammates will understand it in the future, and will not have trouble adding new features and maintaining/fixing the existing ones.

Laravel News